import { describe, expect, test } from "bun:test"import { MessageV2 } from "../../src/session/message-v2"import type { Provider } from "../../src/provider/provider" const sessionID = "session"const model: Provider.Model = { id: "test-model", providerID: "test", api: { id: "test-model", url: "https://example.com", npm: "@ai-sdk/openai", }, name: "Test Model", capabilities: { temperature: true, reasoning: false, attachment: false, toolcall: true, input: { text: true, audio: false, image: false, video: false, pdf: false, }, output: { text: true, audio: false, image: false, video: false, pdf: false, }, interleaved: false, }, cost: { input: 0, output: 0, cache: { read: 0, write: 0, }, }, limit: { context: 0, input: 0, output: 0, }, status: "active", options: {}, headers: {}, release_date: "2026-01-01",} function userInfo(id: string): MessageV2.User { return { id, sessionID, role: "user", time: { created: 0 }, agent: "user", model: { providerID: "test", modelID: "test" }, tools: {}, mode: "", } as unknown as MessageV2.User} function assistantInfo( id: string, parentID: string, error?: MessageV2.Assistant["error"], meta?: { providerID: string; modelID: string },): MessageV2.Assistant { const infoModel = meta ?? { providerID: model.providerID, modelID: model.api.id } return { id, sessionID, role: "assistant", time: { created: 0 }, error, parentID, modelID: infoModel.modelID, providerID: infoModel.providerID, mode: "", agent: "agent", path: { cwd: "/", root: "/" }, cost: 0, tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 }, }, } as unknown as MessageV2.Assistant} function basePart(messageID: string, id: string) { return { id, sessionID, messageID, }} describe("session.message-v2.toModelMessage", () => { test("filters out messages with no parts", () => { const input: MessageV2.WithParts[] = [ { info: userInfo("m-empty"), parts: [], }, { info: userInfo("m-user"), parts: [ { ...basePart("m-user", "p1"), type: "text", text: "hello", }, ] as MessageV2.Part[], }, ] expect(MessageV2.toModelMessages(input, model)).toStrictEqual([ { role: "user", content: [{ type: "text", text: "hello" }], }, ]) }) test("filters out messages with only ignored parts", () => { const messageID = "m-user" const input: MessageV2.WithParts[] = [ { info: userInfo(messageID), parts: [ { ...basePart(messageID, "p1"), type: "text", text: "ignored", ignored: true, }, ] as MessageV2.Part[], }, ] expect(MessageV2.toModelMessages(input, model)).toStrictEqual([]) }) test("includes synthetic text parts", () => { const messageID = "m-user" const input: MessageV2.WithParts[] = [ { info: userInfo(messageID), parts: [ { ...basePart(messageID, "p1"), type: "text", text: "hello", synthetic: true, }, ] as MessageV2.Part[], }, { info: assistantInfo("m-assistant", messageID), parts: [ { ...basePart("m-assistant", "a1"), type: "text", text: "assistant", synthetic: true, }, ] as MessageV2.Part[], }, ] expect(MessageV2.toModelMessages(input, model)).toStrictEqual([ { role: "user", content: [{ type: "text", text: "hello" }], }, { role: "assistant", content: [{ type: "text", text: "assistant" }], }, ]) }) test("converts user text/file parts and injects compaction/subtask prompts", () => { const messageID = "m-user" const input: MessageV2.WithParts[] = [ { info: userInfo(messageID), parts: [ { ...basePart(messageID, "p1"), type: "text", text: "hello", }, { ...basePart(messageID, "p2"), type: "text", text: "ignored", ignored: true, }, { ...basePart(messageID, "p3"), type: "file", mime: "image/png", filename: "img.png", url: "https://example.com/img.png", }, { ...basePart(messageID, "p4"), type: "file", mime: "text/plain", filename: "note.txt", url: "https://example.com/note.txt", }, { ...basePart(messageID, "p5"), type: "file", mime: "application/x-directory", filename: "dir", url: "https://example.com/dir", }, { ...basePart(messageID, "p6"), type: "compaction", auto: true, }, { ...basePart(messageID, "p7"), type: "subtask", prompt: "prompt", description: "desc", agent: "agent", }, ] as MessageV2.Part[], }, ] expect(MessageV2.toModelMessages(input, model)).toStrictEqual([ { role: "user", content: [ { type: "text", text: "hello" }, { type: "file", mediaType: "image/png", filename: "img.png", data: "https://example.com/img.png", }, { type: "text", text: "What did we do so far?" }, { type: "text", text: "The following tool was executed by the user" }, ], }, ]) }) test("converts assistant tool completion into tool-call + tool-result messages with attachments", () => { const userID = "m-user" const assistantID = "m-assistant" const input: MessageV2.WithParts[] = [ { info: userInfo(userID), parts: [ { ...basePart(userID, "u1"), type: "text", text: "run tool", }, ] as MessageV2.Part[], }, { info: assistantInfo(assistantID, userID), parts: [ { ...basePart(assistantID, "a1"), type: "text", text: "done", metadata: { openai: { assistant: "meta" } }, }, { ...basePart(assistantID, "a2"), type: "tool", callID: "call-1", tool: "bash", state: { status: "completed", input: { cmd: "ls" }, output: "ok", title: "Bash", metadata: {}, time: { start: 0, end: 1 }, attachments: [ { ...basePart(assistantID, "file-1"), type: "file", mime: "image/png", filename: "attachment.png", url: "data:image/png;base64,Zm9v", }, ], }, metadata: { openai: { tool: "meta" } }, }, ] as MessageV2.Part[], }, ] expect(MessageV2.toModelMessages(input, model)).toStrictEqual([ { role: "user", content: [{ type: "text", text: "run tool" }], }, { role: "assistant", content: [ { type: "text", text: "done", providerOptions: { openai: { assistant: "meta" } } }, { type: "tool-call", toolCallId: "call-1", toolName: "bash", input: { cmd: "ls" }, providerExecuted: undefined, providerOptions: { openai: { tool: "meta" } }, }, ], }, { role: "tool", content: [ { type: "tool-result", toolCallId: "call-1", toolName: "bash", output: { type: "content", value: [ { type: "text", text: "ok" }, { type: "media", mediaType: "image/png", data: "Zm9v" }, ], }, providerOptions: { openai: { tool: "meta" } }, }, ], }, ]) }) test("omits provider metadata when assistant model differs", () => { const userID = "m-user" const assistantID = "m-assistant" const input: MessageV2.WithParts[] = [ { info: userInfo(userID), parts: [ { ...basePart(userID, "u1"), type: "text", text: "run tool", }, ] as MessageV2.Part[], }, { info: assistantInfo(assistantID, userID, undefined, { providerID: "other", modelID: "other" }), parts: [ { ...basePart(assistantID, "a1"), type: "text", text: "done", metadata: { openai: { assistant: "meta" } }, }, { ...basePart(assistantID, "a2"), type: "tool", callID: "call-1", tool: "bash", state: { status: "completed", input: { cmd: "ls" }, output: "ok", title: "Bash", metadata: {}, time: { start: 0, end: 1 }, }, metadata: { openai: { tool: "meta" } }, }, ] as MessageV2.Part[], }, ] expect(MessageV2.toModelMessages(input, model)).toStrictEqual([ { role: "user", content: [{ type: "text", text: "run tool" }], }, { role: "assistant", content: [ { type: "text", text: "done" }, { type: "tool-call", toolCallId: "call-1", toolName: "bash", input: { cmd: "ls" }, providerExecuted: undefined, }, ], }, { role: "tool", content: [ { type: "tool-result", toolCallId: "call-1", toolName: "bash", output: { type: "text", value: "ok" }, }, ], }, ]) }) test("replaces compacted tool output with placeholder", () => { const userID = "m-user" const assistantID = "m-assistant" const input: MessageV2.WithParts[] = [ { info: userInfo(userID), parts: [ { ...basePart(userID, "u1"), type: "text", text: "run tool", }, ] as MessageV2.Part[], }, { info: assistantInfo(assistantID, userID), parts: [ { ...basePart(assistantID, "a1"), type: "tool", callID: "call-1", tool: "bash", state: { status: "completed", input: { cmd: "ls" }, output: "this should be cleared", title: "Bash", metadata: {}, time: { start: 0, end: 1, compacted: 1 }, }, }, ] as MessageV2.Part[], }, ] expect(MessageV2.toModelMessages(input, model)).toStrictEqual([ { role: "user", content: [{ type: "text", text: "run tool" }], }, { role: "assistant", content: [ { type: "tool-call", toolCallId: "call-1", toolName: "bash", input: { cmd: "ls" }, providerExecuted: undefined, }, ], }, { role: "tool", content: [ { type: "tool-result", toolCallId: "call-1", toolName: "bash", output: { type: "text", value: "[Old tool result content cleared]" }, }, ], }, ]) }) test("converts assistant tool error into error-text tool result", () => { const userID = "m-user"Lines 1–500 of 786. Load more
import { describe, expect, test } from "bun:test" import { MessageV2 } from "../../src/session/message-v2" import type { Provider } from "../../src/provider/provider" const sessionID = "session" const model: Provider.Model = { id: "test-model", providerID: "test", api: { id: "test-model", url: "https://example.com", npm: "@ai-sdk/openai", }, name: "Test Model", capabilities: { temperature: true, reasoning: false, attachment: false, toolcall: true, input: { text: true, audio: false, image: false, video: false, pdf: false, }, output: { text: true, audio: false, image: false, video: false, pdf: false, }, interleaved: false, }, cost: { input: 0, output: 0, cache: { read: 0, write: 0, }, }, limit: { context: 0, input: 0, output: 0, }, status: "active", options: {}, headers: {}, release_date: "2026-01-01", } function userInfo(id: string): MessageV2.User { return { id, sessionID, role: "user", time: { created: 0 }, agent: "user", model: { providerID: "test", modelID: "test" }, tools: {}, mode: "", } as unknown as MessageV2.User } function assistantInfo( id: string, parentID: string, error?: MessageV2.Assistant["error"], meta?: { providerID: string; modelID: string }, ): MessageV2.Assistant { const infoModel = meta ?? { providerID: model.providerID, modelID: model.api.id } return { id, sessionID, role: "assistant", time: { created: 0 }, error, parentID, modelID: infoModel.modelID, providerID: infoModel.providerID, mode: "", agent: "agent", path: { cwd: "/", root: "/" }, cost: 0, tokens: { input: 0, output: 0, reasoning: 0, cache: { read: 0, write: 0 }, }, } as unknown as MessageV2.Assistant } function basePart(messageID: string, id: string) { return { id, sessionID, messageID, } } describe("session.message-v2.toModelMessage", () => { test("filters out messages with no parts", () => { const input: MessageV2.WithParts[] = [ { info: userInfo("m-empty"), parts: [], }, { info: userInfo("m-user"), parts: [ { ...basePart("m-user", "p1"), type: "text", text: "hello", }, ] as MessageV2.Part[], }, ] expect(MessageV2.toModelMessages(input, model)).toStrictEqual([ { role: "user", content: [{ type: "text", text: "hello" }], }, ]) }) test("filters out messages with only ignored parts", () => { const messageID = "m-user" const input: MessageV2.WithParts[] = [ { info: userInfo(messageID), parts: [ { ...basePart(messageID, "p1"), type: "text", text: "ignored", ignored: true, }, ] as MessageV2.Part[], }, ] expect(MessageV2.toModelMessages(input, model)).toStrictEqual([]) }) test("includes synthetic text parts", () => { const messageID = "m-user" const input: MessageV2.WithParts[] = [ { info: userInfo(messageID), parts: [ { ...basePart(messageID, "p1"), type: "text", text: "hello", synthetic: true, }, ] as MessageV2.Part[], }, { info: assistantInfo("m-assistant", messageID), parts: [ { ...basePart("m-assistant", "a1"), type: "text", text: "assistant", synthetic: true, }, ] as MessageV2.Part[], }, ] expect(MessageV2.toModelMessages(input, model)).toStrictEqual([ { role: "user", content: [{ type: "text", text: "hello" }], }, { role: "assistant", content: [{ type: "text", text: "assistant" }], }, ]) }) test("converts user text/file parts and injects compaction/subtask prompts", () => { const messageID = "m-user" const input: MessageV2.WithParts[] = [ { info: userInfo(messageID), parts: [ { ...basePart(messageID, "p1"), type: "text", text: "hello", }, { ...basePart(messageID, "p2"), type: "text", text: "ignored", ignored: true, }, { ...basePart(messageID, "p3"), type: "file", mime: "image/png", filename: "img.png", url: "https://example.com/img.png", }, { ...basePart(messageID, "p4"), type: "file", mime: "text/plain", filename: "note.txt", url: "https://example.com/note.txt", }, { ...basePart(messageID, "p5"), type: "file", mime: "application/x-directory", filename: "dir", url: "https://example.com/dir", }, { ...basePart(messageID, "p6"), type: "compaction", auto: true, }, { ...basePart(messageID, "p7"), type: "subtask", prompt: "prompt", description: "desc", agent: "agent", }, ] as MessageV2.Part[], }, ] expect(MessageV2.toModelMessages(input, model)).toStrictEqual([ { role: "user", content: [ { type: "text", text: "hello" }, { type: "file", mediaType: "image/png", filename: "img.png", data: "https://example.com/img.png", }, { type: "text", text: "What did we do so far?" }, { type: "text", text: "The following tool was executed by the user" }, ], }, ]) }) test("converts assistant tool completion into tool-call + tool-result messages with attachments", () => { const userID = "m-user" const assistantID = "m-assistant" const input: MessageV2.WithParts[] = [ { info: userInfo(userID), parts: [ { ...basePart(userID, "u1"), type: "text", text: "run tool", }, ] as MessageV2.Part[], }, { info: assistantInfo(assistantID, userID), parts: [ { ...basePart(assistantID, "a1"), type: "text", text: "done", metadata: { openai: { assistant: "meta" } }, }, { ...basePart(assistantID, "a2"), type: "tool", callID: "call-1", tool: "bash", state: { status: "completed", input: { cmd: "ls" }, output: "ok", title: "Bash", metadata: {}, time: { start: 0, end: 1 }, attachments: [ { ...basePart(assistantID, "file-1"), type: "file", mime: "image/png", filename: "attachment.png", url: "data:image/png;base64,Zm9v", }, ], }, metadata: { openai: { tool: "meta" } }, }, ] as MessageV2.Part[], }, ] expect(MessageV2.toModelMessages(input, model)).toStrictEqual([ { role: "user", content: [{ type: "text", text: "run tool" }], }, { role: "assistant", content: [ { type: "text", text: "done", providerOptions: { openai: { assistant: "meta" } } }, { type: "tool-call", toolCallId: "call-1", toolName: "bash", input: { cmd: "ls" }, providerExecuted: undefined, providerOptions: { openai: { tool: "meta" } }, }, ], }, { role: "tool", content: [ { type: "tool-result", toolCallId: "call-1", toolName: "bash", output: { type: "content", value: [ { type: "text", text: "ok" }, { type: "media", mediaType: "image/png", data: "Zm9v" }, ], }, providerOptions: { openai: { tool: "meta" } }, }, ], }, ]) }) test("omits provider metadata when assistant model differs", () => { const userID = "m-user" const assistantID = "m-assistant" const input: MessageV2.WithParts[] = [ { info: userInfo(userID), parts: [ { ...basePart(userID, "u1"), type: "text", text: "run tool", }, ] as MessageV2.Part[], }, { info: assistantInfo(assistantID, userID, undefined, { providerID: "other", modelID: "other" }), parts: [ { ...basePart(assistantID, "a1"), type: "text", text: "done", metadata: { openai: { assistant: "meta" } }, }, { ...basePart(assistantID, "a2"), type: "tool", callID: "call-1", tool: "bash", state: { status: "completed", input: { cmd: "ls" }, output: "ok", title: "Bash", metadata: {}, time: { start: 0, end: 1 }, }, metadata: { openai: { tool: "meta" } }, }, ] as MessageV2.Part[], }, ] expect(MessageV2.toModelMessages(input, model)).toStrictEqual([ { role: "user", content: [{ type: "text", text: "run tool" }], }, { role: "assistant", content: [ { type: "text", text: "done" }, { type: "tool-call", toolCallId: "call-1", toolName: "bash", input: { cmd: "ls" }, providerExecuted: undefined, }, ], }, { role: "tool", content: [ { type: "tool-result", toolCallId: "call-1", toolName: "bash", output: { type: "text", value: "ok" }, }, ], }, ]) }) test("replaces compacted tool output with placeholder", () => { const userID = "m-user" const assistantID = "m-assistant" const input: MessageV2.WithParts[] = [ { info: userInfo(userID), parts: [ { ...basePart(userID, "u1"), type: "text", text: "run tool", }, ] as MessageV2.Part[], }, { info: assistantInfo(assistantID, userID), parts: [ { ...basePart(assistantID, "a1"), type: "tool", callID: "call-1", tool: "bash", state: { status: "completed", input: { cmd: "ls" }, output: "this should be cleared", title: "Bash", metadata: {}, time: { start: 0, end: 1, compacted: 1 }, }, }, ] as MessageV2.Part[], }, ] expect(MessageV2.toModelMessages(input, model)).toStrictEqual([ { role: "user", content: [{ type: "text", text: "run tool" }], }, { role: "assistant", content: [ { type: "tool-call", toolCallId: "call-1", toolName: "bash", input: { cmd: "ls" }, providerExecuted: undefined, }, ], }, { role: "tool", content: [ { type: "tool-result", toolCallId: "call-1", toolName: "bash", output: { type: "text", value: "[Old tool result content cleared]" }, }, ], }, ]) }) test("converts assistant tool error into error-text tool result", () => { const userID = "m-user"