session summaries in data

This commit is contained in:
Dax Raad
2025-10-23 16:28:20 -04:00
parent f4dfae0bb0
commit cee7106054
4 changed files with 60 additions and 39 deletions

View File

@@ -36,7 +36,7 @@ import { MCP } from "../mcp"
import { Storage } from "../storage/storage" import { Storage } from "../storage/storage"
import type { ContentfulStatusCode } from "hono/utils/http-status" import type { ContentfulStatusCode } from "hono/utils/http-status"
import { Snapshot } from "@/snapshot" import { Snapshot } from "@/snapshot"
import { MessageSummary } from "@/session/summary" import { SessionSummary } from "@/session/summary"
const ERRORS = { const ERRORS = {
400: { 400: {
@@ -629,19 +629,19 @@ export namespace Server {
validator( validator(
"param", "param",
z.object({ z.object({
id: MessageSummary.diff.schema.shape.sessionID, id: SessionSummary.diff.schema.shape.sessionID,
}), }),
), ),
validator( validator(
"query", "query",
z.object({ z.object({
messageID: MessageSummary.diff.schema.shape.messageID, messageID: SessionSummary.diff.schema.shape.messageID,
}), }),
), ),
async (c) => { async (c) => {
const query = c.req.valid("query") const query = c.req.valid("query")
const params = c.req.valid("param") const params = c.req.valid("param")
const result = await MessageSummary.diff({ const result = await SessionSummary.diff({
sessionID: params.id, sessionID: params.id,
messageID: query.messageID, messageID: query.messageID,
}) })

View File

@@ -36,6 +36,11 @@ export namespace Session {
projectID: z.string(), projectID: z.string(),
directory: z.string(), directory: z.string(),
parentID: Identifier.schema("session").optional(), parentID: Identifier.schema("session").optional(),
summary: z
.object({
diffs: Snapshot.FileDiff.array(),
})
.optional(),
share: z share: z
.object({ .object({
url: z.string(), url: z.string(),

View File

@@ -49,7 +49,7 @@ import { spawn } from "child_process"
import { Command } from "../command" import { Command } from "../command"
import { $, fileURLToPath } from "bun" import { $, fileURLToPath } from "bun"
import { ConfigMarkdown } from "../config/markdown" import { ConfigMarkdown } from "../config/markdown"
import { MessageSummary } from "./summary" import { SessionSummary } from "./summary"
export namespace SessionPrompt { export namespace SessionPrompt {
const log = Log.create({ service: "session.prompt" }) const log = Log.create({ service: "session.prompt" })
@@ -1292,7 +1292,7 @@ export namespace SessionPrompt {
} }
snapshot = undefined snapshot = undefined
} }
MessageSummary.summarize({ SessionSummary.summarize({
sessionID: input.sessionID, sessionID: input.sessionID,
messageID: assistantMsg.parentID, messageID: assistantMsg.parentID,
providerID: assistantMsg.modelID, providerID: assistantMsg.modelID,

View File

@@ -8,7 +8,7 @@ import { Flag } from "@/flag/flag"
import { Identifier } from "@/id/id" import { Identifier } from "@/id/id"
import { Snapshot } from "@/snapshot" import { Snapshot } from "@/snapshot"
export namespace MessageSummary { export namespace SessionSummary {
export const summarize = fn( export const summarize = fn(
z.object({ z.object({
sessionID: z.string(), sessionID: z.string(),
@@ -16,10 +16,26 @@ export namespace MessageSummary {
providerID: z.string(), providerID: z.string(),
}), }),
async (input) => { async (input) => {
const messages = await Session.messages(input.sessionID).then((msgs) => const all = await Session.messages(input.sessionID)
msgs.filter( await Promise.all([
summarizeSession({ sessionID: input.sessionID, messages: all }),
summarizeMessage({ messageID: input.messageID, messages: all }),
])
},
)
async function summarizeSession(input: { sessionID: string; messages: MessageV2.WithParts[] }) {
const diffs = await computeDiff({ messages: input.messages })
await Session.update(input.sessionID, (draft) => {
draft.summary = {
diffs,
}
})
}
async function summarizeMessage(input: { messageID: string; messages: MessageV2.WithParts[] }) {
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)! const userMsg = messages.find((m) => m.info.id === input.messageID)!
const diffs = await computeDiff({ messages }) const diffs = await computeDiff({ messages })
@@ -31,7 +47,8 @@ export namespace MessageSummary {
Flag.OPENCODE_EXPERIMENTAL_TURN_SUMMARY && Flag.OPENCODE_EXPERIMENTAL_TURN_SUMMARY &&
messages.every((m) => m.info.role !== "assistant" || m.info.time.completed) messages.every((m) => m.info.role !== "assistant" || m.info.time.completed)
) { ) {
const small = await Provider.getSmallModel(input.providerID) const assistantMsg = messages.find((m) => m.info.role === "assistant")!.info as MessageV2.Assistant
const small = await Provider.getSmallModel(assistantMsg.providerID)
if (!small) return if (!small) return
const result = await generateText({ const result = await generateText({
model: small.language, model: small.language,
@@ -54,8 +71,7 @@ export namespace MessageSummary {
} }
} }
await Session.updateMessage(userMsg.info) await Session.updateMessage(userMsg.info)
}, }
)
export const diff = fn( export const diff = fn(
z.object({ z.object({