Skip to content

Commit a092c17

Browse files
committed
Normalize legacy session messages without agent or model
1 parent 2fd1bdf commit a092c17

2 files changed

Lines changed: 47 additions & 23 deletions

File tree

packages/opencode/src/session/message-v2.ts

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import { ProviderError } from "@/provider/error"
3434
import { iife } from "@/util/iife"
3535
import { errorMessage } from "@/util/error"
3636
import { isMedia } from "@/util/media"
37+
import { isRecord } from "@/util/record"
3738
import type { SystemError } from "bun"
3839
import type { Provider } from "@/provider/provider"
3940
import { Effect, Schema } from "effect"
@@ -89,13 +90,28 @@ export const cursor = {
8990
},
9091
}
9192

92-
const info = (row: typeof MessageTable.$inferSelect) => {
93-
const data = row.data as typeof row.data & { agent?: unknown; mode?: unknown }
93+
function infoModel(input: unknown): User["model"] | undefined {
94+
if (!isRecord(input) || typeof input.providerID !== "string") return
95+
const modelID = typeof input.modelID === "string" ? input.modelID : typeof input.id === "string" ? input.id : undefined
96+
if (!modelID) return
97+
return {
98+
providerID: ProviderV2.ID.make(input.providerID),
99+
modelID: ProviderV2.ModelID.make(modelID),
100+
...(typeof input.variant === "string" ? { variant: input.variant } : {}),
101+
}
102+
}
103+
104+
const legacyModel = (input: unknown, fallback?: User["model"]) =>
105+
infoModel(input) ?? fallback ?? { providerID: ProviderV2.ID.make("unknown"), modelID: ProviderV2.ModelID.make("unknown") }
106+
107+
const info = (row: typeof MessageTable.$inferSelect, fallbackModel?: User["model"]) => {
108+
const data = row.data as typeof row.data & { agent?: unknown; mode?: unknown; model?: unknown }
94109
return {
95110
...row.data,
96111
id: row.id,
97112
sessionID: row.session_id,
98113
...(typeof data.agent === "string" ? {} : { agent: typeof data.mode === "string" ? data.mode : "build" }),
114+
...(data.role === "user" ? { model: legacyModel(data.model, fallbackModel) } : {}),
99115
} as Info
100116
}
101117

@@ -113,6 +129,20 @@ const older = (row: Cursor) =>
113129
function hydrate(db: Database.Interface["db"], rows: (typeof MessageTable.$inferSelect)[]) {
114130
const ids = rows.map((row) => row.id)
115131
const partByMessage = new Map<string, Part[]>()
132+
const modelByParent = new Map<string, User["model"]>()
133+
for (const row of rows) {
134+
const data = row.data as typeof row.data & {
135+
modelID?: unknown
136+
parentID?: unknown
137+
providerID?: unknown
138+
variant?: unknown
139+
}
140+
if (data.role !== "assistant" || typeof data.parentID !== "string") continue
141+
modelByParent.set(
142+
data.parentID,
143+
legacyModel({ providerID: data.providerID, modelID: data.modelID, variant: data.variant }),
144+
)
145+
}
116146
return Effect.gen(function* () {
117147
if (ids.length > 0) {
118148
const partRows = yield* db
@@ -131,7 +161,7 @@ function hydrate(db: Database.Interface["db"], rows: (typeof MessageTable.$infer
131161
}
132162

133163
return rows.map((row) => ({
134-
info: info(row),
164+
info: info(row, modelByParent.get(row.id)),
135165
parts: partByMessage.get(row.id) ?? [],
136166
}))
137167
})

packages/opencode/test/server/httpapi-session.test.ts

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -215,11 +215,12 @@ const insertLegacyMessageV2Assistant = (sessionID: SessionIDType, parentID: Mess
215215

216216
const insertLegacyMessageV2User = (sessionID: SessionIDType) =>
217217
Effect.sync(() => {
218+
const id = MessageID.ascending()
218219
Database.use((db) =>
219220
db
220221
.insert(MessageTable)
221222
.values({
222-
id: MessageID.ascending(),
223+
id,
223224
session_id: sessionID,
224225
time_created: 1,
225226
time_updated: 1,
@@ -231,6 +232,7 @@ const insertLegacyMessageV2User = (sessionID: SessionIDType) =>
231232
})
232233
.run(),
233234
)
235+
return id
234236
})
235237

236238
const setLegacySummaryDiff = (sessionID: SessionIDType) =>
@@ -691,31 +693,23 @@ describe("session HttpApi", () => {
691693
() =>
692694
Effect.gen(function* () {
693695
const test = yield* TestInstance
694-
const userSession = yield* createSession({ title: "legacy user" })
695-
const assistantSession = yield* createSession({ title: "legacy assistant" })
696-
const message = yield* createTextMessage(assistantSession.id, "hello")
697-
yield* insertLegacyMessageV2User(userSession.id)
698-
yield* insertLegacyMessageV2Assistant(assistantSession.id, message.info.id)
696+
const session = yield* createSession({ title: "legacy messages" })
697+
const userID = yield* insertLegacyMessageV2User(session.id)
698+
yield* insertLegacyMessageV2Assistant(session.id, userID)
699699

700700
const headers = { "x-opencode-directory": test.directory }
701-
const userResponse = yield* request(
702-
`${pathFor(SessionPaths.messages, { sessionID: userSession.id })}?limit=80`,
703-
{ headers },
704-
)
705-
const assistantResponse = yield* request(
706-
`${pathFor(SessionPaths.messages, { sessionID: assistantSession.id })}?limit=80`,
707-
{ headers },
708-
)
701+
const response = yield* request(`${pathFor(SessionPaths.messages, { sessionID: session.id })}?limit=80`, {
702+
headers,
703+
})
704+
const messages = yield* json<MessageV2.WithParts[]>(response)
709705

710-
expect(userResponse.status).toBe(200)
711-
expect((yield* json<MessageV2.WithParts[]>(userResponse))[0]?.info).toMatchObject({
706+
expect(response.status).toBe(200)
707+
expect(messages.find((item) => item.info.role === "user")?.info).toMatchObject({
712708
role: "user",
713709
agent: "build",
710+
model: { providerID: "test", modelID: "test" },
714711
})
715-
expect(assistantResponse.status).toBe(200)
716-
expect(
717-
(yield* json<MessageV2.WithParts[]>(assistantResponse)).find((item) => item.info.role === "assistant")?.info,
718-
).toMatchObject({
712+
expect(messages.find((item) => item.info.role === "assistant")?.info).toMatchObject({
719713
role: "assistant",
720714
agent: "build",
721715
})

0 commit comments

Comments
 (0)