refactor(core): move database schema ownership (#29068)
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -1,16 +1,18 @@
|
||||
import { describe, expect, test } from "bun:test"
|
||||
import { SessionLegacy } from "@opencode-ai/core/session/legacy"
|
||||
import { APICallError } from "ai"
|
||||
import { MessageV2 } from "../../src/session/message-v2"
|
||||
import { ProviderTransform } from "@/provider/transform"
|
||||
import type { Provider } from "@/provider/provider"
|
||||
import { ModelID, ProviderID } from "../../src/provider/schema"
|
||||
|
||||
import { SessionID, MessageID, PartID } from "../../src/session/schema"
|
||||
import { Question } from "../../src/question"
|
||||
import { ProviderV2 } from "@opencode-ai/core/provider"
|
||||
|
||||
const sessionID = SessionID.make("session")
|
||||
const providerID = ProviderID.make("test")
|
||||
const providerID = ProviderV2.ID.make("test")
|
||||
const model: Provider.Model = {
|
||||
id: ModelID.make("test-model"),
|
||||
id: ProviderV2.ModelID.make("test-model"),
|
||||
providerID,
|
||||
api: {
|
||||
id: "test-model",
|
||||
@@ -58,25 +60,25 @@ const model: Provider.Model = {
|
||||
release_date: "2026-01-01",
|
||||
}
|
||||
|
||||
function userInfo(id: string): MessageV2.User {
|
||||
function userInfo(id: string): SessionLegacy.User {
|
||||
return {
|
||||
id,
|
||||
sessionID,
|
||||
role: "user",
|
||||
time: { created: 0 },
|
||||
agent: "user",
|
||||
model: { providerID, modelID: ModelID.make("test") },
|
||||
model: { providerID, modelID: ProviderV2.ModelID.make("test") },
|
||||
tools: {},
|
||||
mode: "",
|
||||
} as unknown as MessageV2.User
|
||||
} as unknown as SessionLegacy.User
|
||||
}
|
||||
|
||||
function assistantInfo(
|
||||
id: string,
|
||||
parentID: string,
|
||||
error?: MessageV2.Assistant["error"],
|
||||
error?: SessionLegacy.Assistant["error"],
|
||||
meta?: { providerID: string; modelID: string },
|
||||
): MessageV2.Assistant {
|
||||
): SessionLegacy.Assistant {
|
||||
const infoModel = meta ?? { providerID: model.providerID, modelID: model.api.id }
|
||||
return {
|
||||
id,
|
||||
@@ -97,7 +99,7 @@ function assistantInfo(
|
||||
reasoning: 0,
|
||||
cache: { read: 0, write: 0 },
|
||||
},
|
||||
} as unknown as MessageV2.Assistant
|
||||
} as unknown as SessionLegacy.Assistant
|
||||
}
|
||||
|
||||
function basePart(messageID: string, id: string) {
|
||||
@@ -110,7 +112,7 @@ function basePart(messageID: string, id: string) {
|
||||
|
||||
describe("session.message-v2.toModelMessage", () => {
|
||||
test("filters out messages with no parts", async () => {
|
||||
const input: MessageV2.WithParts[] = [
|
||||
const input: SessionLegacy.WithParts[] = [
|
||||
{
|
||||
info: userInfo("m-empty"),
|
||||
parts: [],
|
||||
@@ -123,7 +125,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
type: "text",
|
||||
text: "hello",
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -138,7 +140,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
test("filters out messages with only ignored parts", async () => {
|
||||
const messageID = "m-user"
|
||||
|
||||
const input: MessageV2.WithParts[] = [
|
||||
const input: SessionLegacy.WithParts[] = [
|
||||
{
|
||||
info: userInfo(messageID),
|
||||
parts: [
|
||||
@@ -148,7 +150,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
text: "ignored",
|
||||
ignored: true,
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -158,7 +160,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
test("filters out user messages with only empty text parts", async () => {
|
||||
const messageID = "m-user"
|
||||
|
||||
const input: MessageV2.WithParts[] = [
|
||||
const input: SessionLegacy.WithParts[] = [
|
||||
{
|
||||
info: userInfo(messageID),
|
||||
parts: [
|
||||
@@ -167,7 +169,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
type: "text",
|
||||
text: "",
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -177,7 +179,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
test("filters empty user text parts while keeping non-empty parts", async () => {
|
||||
const messageID = "m-user"
|
||||
|
||||
const input: MessageV2.WithParts[] = [
|
||||
const input: SessionLegacy.WithParts[] = [
|
||||
{
|
||||
info: userInfo(messageID),
|
||||
parts: [
|
||||
@@ -191,7 +193,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
type: "text",
|
||||
text: "hello",
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -206,7 +208,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
test("includes synthetic text parts", async () => {
|
||||
const messageID = "m-user"
|
||||
|
||||
const input: MessageV2.WithParts[] = [
|
||||
const input: SessionLegacy.WithParts[] = [
|
||||
{
|
||||
info: userInfo(messageID),
|
||||
parts: [
|
||||
@@ -216,7 +218,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
text: "hello",
|
||||
synthetic: true,
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
{
|
||||
info: assistantInfo("m-assistant", messageID),
|
||||
@@ -227,7 +229,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
text: "assistant",
|
||||
synthetic: true,
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -246,7 +248,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
test("converts user text/file parts and injects compaction/subtask prompts", async () => {
|
||||
const messageID = "m-user"
|
||||
|
||||
const input: MessageV2.WithParts[] = [
|
||||
const input: SessionLegacy.WithParts[] = [
|
||||
{
|
||||
info: userInfo(messageID),
|
||||
parts: [
|
||||
@@ -294,7 +296,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
description: "desc",
|
||||
agent: "agent",
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -320,7 +322,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
const userID = "m-user"
|
||||
const assistantID = "m-assistant"
|
||||
|
||||
const input: MessageV2.WithParts[] = [
|
||||
const input: SessionLegacy.WithParts[] = [
|
||||
{
|
||||
info: userInfo(userID),
|
||||
parts: [
|
||||
@@ -329,7 +331,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
type: "text",
|
||||
text: "run tool",
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
{
|
||||
info: assistantInfo(assistantID, userID),
|
||||
@@ -364,7 +366,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
},
|
||||
metadata: { openai: { tool: "meta" } },
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -411,8 +413,8 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
test("preserves jpeg tool-result media for anthropic models", async () => {
|
||||
const anthropicModel: Provider.Model = {
|
||||
...model,
|
||||
id: ModelID.make("anthropic/claude-opus-4-7"),
|
||||
providerID: ProviderID.make("anthropic"),
|
||||
id: ProviderV2.ModelID.make("anthropic/claude-opus-4-7"),
|
||||
providerID: ProviderV2.ID.make("anthropic"),
|
||||
api: {
|
||||
id: "claude-opus-4-7-20250805",
|
||||
url: "https://api.anthropic.com",
|
||||
@@ -433,7 +435,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
)
|
||||
const userID = "m-user-anthropic"
|
||||
const assistantID = "m-assistant-anthropic"
|
||||
const input: MessageV2.WithParts[] = [
|
||||
const input: SessionLegacy.WithParts[] = [
|
||||
{
|
||||
info: userInfo(userID),
|
||||
parts: [
|
||||
@@ -442,7 +444,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
type: "text",
|
||||
text: "run tool",
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
{
|
||||
info: assistantInfo(assistantID, userID),
|
||||
@@ -470,7 +472,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
],
|
||||
},
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -494,8 +496,8 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
test("moves bedrock pdf tool-result media into a separate user message", async () => {
|
||||
const bedrockModel: Provider.Model = {
|
||||
...model,
|
||||
id: ModelID.make("amazon-bedrock/anthropic.claude-sonnet-4-6"),
|
||||
providerID: ProviderID.make("amazon-bedrock"),
|
||||
id: ProviderV2.ModelID.make("amazon-bedrock/anthropic.claude-sonnet-4-6"),
|
||||
providerID: ProviderV2.ID.make("amazon-bedrock"),
|
||||
api: {
|
||||
id: "anthropic.claude-sonnet-4-6",
|
||||
url: "https://bedrock-runtime.us-east-1.amazonaws.com",
|
||||
@@ -514,7 +516,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
const pdf = Buffer.from("%PDF-1.4\n").toString("base64")
|
||||
const userID = "m-user-bedrock-pdf"
|
||||
const assistantID = "m-assistant-bedrock-pdf"
|
||||
const input: MessageV2.WithParts[] = [
|
||||
const input: SessionLegacy.WithParts[] = [
|
||||
{
|
||||
info: userInfo(userID),
|
||||
parts: [
|
||||
@@ -523,7 +525,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
type: "text",
|
||||
text: "run tool",
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
{
|
||||
info: assistantInfo(assistantID, userID),
|
||||
@@ -551,7 +553,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
],
|
||||
},
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -602,7 +604,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
const userID = "m-user"
|
||||
const assistantID = "m-assistant"
|
||||
|
||||
const input: MessageV2.WithParts[] = [
|
||||
const input: SessionLegacy.WithParts[] = [
|
||||
{
|
||||
info: userInfo(userID),
|
||||
parts: [
|
||||
@@ -611,7 +613,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
type: "text",
|
||||
text: "run tool",
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
{
|
||||
info: assistantInfo(assistantID, userID, undefined, { providerID: "other", modelID: "other" }),
|
||||
@@ -644,7 +646,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
},
|
||||
metadata: { openai: { tool: "meta" } },
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -685,7 +687,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
const userID = "m-user"
|
||||
const assistantID = "m-assistant"
|
||||
|
||||
const input: MessageV2.WithParts[] = [
|
||||
const input: SessionLegacy.WithParts[] = [
|
||||
{
|
||||
info: userInfo(userID),
|
||||
parts: [
|
||||
@@ -694,7 +696,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
type: "text",
|
||||
text: "run tool",
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
{
|
||||
info: assistantInfo(assistantID, userID),
|
||||
@@ -713,7 +715,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
time: { start: 0, end: 1, compacted: 1 },
|
||||
},
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -752,7 +754,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
const userID = "m-user"
|
||||
const assistantID = "m-assistant"
|
||||
|
||||
const input: MessageV2.WithParts[] = [
|
||||
const input: SessionLegacy.WithParts[] = [
|
||||
{
|
||||
info: userInfo(userID),
|
||||
parts: [
|
||||
@@ -761,7 +763,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
type: "text",
|
||||
text: "run tool",
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
{
|
||||
info: assistantInfo(assistantID, userID),
|
||||
@@ -780,7 +782,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
time: { start: 0, end: 1 },
|
||||
},
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -822,7 +824,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
const userID = "m-user"
|
||||
const assistantID = "m-assistant"
|
||||
|
||||
const input: MessageV2.WithParts[] = [
|
||||
const input: SessionLegacy.WithParts[] = [
|
||||
{
|
||||
info: userInfo(userID),
|
||||
parts: [
|
||||
@@ -831,7 +833,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
type: "text",
|
||||
text: "run tool",
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
{
|
||||
info: assistantInfo(assistantID, userID),
|
||||
@@ -850,7 +852,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
},
|
||||
metadata: { openai: { tool: "meta" } },
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -900,7 +902,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
"</shell_metadata>",
|
||||
].join("\n")
|
||||
|
||||
const input: MessageV2.WithParts[] = [
|
||||
const input: SessionLegacy.WithParts[] = [
|
||||
{
|
||||
info: userInfo(userID),
|
||||
parts: [
|
||||
@@ -909,7 +911,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
type: "text",
|
||||
text: "run tool",
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
{
|
||||
info: assistantInfo(assistantID, userID),
|
||||
@@ -927,7 +929,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
time: { start: 0, end: 1 },
|
||||
},
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -965,12 +967,12 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
test("filters assistant messages with non-abort errors", async () => {
|
||||
const assistantID = "m-assistant"
|
||||
|
||||
const input: MessageV2.WithParts[] = [
|
||||
const input: SessionLegacy.WithParts[] = [
|
||||
{
|
||||
info: assistantInfo(
|
||||
assistantID,
|
||||
"m-parent",
|
||||
new MessageV2.APIError({ message: "boom", isRetryable: true }).toObject() as MessageV2.APIError,
|
||||
new SessionLegacy.APIError({ message: "boom", isRetryable: true }).toObject() as SessionLegacy.APIError,
|
||||
),
|
||||
parts: [
|
||||
{
|
||||
@@ -978,7 +980,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
type: "text",
|
||||
text: "should not render",
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -989,9 +991,9 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
const assistantID1 = "m-assistant-1"
|
||||
const assistantID2 = "m-assistant-2"
|
||||
|
||||
const aborted = new MessageV2.AbortedError({ message: "aborted" }).toObject() as MessageV2.Assistant["error"]
|
||||
const aborted = new SessionLegacy.AbortedError({ message: "aborted" }).toObject() as SessionLegacy.Assistant["error"]
|
||||
|
||||
const input: MessageV2.WithParts[] = [
|
||||
const input: SessionLegacy.WithParts[] = [
|
||||
{
|
||||
info: assistantInfo(assistantID1, "m-parent", aborted),
|
||||
parts: [
|
||||
@@ -1006,7 +1008,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
type: "text",
|
||||
text: "partial answer",
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
{
|
||||
info: assistantInfo(assistantID2, "m-parent", aborted),
|
||||
@@ -1021,7 +1023,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
text: "thinking",
|
||||
time: { start: 0 },
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -1040,8 +1042,8 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
const assistantID = "m-assistant"
|
||||
const openrouterModel: Provider.Model = {
|
||||
...model,
|
||||
id: ModelID.make("deepseek/deepseek-v4-pro"),
|
||||
providerID: ProviderID.make("openrouter"),
|
||||
id: ProviderV2.ModelID.make("deepseek/deepseek-v4-pro"),
|
||||
providerID: ProviderV2.ID.make("openrouter"),
|
||||
api: {
|
||||
id: "deepseek/deepseek-v4-pro",
|
||||
url: "https://openrouter.ai/api/v1",
|
||||
@@ -1061,7 +1063,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
index: 0,
|
||||
},
|
||||
]
|
||||
const input: MessageV2.WithParts[] = [
|
||||
const input: SessionLegacy.WithParts[] = [
|
||||
{
|
||||
info: assistantInfo(assistantID, "m-parent", undefined, {
|
||||
providerID: openrouterModel.providerID,
|
||||
@@ -1084,7 +1086,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
type: "text",
|
||||
text: "answer",
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -1112,7 +1114,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
test("splits assistant messages on step-start boundaries", async () => {
|
||||
const assistantID = "m-assistant"
|
||||
|
||||
const input: MessageV2.WithParts[] = [
|
||||
const input: SessionLegacy.WithParts[] = [
|
||||
{
|
||||
info: assistantInfo(assistantID, "m-parent"),
|
||||
parts: [
|
||||
@@ -1130,7 +1132,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
type: "text",
|
||||
text: "second",
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -1149,7 +1151,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
test("drops messages that only contain step-start parts", async () => {
|
||||
const assistantID = "m-assistant"
|
||||
|
||||
const input: MessageV2.WithParts[] = [
|
||||
const input: SessionLegacy.WithParts[] = [
|
||||
{
|
||||
info: assistantInfo(assistantID, "m-parent"),
|
||||
parts: [
|
||||
@@ -1157,7 +1159,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
...basePart(assistantID, "p1"),
|
||||
type: "step-start",
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -1168,7 +1170,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
const userID = "m-user"
|
||||
const assistantID = "m-assistant"
|
||||
|
||||
const input: MessageV2.WithParts[] = [
|
||||
const input: SessionLegacy.WithParts[] = [
|
||||
{
|
||||
info: userInfo(userID),
|
||||
parts: [
|
||||
@@ -1177,7 +1179,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
type: "text",
|
||||
text: "run tool",
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
{
|
||||
info: assistantInfo(assistantID, userID),
|
||||
@@ -1204,7 +1206,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
time: { start: 0 },
|
||||
},
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -1257,7 +1259,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
test("substitutes space for empty text between signed reasoning blocks", async () => {
|
||||
// Reproduces the bug pattern: [reasoning(sig), text(""), reasoning(sig), text(full)]
|
||||
const assistantID = "m-assistant"
|
||||
const input: MessageV2.WithParts[] = [
|
||||
const input: SessionLegacy.WithParts[] = [
|
||||
{
|
||||
info: assistantInfo(assistantID, "m-parent"),
|
||||
parts: [
|
||||
@@ -1277,7 +1279,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
metadata: { anthropic: { signature: "sig2" } },
|
||||
},
|
||||
{ ...basePart(assistantID, "p6"), type: "text", text: "the answer" },
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -1293,7 +1295,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
// Bedrock signed reasoning is preserved as reasoning metadata, but unlike the
|
||||
// direct Anthropic path we do not preserve empty text separators for Bedrock.
|
||||
const assistantID = "m-assistant-bedrock"
|
||||
const input: MessageV2.WithParts[] = [
|
||||
const input: SessionLegacy.WithParts[] = [
|
||||
{
|
||||
info: assistantInfo(assistantID, "m-parent"),
|
||||
parts: [
|
||||
@@ -1305,7 +1307,7 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
},
|
||||
{ ...basePart(assistantID, "p2"), type: "text", text: "" },
|
||||
{ ...basePart(assistantID, "p3"), type: "text", text: "answer" },
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -1320,14 +1322,14 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
// Non-Anthropic providers' reasoning doesn't position-validate, so empty text
|
||||
// should be filtered normally rather than substituted.
|
||||
const assistantID = "m-assistant-unsigned"
|
||||
const input: MessageV2.WithParts[] = [
|
||||
const input: SessionLegacy.WithParts[] = [
|
||||
{
|
||||
info: assistantInfo(assistantID, "m-parent"),
|
||||
parts: [
|
||||
{ ...basePart(assistantID, "p1"), type: "reasoning", text: "thinking" },
|
||||
{ ...basePart(assistantID, "p2"), type: "text", text: "" },
|
||||
{ ...basePart(assistantID, "p3"), type: "text", text: "answer" },
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -1340,13 +1342,13 @@ describe("session.message-v2.toModelMessage", () => {
|
||||
|
||||
test("leaves empty text alone in assistant messages without reasoning", async () => {
|
||||
const assistantID = "m-assistant-no-reasoning"
|
||||
const input: MessageV2.WithParts[] = [
|
||||
const input: SessionLegacy.WithParts[] = [
|
||||
{
|
||||
info: assistantInfo(assistantID, "m-parent"),
|
||||
parts: [
|
||||
{ ...basePart(assistantID, "p1"), type: "text", text: "" },
|
||||
{ ...basePart(assistantID, "p2"), type: "text", text: "hello" },
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
},
|
||||
]
|
||||
|
||||
@@ -1458,7 +1460,7 @@ describe("session.message-v2.fromError", () => {
|
||||
isRetryable: false,
|
||||
})
|
||||
const result = MessageV2.fromError(error, { providerID })
|
||||
expect(MessageV2.ContextOverflowError.isInstance(result)).toBe(true)
|
||||
expect(SessionLegacy.ContextOverflowError.isInstance(result)).toBe(true)
|
||||
})
|
||||
})
|
||||
|
||||
@@ -1479,7 +1481,7 @@ describe("session.message-v2.fromError", () => {
|
||||
isRetryable: false,
|
||||
})
|
||||
const result = MessageV2.fromError(error, { providerID })
|
||||
expect(MessageV2.ContextOverflowError.isInstance(result)).toBe(true)
|
||||
expect(SessionLegacy.ContextOverflowError.isInstance(result)).toBe(true)
|
||||
})
|
||||
|
||||
test("does not classify 429 no body as context overflow", () => {
|
||||
@@ -1494,8 +1496,8 @@ describe("session.message-v2.fromError", () => {
|
||||
}),
|
||||
{ providerID },
|
||||
)
|
||||
expect(MessageV2.ContextOverflowError.isInstance(result)).toBe(false)
|
||||
expect(MessageV2.APIError.isInstance(result)).toBe(true)
|
||||
expect(SessionLegacy.ContextOverflowError.isInstance(result)).toBe(false)
|
||||
expect(SessionLegacy.APIError.isInstance(result)).toBe(true)
|
||||
})
|
||||
|
||||
test("serializes unknown inputs", () => {
|
||||
@@ -1530,9 +1532,9 @@ describe("session.message-v2.fromError", () => {
|
||||
|
||||
const result = MessageV2.fromError(zlibError, { providerID })
|
||||
|
||||
expect(MessageV2.APIError.isInstance(result)).toBe(true)
|
||||
expect((result as MessageV2.APIError).data.isRetryable).toBe(true)
|
||||
expect((result as MessageV2.APIError).data.message).toInclude("decompression")
|
||||
expect(SessionLegacy.APIError.isInstance(result)).toBe(true)
|
||||
expect((result as SessionLegacy.APIError).data.isRetryable).toBe(true)
|
||||
expect((result as SessionLegacy.APIError).data.message).toInclude("decompression")
|
||||
})
|
||||
|
||||
test("classifies ZlibError as AbortedError when abort context is provided", () => {
|
||||
@@ -1556,21 +1558,21 @@ describe("session.message-v2.latest", () => {
|
||||
const CONTINUE_USER = MessageID.make("msg_005")
|
||||
const NEW_COMPACTION_USER = MessageID.make("msg_006")
|
||||
|
||||
const tailUser: MessageV2.WithParts = {
|
||||
const tailUser: SessionLegacy.WithParts = {
|
||||
info: userInfo(TAIL_USER),
|
||||
parts: [{ ...basePart(TAIL_USER, "p1"), type: "text", text: "original prompt" }] as MessageV2.Part[],
|
||||
parts: [{ ...basePart(TAIL_USER, "p1"), type: "text", text: "original prompt" }] as SessionLegacy.Part[],
|
||||
}
|
||||
|
||||
const overflowAssistant: MessageV2.WithParts = {
|
||||
const overflowAssistant: SessionLegacy.WithParts = {
|
||||
info: {
|
||||
...assistantInfo(OVERFLOW_ASSISTANT, TAIL_USER),
|
||||
finish: "tool-calls",
|
||||
tokens: { input: 280_000, output: 200, reasoning: 0, cache: { read: 0, write: 0 }, total: 280_200 },
|
||||
} as MessageV2.Assistant,
|
||||
} as SessionLegacy.Assistant,
|
||||
parts: [],
|
||||
}
|
||||
|
||||
const compactionUser: MessageV2.WithParts = {
|
||||
const compactionUser: SessionLegacy.WithParts = {
|
||||
info: userInfo(COMPACTION_USER),
|
||||
parts: [
|
||||
{
|
||||
@@ -1579,20 +1581,20 @@ describe("session.message-v2.latest", () => {
|
||||
auto: true,
|
||||
tail_start_id: TAIL_USER,
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
}
|
||||
|
||||
const summaryAssistant: MessageV2.WithParts = {
|
||||
const summaryAssistant: SessionLegacy.WithParts = {
|
||||
info: {
|
||||
...assistantInfo(SUMMARY_ASSISTANT, COMPACTION_USER),
|
||||
summary: true,
|
||||
finish: "stop",
|
||||
tokens: { input: 150_000, output: 1_500, reasoning: 0, cache: { read: 0, write: 0 }, total: 151_500 },
|
||||
} as MessageV2.Assistant,
|
||||
} as SessionLegacy.Assistant,
|
||||
parts: [],
|
||||
}
|
||||
|
||||
const continueUser: MessageV2.WithParts = {
|
||||
const continueUser: SessionLegacy.WithParts = {
|
||||
info: userInfo(CONTINUE_USER),
|
||||
parts: [
|
||||
{
|
||||
@@ -1602,7 +1604,7 @@ describe("session.message-v2.latest", () => {
|
||||
synthetic: true,
|
||||
metadata: { compaction_continue: true },
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
}
|
||||
|
||||
// Regression for double auto-compaction. The reorder in filterCompacted
|
||||
@@ -1628,7 +1630,7 @@ describe("session.message-v2.latest", () => {
|
||||
})
|
||||
|
||||
test("a fresh compaction-user newer than the latest summary surfaces in tasks", () => {
|
||||
const newCompactionUser: MessageV2.WithParts = {
|
||||
const newCompactionUser: SessionLegacy.WithParts = {
|
||||
info: userInfo(NEW_COMPACTION_USER),
|
||||
parts: [
|
||||
{
|
||||
@@ -1636,7 +1638,7 @@ describe("session.message-v2.latest", () => {
|
||||
type: "compaction",
|
||||
auto: true,
|
||||
},
|
||||
] as MessageV2.Part[],
|
||||
] as SessionLegacy.Part[],
|
||||
}
|
||||
|
||||
const state = MessageV2.latest([
|
||||
|
||||
Reference in New Issue
Block a user