Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 16 additions & 15 deletions packages/opencode/src/session/compaction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,21 @@ export namespace SessionCompaction {
model: model.info,
abort: input.abort,
})
const modelMessages = await MessageV2.toModelMessage(
input.messages.filter((m) => {
if (m.info.role !== "assistant" || m.info.error === undefined) {
return true
}
if (
MessageV2.AbortedError.isInstance(m.info.error) &&
m.parts.some((part) => part.type !== "step-start" && part.type !== "reasoning")
) {
return true
}

return false
}),
)
const result = await processor.process(() =>
streamText({
onError(error) {
Expand Down Expand Up @@ -157,21 +172,7 @@ export namespace SessionCompaction {
content: x,
}),
),
...MessageV2.toModelMessage(
input.messages.filter((m) => {
if (m.info.role !== "assistant" || m.info.error === undefined) {
return true
}
if (
MessageV2.AbortedError.isInstance(m.info.error) &&
m.parts.some((part) => part.type !== "step-start" && part.type !== "reasoning")
) {
return true
}

return false
}),
),
...modelMessages,
{
role: "user",
content: [
Expand Down
10 changes: 8 additions & 2 deletions packages/opencode/src/session/message-v2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { Snapshot } from "@/snapshot"
import { fn } from "@/util/fn"
import { Storage } from "@/storage/storage"
import { ProviderTransform } from "@/provider/transform"
import { ulid } from "ulid"

export namespace MessageV2 {
export const OutputLengthError = NamedError.create("MessageOutputLengthError", z.object({}))
Expand Down Expand Up @@ -549,12 +550,12 @@ export namespace MessageV2 {
throw new Error("unknown message type")
}

export function toModelMessage(
export async function toModelMessage(
input: {
info: Info
parts: Part[]
}[],
): ModelMessage[] {
): Promise<ModelMessage[]> {
const result: UIMessage[] = []

for (const msg of input) {
Expand Down Expand Up @@ -616,6 +617,11 @@ export namespace MessageV2 {
type: "step-start",
})
if (part.type === "tool") {
// Fix empty callID from providers that don't generate tool call IDs (e.g. Gemini)
if (!part.callID) {
part.callID = ulid()
await Storage.write(["part", part.messageID, part.id], part)
}
if (part.state.status === "completed") {
if (part.state.attachments?.length) {
result.push({
Expand Down
3 changes: 2 additions & 1 deletion packages/opencode/src/session/processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { MessageV2 } from "./message-v2"
import { type StreamTextResult, type Tool as AITool, APICallError } from "ai"
import { Log } from "@/util/log"
import { Identifier } from "@/id/id"
import { ulid } from "ulid"
import { Session } from "."
import { Agent } from "@/agent/agent"
import { Permission } from "@/permission"
Expand Down Expand Up @@ -101,7 +102,7 @@ export namespace SessionProcessor {
sessionID: input.assistantMessage.sessionID,
type: "tool",
tool: value.toolName,
callID: value.id,
callID: value.id || ulid(),
state: {
status: "pending",
input: {},
Expand Down
36 changes: 19 additions & 17 deletions packages/opencode/src/session/prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,22 @@ export namespace SessionPrompt {
})
}

const modelMessages = await MessageV2.toModelMessage(
msgs.filter((m) => {
if (m.info.role !== "assistant" || m.info.error === undefined) {
return true
}
if (
MessageV2.AbortedError.isInstance(m.info.error) &&
m.parts.some((part) => part.type !== "step-start" && part.type !== "reasoning")
) {
return true
}

return false
}),
)

const result = await processor.process(() =>
streamText({
onError(error) {
Expand Down Expand Up @@ -563,21 +579,7 @@ export namespace SessionPrompt {
content: x,
}),
),
...MessageV2.toModelMessage(
msgs.filter((m) => {
if (m.info.role !== "assistant" || m.info.error === undefined) {
return true
}
if (
MessageV2.AbortedError.isInstance(m.info.error) &&
m.parts.some((part) => part.type !== "step-start" && part.type !== "reasoning")
) {
return true
}

return false
}),
),
...modelMessages,
],
tools: model.info.tool_call === false ? undefined : tools,
model: wrapLanguageModel({
Expand Down Expand Up @@ -1431,7 +1433,7 @@ export namespace SessionPrompt {
role: "user",
content: "Generate a title for this conversation:\n",
},
...MessageV2.toModelMessage([
...(await MessageV2.toModelMessage([
{
info: {
id: Identifier.ascending("message"),
Expand All @@ -1448,7 +1450,7 @@ export namespace SessionPrompt {
},
parts: input.message.parts,
},
]),
])),
],
headers: small.info.headers,
model: small.language,
Expand Down
2 changes: 1 addition & 1 deletion packages/opencode/src/session/summary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ export namespace SessionSummary {
content: x,
}),
),
...MessageV2.toModelMessage(messages),
...(await MessageV2.toModelMessage(messages)),
{
role: "user",
content: `Summarize the above conversation according to your system prompts.`,
Expand Down