fix(cli): mark context synthetic

This commit is contained in:
Alex Alecu
2026-04-28 10:46:26 +03:00
parent 37b54fced2
commit 9e67b52e7e
3 changed files with 63 additions and 1 deletions
@@ -91,6 +91,7 @@ export namespace KiloSessionPrompt {
messageID: input.msgs[idx].info.id,
type: "text",
text: input.cache.block,
synthetic: true,
} satisfies MessageV2.TextPart,
],
}
@@ -416,6 +416,23 @@ describe("KiloSessionPrompt.stripHistoricalMedia", () => {
// synthetic user preserved as-is
expect(result[4]).toBe(msgs[4])
})
test("skips synthetic user turns with injected context when picking the cutoff", () => {
const currentImage = filePart("msg_current", "image/png", "current.png")
const msgs = [
user("msg_hist", [textPart("msg_hist", "older"), filePart("msg_hist", "image/png", "old.png")]),
user("msg_current", [textPart("msg_current", "check this"), currentImage]),
user("msg_syn", [
syntheticTextPart("msg_syn", "Summarize the task tool output above and continue with your task."),
syntheticTextPart("msg_syn", "<environment_details>\nCurrent time: now\n</environment_details>", "p_env"),
]),
]
const result = KiloSessionPrompt.stripHistoricalMedia(msgs)
expect(result[1].parts[1]).toBe(currentImage)
const hist = result[0].parts[1]
expect(hist.type).toBe("text")
expect((hist as MessageV2.TextPart).text).toBe("[Attached image/png: old.png]")
})
})
describe("KiloSessionPrompt.maybeStripHistoricalMedia", () => {
@@ -180,6 +180,7 @@ const cfg = {
temperature: false,
tool_call: true,
release_date: "2025-01-01",
modalities: { input: ["text" as const, "image" as const, "pdf" as const], output: ["text" as const] },
limit: { context: 100000, output: 10000 },
cost: { input: 0, output: 0 },
options: {},
@@ -209,7 +210,11 @@ function providerCfg(url: string) {
}
}
const user = Effect.fn("prompt-safety.user")(function* (sessionID: SessionID, text: string) {
const user = Effect.fn("prompt-safety.user")(function* (
sessionID: SessionID,
text: string,
input?: { synthetic?: boolean; editorContext?: MessageV2.User["editorContext"] },
) {
const sessions = yield* Session.Service
const msg = yield* sessions.updateMessage({
id: MessageID.ascending(),
@@ -219,6 +224,7 @@ const user = Effect.fn("prompt-safety.user")(function* (sessionID: SessionID, te
model: ref,
time: { created: Date.now() },
tools: {},
editorContext: input?.editorContext,
} satisfies MessageV2.User)
yield* sessions.updatePart({
id: PartID.ascending(),
@@ -226,6 +232,7 @@ const user = Effect.fn("prompt-safety.user")(function* (sessionID: SessionID, te
sessionID,
type: "text",
text,
synthetic: input?.synthetic,
} satisfies MessageV2.TextPart)
return msg
})
@@ -343,4 +350,41 @@ describe("SessionPrompt compaction safety", () => {
{ git: true, config: providerCfg },
),
)
it.live("preserves current media before synthetic handoff with editor context", () =>
provideTmpdirServer(
Effect.fnUntraced(function* ({ llm }) {
const prompt = yield* SessionPrompt.Service
const sessions = yield* Session.Service
const chat = yield* sessions.create({
title: "Prompt handoff safety",
permission: [{ permission: "*", pattern: "*", action: "allow" }],
})
const status = yield* user(chat.id, "status?")
yield* assistant(chat.id, status.id, { text: "summary body", summary: true })
const hist = yield* user(chat.id, "older image")
yield* file(chat.id, hist.id, { mime: "image/png", name: "old.png", body: "OLDIMAGE" })
const current = yield* user(chat.id, "check this image")
yield* file(chat.id, current.id, { mime: "image/png", name: "current.png", body: "CURRENTIMAGE" })
yield* assistant(chat.id, current.id, { text: "handoff", summary: false })
yield* user(chat.id, "Summarize the task tool output above and continue with your task.", {
synthetic: true,
editorContext: { activeFile: "src/app.ts" },
})
yield* llm.text("final answer")
yield* prompt.loop({ sessionID: chat.id })
const inputs = yield* llm.inputs
const body = JSON.stringify(inputs.at(-1)?.messages)
expect(body).toContain("[Attached image/png: old.png]")
expect(body).toContain("CURRENTIMAGE")
expect(body).toContain("src/app.ts")
expect(body).not.toContain("OLDIMAGE")
expect(body).not.toContain("[Attached image/png: current.png]")
}),
{ git: true, config: providerCfg },
),
)
})