generate user message title and body

This commit is contained in:
Dax Raad
2025-10-24 11:49:27 -04:00
parent 483fcdaddb
commit fb40dc6b20
3 changed files with 43 additions and 16 deletions

View File

@@ -6,7 +6,6 @@ import { APICallError, convertToModelMessages, LoadAPIKeyError, type ModelMessag
import { Identifier } from "../id/id" import { Identifier } from "../id/id"
import { LSP } from "../lsp" import { LSP } from "../lsp"
import { Snapshot } from "@/snapshot" import { Snapshot } from "@/snapshot"
import { fn } from "@/util/fn"
export namespace MessageV2 { export namespace MessageV2 {
export const OutputLengthError = NamedError.create("MessageOutputLengthError", z.object({})) export const OutputLengthError = NamedError.create("MessageOutputLengthError", z.object({}))
@@ -268,8 +267,9 @@ export namespace MessageV2 {
}), }),
summary: z summary: z
.object({ .object({
title: z.string().optional(),
body: z.string().optional(),
diffs: Snapshot.FileDiff.array(), diffs: Snapshot.FileDiff.array(),
text: z.string(),
}) })
.optional(), .optional(),
}).meta({ }).meta({

View File

@@ -2,12 +2,14 @@ import { Provider } from "@/provider/provider"
import { fn } from "@/util/fn" import { fn } from "@/util/fn"
import z from "zod" import z from "zod"
import { Session } from "." import { Session } from "."
import { generateText } from "ai" import { generateText, type ModelMessage } from "ai"
import { MessageV2 } from "./message-v2" import { MessageV2 } from "./message-v2"
import { Flag } from "@/flag/flag" import { Flag } from "@/flag/flag"
import { Identifier } from "@/id/id" import { Identifier } from "@/id/id"
import { Snapshot } from "@/snapshot" import { Snapshot } from "@/snapshot"
import type { UserMessage } from "@opencode-ai/sdk"
import { ProviderTransform } from "@/provider/transform"
import { SystemPrompt } from "./system"
export namespace SessionSummary { export namespace SessionSummary {
export const summarize = fn( export const summarize = fn(
@@ -38,19 +40,43 @@ export namespace SessionSummary {
const messages = input.messages.filter( const messages = input.messages.filter(
(m) => m.info.id === input.messageID || (m.info.role === "assistant" && m.info.parentID === input.messageID), (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 }) const diffs = await computeDiff({ messages })
userMsg.summary = { userMsg.summary = {
...userMsg.summary,
diffs, diffs,
text: userMsg.summary?.text ?? "",
} }
if ( await Session.updateMessage(userMsg)
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 assistantMsg = messages.find((m) => m.info.role === "assistant")!.info as MessageV2.Assistant
const small = await Provider.getSmallModel(assistantMsg.providerID) const small = await Provider.getSmallModel(assistantMsg.providerID)
if (!small) return 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({ const result = await generateText({
model: small.language, model: small.language,
maxOutputTokens: 100, maxOutputTokens: 100,
@@ -66,10 +92,10 @@ 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( export const diff = fn(
z.object({ z.object({

View File

@@ -602,8 +602,9 @@ export type UserMessage = {
created: number created: number
} }
summary?: { summary?: {
title?: string
body?: string
diffs: Array<FileDiff> diffs: Array<FileDiff>
text: string
} }
} }