fix(core): simplify compaction semantics (#36267)

This commit is contained in:
Kit Langton 2026-07-10 11:36:29 -04:00 committed by GitHub
commit cf5e0adf02
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 192 additions and 196 deletions

View file

@ -147,10 +147,11 @@ it.effect("manual compaction summarizes short context instead of no-op", () =>
messages: [userMessage],
inputID: SessionMessage.ID.make("msg_manual_compaction"),
}),
).toBe(true)
).toEqual({ status: "completed" })
expect(Array.from(yield* Fiber.join(delta)).map((event) => event.data.text)).toEqual(["manual summary"])
expect(requests).toHaveLength(1)
expect(requests[0]?.generation).toBeUndefined()
expect(JSON.stringify(requests[0]?.messages)).toContain("Manual compaction should include this short conversation.")
expect(yield* store.context(sessionID)).toMatchObject([
{ type: "compaction", reason: "manual", summary: "manual summary", recent: "" },

View file

@ -113,6 +113,16 @@ const reply = {
LLMEvent.finish({ reason: "stop" }),
],
text: (text: string, id: string) => fragmentFixture("text", id, [text]).completeEvents,
textWithUsage: (text: string, id: string, inputTokens: number) =>
fragmentFixture("text", id, [text]).completeEvents.map((event) =>
LLMEvent.is.stepFinish(event)
? LLMEvent.stepFinish({
index: event.index,
reason: event.reason,
usage: { inputTokens, nonCachedInputTokens: inputTokens },
})
: event,
),
tool: (id: string, name: string, input: unknown) => [
LLMEvent.stepStart({ index: 0 }),
LLMEvent.toolCall({ id, name, input }),
@ -1696,7 +1706,7 @@ describe("SessionRunnerLLM", () => {
it.effect("automatically compacts into a completed summary and retained recent turn", () =>
Effect.gen(function* () {
const session = yield* setup
response = reply.text("Earlier answer", "text-first")
response = reply.textWithUsage("Earlier answer", "text-first", 3_950)
yield* admit(session, "Earlier question ".repeat(180))
yield* session.resume(sessionID)
@ -1704,7 +1714,7 @@ describe("SessionRunnerLLM", () => {
requests.length = 0
responses = [
reply.text("## Objective\n- Preserve the task", "text-summary"),
reply.text("Continued", "text-final"),
reply.textWithUsage("Continued", "text-final", 3_950),
]
yield* admit(session, "Recent exact request ".repeat(180))
yield* session.resume(sessionID)
@ -1743,6 +1753,35 @@ describe("SessionRunnerLLM", () => {
}),
)
it.effect("stops after required automatic compaction fails", () =>
Effect.gen(function* () {
const session = yield* setup
response = reply.textWithUsage("Earlier answer", "text-before-failed-compaction", 3_950)
yield* admit(session, "Earlier question ".repeat(180))
yield* session.resume(sessionID)
currentModel = compactModel
requests.length = 0
responses = [
[LLMEvent.providerError({ message: "Unsupported parameter: max_output_tokens" })],
reply.text("Must not run", "text-after-failed-compaction"),
]
yield* admit(session, "Recent exact request ".repeat(180))
expect(yield* Effect.exit(session.resume(sessionID))).toMatchObject({ _tag: "Failure" })
expect(requests).toHaveLength(1)
expect(requests[0]?.generation).toBeUndefined()
expect(yield* session.context(sessionID)).toContainEqual(
expect.objectContaining({
type: "compaction",
status: "failed",
reason: "auto",
error: expect.objectContaining({ message: "Unsupported parameter: max_output_tokens" }),
}),
)
}),
)
it.effect("forces one compaction and retries after provider context overflow", () =>
Effect.gen(function* () {
const session = yield* setupOverflowRecovery