Dax Raad 4 месяцев назад
Родитель
Сommit
736a85d427

+ 1 - 0
packages/opencode/src/session/message-v2.ts

@@ -162,6 +162,7 @@ export namespace MessageV2 {
 
   export const StepFinishPart = PartBase.extend({
     type: z.literal("step-finish"),
+    reason: z.string(),
     snapshot: z.string().optional(),
     cost: z.number(),
     tokens: z.object({

+ 1 - 0
packages/opencode/src/session/prompt.ts

@@ -1270,6 +1270,7 @@ export namespace SessionPrompt {
                 assistantMsg.tokens = usage.tokens
                 await Session.updatePart({
                   id: Identifier.ascending("part"),
+                  reason: value.finishReason,
                   snapshot: await Snapshot.track(),
                   messageID: assistantMsg.id,
                   sessionID: assistantMsg.sessionID,

+ 14 - 5
packages/opencode/src/session/summary.ts

@@ -4,14 +4,16 @@ import z from "zod"
 import { Session } from "."
 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 { ProviderTransform } from "@/provider/transform"
 import { SystemPrompt } from "./system"
+import { Log } from "@/util/log"
 
 export namespace SessionSummary {
+  const log = Log.create({ service: "session.summary" })
+
   export const summarize = fn(
     z.object({
       sessionID: z.string(),
@@ -53,7 +55,7 @@ export namespace SessionSummary {
     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
+    const textPart = msgWithParts.parts.find((p) => p.type === "text" && !p.synthetic) as MessageV2.TextPart
     if (textPart && !userMsg.summary?.title) {
       const result = await generateText({
         maxOutputTokens: small.info.reasoning ? 1500 : 20,
@@ -72,19 +74,25 @@ export namespace SessionSummary {
         ],
         model: small.language,
       })
+      log.info("title", { title: result.text })
       userMsg.summary.title = result.text
       await Session.updateMessage(userMsg)
     }
 
-    if (messages.every((m) => m.info.role !== "assistant" || m.info.time.completed)) {
+    if (
+      messages.some(
+        (m) =>
+          m.info.role === "assistant" && m.parts.some((p) => p.type === "step-finish" && p.reason !== "tool-calls"),
+      )
+    ) {
       const result = await generateText({
         model: small.language,
-        maxOutputTokens: 100,
+        maxOutputTokens: 50,
         messages: [
           {
             role: "user",
             content: `
-            Summarize the following conversation into 2 sentences MAX explaining what the assistant did and why. Do not explain the user's input.
+            Summarize the following conversation into 2 sentences MAX explaining what the assistant did and why. Do not explain the user's input. Do not speak in the third person about the assistant.
             <conversation>
             ${JSON.stringify(MessageV2.toModelMessage(messages))}
             </conversation>
@@ -93,6 +101,7 @@ export namespace SessionSummary {
         ],
       })
       userMsg.summary.body = result.text
+      log.info("body", { body: result.text })
       await Session.updateMessage(userMsg)
     }
   }