mirror of
https://github.com/kennethnym/freya
synced 2026-07-03 14:51:13 +01:00
feat: add conversation schemas (#155)
This commit is contained in:
@@ -4,7 +4,11 @@ import {
|
||||
AttachmentType,
|
||||
AttachmentPayload,
|
||||
ContextSummaryPayload,
|
||||
Conversation,
|
||||
ConversationEntry,
|
||||
ConversationEntryKind,
|
||||
ConversationEntryMetadata,
|
||||
ConversationEntryVisibility,
|
||||
GenericObjectPayload,
|
||||
UserMessagePayload,
|
||||
} from "./conversation"
|
||||
@@ -143,4 +147,99 @@ describe("conversation entry schemas", () => {
|
||||
}),
|
||||
).toThrow()
|
||||
})
|
||||
|
||||
test("parses conversation summaries", () => {
|
||||
const conversation = Conversation.assert({
|
||||
id: "11111111-1111-4111-8111-111111111111",
|
||||
createdAt: "2026-06-17T09:30:00.000Z",
|
||||
updatedAt: "2026-06-17T09:35:00.000Z",
|
||||
})
|
||||
|
||||
expect(conversation.id).toBe("11111111-1111-4111-8111-111111111111")
|
||||
})
|
||||
|
||||
test("parses kind-specific conversation entries", () => {
|
||||
const userMessageEntry = ConversationEntry.assert({
|
||||
id: "22222222-2222-4222-8222-222222222222",
|
||||
conversationId: "11111111-1111-4111-8111-111111111111",
|
||||
sequence: 1,
|
||||
kind: ConversationEntryKind.UserMessage,
|
||||
visibility: ConversationEntryVisibility.UserVisible,
|
||||
fileId: null,
|
||||
payload: {
|
||||
role: "user",
|
||||
parts: [{ type: "text", text: "hello" }],
|
||||
},
|
||||
metadata: {},
|
||||
createdAt: "2026-06-17T09:30:00.000Z",
|
||||
})
|
||||
const attachmentEntry = ConversationEntry.assert({
|
||||
id: "33333333-3333-4333-8333-333333333333",
|
||||
conversationId: "11111111-1111-4111-8111-111111111111",
|
||||
sequence: 2,
|
||||
kind: ConversationEntryKind.Attachment,
|
||||
visibility: ConversationEntryVisibility.UserVisible,
|
||||
fileId: "44444444-4444-4444-8444-444444444444",
|
||||
payload: {
|
||||
role: "user",
|
||||
name: "photo.png",
|
||||
mimeType: "image/png",
|
||||
attachmentType: AttachmentType.Image,
|
||||
},
|
||||
metadata: {},
|
||||
createdAt: "2026-06-17T09:31:00.000Z",
|
||||
})
|
||||
|
||||
expect(userMessageEntry.kind).toBe(ConversationEntryKind.UserMessage)
|
||||
expect(attachmentEntry.kind).toBe(ConversationEntryKind.Attachment)
|
||||
})
|
||||
|
||||
test("rejects conversation entries whose payload does not match the kind", () => {
|
||||
expect(() =>
|
||||
ConversationEntry.assert({
|
||||
id: "22222222-2222-4222-8222-222222222222",
|
||||
conversationId: "11111111-1111-4111-8111-111111111111",
|
||||
sequence: 1,
|
||||
kind: ConversationEntryKind.UserMessage,
|
||||
visibility: ConversationEntryVisibility.UserVisible,
|
||||
fileId: null,
|
||||
payload: {
|
||||
role: "assistant",
|
||||
parts: [{ type: "text", text: "hello" }],
|
||||
},
|
||||
metadata: {},
|
||||
createdAt: "2026-06-17T09:30:00.000Z",
|
||||
}),
|
||||
).toThrow()
|
||||
})
|
||||
|
||||
test("rejects serialized conversations with extra fields", () => {
|
||||
expect(() =>
|
||||
Conversation.assert({
|
||||
id: "11111111-1111-4111-8111-111111111111",
|
||||
createdAt: "2026-06-17T09:30:00.000Z",
|
||||
updatedAt: "2026-06-17T09:35:00.000Z",
|
||||
title: "not yet part of the schema",
|
||||
}),
|
||||
).toThrow()
|
||||
})
|
||||
|
||||
test("rejects file ids on non-attachment entries", () => {
|
||||
expect(() =>
|
||||
ConversationEntry.assert({
|
||||
id: "22222222-2222-4222-8222-222222222222",
|
||||
conversationId: "11111111-1111-4111-8111-111111111111",
|
||||
sequence: 1,
|
||||
kind: ConversationEntryKind.UserMessage,
|
||||
visibility: ConversationEntryVisibility.UserVisible,
|
||||
fileId: "44444444-4444-4444-8444-444444444444",
|
||||
payload: {
|
||||
role: "user",
|
||||
parts: [{ type: "text", text: "hello" }],
|
||||
},
|
||||
metadata: {},
|
||||
createdAt: "2026-06-17T09:30:00.000Z",
|
||||
}),
|
||||
).toThrow()
|
||||
})
|
||||
})
|
||||
|
||||
@@ -159,3 +159,115 @@ export type ConversationEntryPayload =
|
||||
| AttachmentPayload
|
||||
| ContextSummaryPayload
|
||||
| GenericObjectPayload
|
||||
|
||||
export const Conversation = type({
|
||||
"+": "reject",
|
||||
id: "string.uuid",
|
||||
createdAt: "string.date.iso",
|
||||
updatedAt: "string.date.iso",
|
||||
})
|
||||
|
||||
export type Conversation = typeof Conversation.infer
|
||||
|
||||
export const UserMessageConversationEntry = type({
|
||||
"+": "reject",
|
||||
id: "string.uuid",
|
||||
conversationId: "string.uuid",
|
||||
sequence: "number.integer >= 1",
|
||||
kind: "'user_message'",
|
||||
visibility: type.enumerated(...Object.values(ConversationEntryVisibility)),
|
||||
fileId: "null",
|
||||
payload: UserMessagePayload,
|
||||
metadata: ConversationEntryMetadata,
|
||||
createdAt: "string.date.iso",
|
||||
})
|
||||
|
||||
export const AssistantMessageConversationEntry = type({
|
||||
"+": "reject",
|
||||
id: "string.uuid",
|
||||
conversationId: "string.uuid",
|
||||
sequence: "number.integer >= 1",
|
||||
kind: "'assistant_message'",
|
||||
visibility: type.enumerated(...Object.values(ConversationEntryVisibility)),
|
||||
fileId: "null",
|
||||
payload: AssistantMessagePayload,
|
||||
metadata: ConversationEntryMetadata,
|
||||
createdAt: "string.date.iso",
|
||||
})
|
||||
|
||||
export const AttachmentConversationEntry = type({
|
||||
"+": "reject",
|
||||
id: "string.uuid",
|
||||
conversationId: "string.uuid",
|
||||
sequence: "number.integer >= 1",
|
||||
kind: "'attachment'",
|
||||
visibility: type.enumerated(...Object.values(ConversationEntryVisibility)),
|
||||
fileId: "string.uuid",
|
||||
payload: AttachmentPayload,
|
||||
metadata: ConversationEntryMetadata,
|
||||
createdAt: "string.date.iso",
|
||||
})
|
||||
|
||||
export const ToolCallConversationEntry = type({
|
||||
"+": "reject",
|
||||
id: "string.uuid",
|
||||
conversationId: "string.uuid",
|
||||
sequence: "number.integer >= 1",
|
||||
kind: "'tool_call'",
|
||||
visibility: type.enumerated(...Object.values(ConversationEntryVisibility)),
|
||||
fileId: "null",
|
||||
payload: GenericObjectPayload,
|
||||
metadata: ConversationEntryMetadata,
|
||||
createdAt: "string.date.iso",
|
||||
})
|
||||
|
||||
export const ToolResultConversationEntry = type({
|
||||
"+": "reject",
|
||||
id: "string.uuid",
|
||||
conversationId: "string.uuid",
|
||||
sequence: "number.integer >= 1",
|
||||
kind: "'tool_result'",
|
||||
visibility: type.enumerated(...Object.values(ConversationEntryVisibility)),
|
||||
fileId: "null",
|
||||
payload: GenericObjectPayload,
|
||||
metadata: ConversationEntryMetadata,
|
||||
createdAt: "string.date.iso",
|
||||
})
|
||||
|
||||
export const ContextSummaryConversationEntry = type({
|
||||
"+": "reject",
|
||||
id: "string.uuid",
|
||||
conversationId: "string.uuid",
|
||||
sequence: "number.integer >= 1",
|
||||
kind: "'context_summary'",
|
||||
visibility: type.enumerated(...Object.values(ConversationEntryVisibility)),
|
||||
fileId: "null",
|
||||
payload: ContextSummaryPayload,
|
||||
metadata: ConversationEntryMetadata,
|
||||
createdAt: "string.date.iso",
|
||||
})
|
||||
|
||||
export const SystemNoteConversationEntry = type({
|
||||
"+": "reject",
|
||||
id: "string.uuid",
|
||||
conversationId: "string.uuid",
|
||||
sequence: "number.integer >= 1",
|
||||
kind: "'system_note'",
|
||||
visibility: type.enumerated(...Object.values(ConversationEntryVisibility)),
|
||||
fileId: "null",
|
||||
payload: GenericObjectPayload,
|
||||
metadata: ConversationEntryMetadata,
|
||||
createdAt: "string.date.iso",
|
||||
})
|
||||
|
||||
export const ConversationEntry = type.or(
|
||||
UserMessageConversationEntry,
|
||||
AssistantMessageConversationEntry,
|
||||
AttachmentConversationEntry,
|
||||
ToolCallConversationEntry,
|
||||
ToolResultConversationEntry,
|
||||
ContextSummaryConversationEntry,
|
||||
SystemNoteConversationEntry,
|
||||
)
|
||||
|
||||
export type ConversationEntry = typeof ConversationEntry.infer
|
||||
|
||||
@@ -10,10 +10,15 @@ export { UnknownActionError } from "./action"
|
||||
export type { ConversationEntryPayload } from "./conversation"
|
||||
export {
|
||||
AssistantMessagePayload,
|
||||
AssistantMessageConversationEntry,
|
||||
AttachmentPayload,
|
||||
AttachmentConversationEntry,
|
||||
AttachmentType,
|
||||
ContextSummary,
|
||||
ContextSummaryConversationEntry,
|
||||
ContextSummaryPayload,
|
||||
Conversation,
|
||||
ConversationEntry,
|
||||
ConversationEntryKind,
|
||||
ConversationEntryMetadata,
|
||||
ConversationEntryVisibility,
|
||||
@@ -21,8 +26,12 @@ export {
|
||||
JsonMessagePart,
|
||||
MessagePart,
|
||||
ModelRunMetadata,
|
||||
SystemNoteConversationEntry,
|
||||
TextMessagePart,
|
||||
ToolCallConversationEntry,
|
||||
ToolResultConversationEntry,
|
||||
UserMessagePayload,
|
||||
UserMessageConversationEntry,
|
||||
} from "./conversation"
|
||||
|
||||
// Feed
|
||||
|
||||
Reference in New Issue
Block a user