summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorDax Raad <[email protected]>2025-10-24 11:49:27 -0400
committerDax Raad <[email protected]>2025-10-24 11:50:42 -0400
commitfb40dc6b20aefcfb1258f25c22396ad966ccbc7b (patch)
tree9be9eba1fb5e6639162019de38476fe8cb8f9ed5
parent483fcdaddba6e6da677079e59367a1eb4a996d66 (diff)
downloadopencode-fb40dc6b20aefcfb1258f25c22396ad966ccbc7b.tar.gz
opencode-fb40dc6b20aefcfb1258f25c22396ad966ccbc7b.zip
generate user message title and body
-rw-r--r--packages/opencode/src/session/message-v2.ts4
-rw-r--r--packages/opencode/src/session/summary.ts52
-rw-r--r--packages/sdk/js/src/gen/types.gen.ts3
3 files changed, 43 insertions, 16 deletions
diff --git a/packages/opencode/src/session/message-v2.ts b/packages/opencode/src/session/message-v2.ts
index bd3691881..9e42a6f2b 100644
--- a/packages/opencode/src/session/message-v2.ts
+++ b/packages/opencode/src/session/message-v2.ts
@@ -6,7 +6,6 @@ import { APICallError, convertToModelMessages, LoadAPIKeyError, type ModelMessag
import { Identifier } from "../id/id"
import { LSP } from "../lsp"
import { Snapshot } from "@/snapshot"
-import { fn } from "@/util/fn"
export namespace MessageV2 {
export const OutputLengthError = NamedError.create("MessageOutputLengthError", z.object({}))
@@ -268,8 +267,9 @@ export namespace MessageV2 {
}),
summary: z
.object({
+ title: z.string().optional(),
+ body: z.string().optional(),
diffs: Snapshot.FileDiff.array(),
- text: z.string(),
})
.optional(),
}).meta({
diff --git a/packages/opencode/src/session/summary.ts b/packages/opencode/src/session/summary.ts
index 19aba1548..de8567882 100644
--- a/packages/opencode/src/session/summary.ts
+++ b/packages/opencode/src/session/summary.ts
@@ -2,12 +2,14 @@ import { Provider } from "@/provider/provider"
import { fn } from "@/util/fn"
import z from "zod"
import { Session } from "."
-import { generateText } from "ai"
+import { generateText, type ModelMessage } from "ai"
import { MessageV2 } from "./message-v2"
import { Flag } from "@/flag/flag"
import { Identifier } from "@/id/id"
import { Snapshot } from "@/snapshot"
-import type { UserMessage } from "@opencode-ai/sdk"
+
+import { ProviderTransform } from "@/provider/transform"
+import { SystemPrompt } from "./system"
export namespace SessionSummary {
export const summarize = fn(
@@ -38,19 +40,43 @@ export namespace SessionSummary {
const messages = input.messages.filter(
(m) => m.info.id === input.messageID || (m.info.role === "assistant" && m.info.parentID === input.messageID),
)
- const userMsg = messages.find((m) => m.info.id === input.messageID)!.info as UserMessage
+ const msgWithParts = messages.find((m) => m.info.id === input.messageID)!
+ const userMsg = msgWithParts.info as MessageV2.User
const diffs = await computeDiff({ messages })
userMsg.summary = {
+ ...userMsg.summary,
diffs,
- text: userMsg.summary?.text ?? "",
}
- if (
- Flag.OPENCODE_EXPERIMENTAL_TURN_SUMMARY &&
- messages.every((m) => m.info.role !== "assistant" || m.info.time.completed)
- ) {
- const assistantMsg = messages.find((m) => m.info.role === "assistant")!.info as MessageV2.Assistant
- const small = await Provider.getSmallModel(assistantMsg.providerID)
- if (!small) return
+ await Session.updateMessage(userMsg)
+
+ const assistantMsg = messages.find((m) => m.info.role === "assistant")!.info as MessageV2.Assistant
+ const small = await Provider.getSmallModel(assistantMsg.providerID)
+ if (!small) return
+
+ const textPart = msgWithParts.parts.find((p) => p.type === "text" && p.synthetic === false) as MessageV2.TextPart
+ if (textPart && !userMsg.summary?.title) {
+ const result = await generateText({
+ maxOutputTokens: small.info.reasoning ? 1500 : 20,
+ providerOptions: ProviderTransform.providerOptions(small.npm, small.providerID, {}),
+ messages: [
+ ...SystemPrompt.title(small.providerID).map(
+ (x): ModelMessage => ({
+ role: "system",
+ content: x,
+ }),
+ ),
+ {
+ role: "user" as const,
+ content: textPart?.text ?? "",
+ },
+ ],
+ model: small.language,
+ })
+ userMsg.summary.title = result.text
+ await Session.updateMessage(userMsg)
+ }
+
+ if (messages.every((m) => m.info.role !== "assistant" || m.info.time.completed)) {
const result = await generateText({
model: small.language,
maxOutputTokens: 100,
@@ -66,9 +92,9 @@ export namespace SessionSummary {
},
],
})
- userMsg.summary.text = result.text
+ userMsg.summary.body = result.text
+ await Session.updateMessage(userMsg)
}
- await Session.updateMessage(userMsg)
}
export const diff = fn(
diff --git a/packages/sdk/js/src/gen/types.gen.ts b/packages/sdk/js/src/gen/types.gen.ts
index 3dd785dd8..3c53b4ac1 100644
--- a/packages/sdk/js/src/gen/types.gen.ts
+++ b/packages/sdk/js/src/gen/types.gen.ts
@@ -602,8 +602,9 @@ export type UserMessage = {
created: number
}
summary?: {
+ title?: string
+ body?: string
diffs: Array<FileDiff>
- text: string
}
}