Compare commits

...

2 Commits

Author SHA1 Message Date
Kit Langton 219ded0330 fix(core): prioritize manual compaction 2026-07-08 11:38:43 -04:00
Kit Langton 2062a5a3a8 fix(core): steer manual compaction 2026-07-07 20:44:34 -04:00
2 changed files with 18 additions and 9 deletions
+2 -5
View File
@@ -624,13 +624,10 @@ const layer = Layer.effect(
} }
needsContinuation = result.needsContinuation needsContinuation = result.needsContinuation
step = result.step + 1 step = result.step + 1
if (needsContinuation) { // Manual compaction is a barrier: handle it before continuing or promoting steers.
promotion = (yield* SessionInput.pendingCompaction(db, input.sessionID)) ? undefined : "steer"
continue
}
yield* runPendingCompaction(input.sessionID) yield* runPendingCompaction(input.sessionID)
promotion = "steer" promotion = "steer"
needsContinuation = yield* SessionInput.hasPending(db, input.sessionID, "steer") if (!needsContinuation) needsContinuation = yield* SessionInput.hasPending(db, input.sessionID, "steer")
} }
yield* runPendingCompaction(input.sessionID) yield* runPendingCompaction(input.sessionID)
const hasSteer = yield* SessionInput.hasPending(db, input.sessionID, "steer") const hasSteer = yield* SessionInput.hasPending(db, input.sessionID, "steer")
+16 -4
View File
@@ -1346,16 +1346,22 @@ describe("SessionRunnerLLM", () => {
}), }),
) )
it.effect("runs one durable compaction barrier before later steer and queued prompts", () => it.effect("runs compaction at the next step boundary before continuation, steer, and queue", () =>
Effect.gen(function* () { Effect.gen(function* () {
yield* setup yield* setup
requests.length = 0 requests.length = 0
executions.length = 0
currentModel = recoveryModel currentModel = recoveryModel
const session = yield* SessionV2.Service const session = yield* SessionV2.Service
streamGate = yield* Deferred.make<void>() streamGate = yield* Deferred.make<void>()
streamStarted = yield* Deferred.make<void>() streamStarted = yield* Deferred.make<void>()
responses = [ responses = [
fragmentFixture("text", "text-active", ["Active complete"]).completeEvents, [
LLMEvent.stepStart({ index: 0 }),
LLMEvent.toolCall({ id: "call-before-compaction", name: "echo", input: { text: "before compaction" } }),
LLMEvent.stepFinish({ index: 0, reason: "tool-calls" }),
LLMEvent.finish({ reason: "tool-calls" }),
],
[LLMEvent.textDelta({ id: "summary", text: "durable summary" })], [LLMEvent.textDelta({ id: "summary", text: "durable summary" })],
fragmentFixture("text", "text-steer", ["Steer complete"]).completeEvents, fragmentFixture("text", "text-steer", ["Steer complete"]).completeEvents,
fragmentFixture("text", "text-queue", ["Queue complete"]).completeEvents, fragmentFixture("text", "text-queue", ["Queue complete"]).completeEvents,
@@ -1365,8 +1371,12 @@ describe("SessionRunnerLLM", () => {
yield* Deferred.await(streamStarted) yield* Deferred.await(streamStarted)
const first = yield* session.compact({ sessionID }) const first = yield* session.compact({ sessionID })
const second = yield* session.compact({ sessionID }) const [exactRetry, coalesced] = yield* Effect.all(
expect(second.id).toBe(first.id) [session.compact({ id: first.id, sessionID }), session.compact({ sessionID })],
{ concurrency: "unbounded" },
)
expect(exactRetry.id).toBe(first.id)
expect(coalesced.id).toBe(first.id)
expect(yield* SessionInput.pendingCompaction((yield* Database.Service).db, sessionID)).toMatchObject({ expect(yield* SessionInput.pendingCompaction((yield* Database.Service).db, sessionID)).toMatchObject({
id: first.id, id: first.id,
}) })
@@ -1392,6 +1402,8 @@ describe("SessionRunnerLLM", () => {
yield* Fiber.join(active) yield* Fiber.join(active)
expect(requests).toHaveLength(4) expect(requests).toHaveLength(4)
expect(executions).toEqual(["before compaction"])
expect(userTexts(requests[0])).toContain("Active work")
expect(userTexts(requests[1])[0]).toContain("Create a new anchored summary") expect(userTexts(requests[1])[0]).toContain("Create a new anchored summary")
expect(userTexts(requests[2])).toContain("Steer after compaction") expect(userTexts(requests[2])).toContain("Steer after compaction")
expect(userTexts(requests[3])).toContain("Queue after compaction") expect(userTexts(requests[3])).toContain("Queue after compaction")