fix(compact): address PR 110 review findings

Honor cancellation and disposal around async pre-step setup before the loop can open a step or call the model.

Route compaction summarization through agent/request so router agents can select the model, and remove the stale model argument from agent/pre-step.

Document serial events and the approximate convergence bound, regenerate the Cordis catalog, and add regression coverage for router compaction, HMR cleanup, and assembly/pre-step interruption.
This commit is contained in:
Hypatia May
2026-06-29 15:59:52 +08:00
parent c13f25586c
commit 1f35a4446d
18 changed files with 551 additions and 193 deletions
+9 -9
View File
@@ -322,9 +322,9 @@ describe('agent loop', () => {
it('agent/pre-step fires once per step before the step is opened', async () => {
// Two steps (a tool call, then a final text turn) → two model calls → two
// pre-step fires, each carrying the assembled system + model, BEFORE the
// step is opened and its request is derived (the request the adapter sees
// reflects any surface state at fire time).
// pre-step fires, each carrying the assembled full system prompt, BEFORE
// the step is opened and its request is derived (the request the adapter
// sees reflects any surface state at fire time).
const adapter = new MockAdapter([
toolCallResponse('c1', 'echo', {}, 'calling echo'),
textResponse('done'),
@@ -336,18 +336,18 @@ describe('agent loop', () => {
}))
const agent = ctx.agentLoop.create(AgentId('a1'), { model: 'mock' })
const fires: { turn: number; step: number; model: string }[] = []
ctx.on('agent/pre-step', (subject, turn, step, _system, model) => {
if (subject === agent) fires.push({ turn, step, model })
const fires: { turn: number; step: number; fullSystemPrompt: string }[] = []
ctx.on('agent/pre-step', (subject, turn, step, fullSystemPrompt) => {
if (subject === agent) fires.push({ turn, step, fullSystemPrompt })
})
send(agent, 'go')
await waitForIdle(ctx, agent)
// One fire per step, in order, each with the agent's model.
// One fire per step, in order, each with the assembled system prompt.
expect(fires).toEqual([
{ turn: 1, step: 1, model: 'mock' },
{ turn: 1, step: 2, model: 'mock' },
{ turn: 1, step: 1, fullSystemPrompt: '' },
{ turn: 1, step: 2, fullSystemPrompt: '' },
])
})