refactor(agent): simplify inbox-driven turn admission

This commit is contained in:
_Kerman
2026-08-02 00:27:37 +08:00
parent d38c8bfaf3
commit dbdf270af0
104 changed files with 550 additions and 511 deletions

View File

@@ -32,9 +32,9 @@ async function unwrap<T>(response: RpcResponse<T>, dispose: () => Promise<void>)
/**
* Consume mux frames until the task turn ends, per the cli-demo runOneShot
* correlation precedent: anchor on the first turn/start whose trigger kind is
* 'message' (startup-injected turns are skipped), aggregate text from that
* turn's assistant/message events (last one wins), finish on its turn/end.
* correlation precedent: the stream opens immediately before the prompt, so
* its first observed turn/start owns the task. Aggregate text from that turn's
* assistant/message events (last one wins), then finish on its turn/end.
*/
async function consumeUntilTurnEnd(frames: AsyncIterable<RpcRequest<MuxFrame>>, sessionId: SessionId): Promise<TurnOutcome> {
let targetTurn: number | undefined

View File

@@ -92,7 +92,7 @@ async function seedResumeSession(cwd: string): Promise<void> {
{ type: 'step/end', seq: 5, time: 1_700_000_000_006, data: { turn: 1, step: 1 } },
{ type: 'session/title', seq: 6, time: 1_700_000_000_007, data: { title: 'Resume selector design', messageSeqs: [1], source: { kind: 'fallback' } } },
{ type: 'todo/write', seq: 7, time: 1_700_000_000_008, data: { todos: [{ content: 'Preserve restored state', status: 'in_progress' }] } },
{ type: 'turn/end', seq: 8, time: 1_700_000_000_009, data: { turn: 1, reason: { kind: 'completed' } } },
{ type: 'turn/end', seq: 8, time: 1_700_000_000_009, data: { turn: 1, step: 1, reason: { kind: 'completed' } } },
]
const file = logPath(join(cwd, '.sessions'), sessionCwd, id, 'none')
await mkdir(dirname(file), { recursive: true })

View File

@@ -509,14 +509,14 @@ async function runScenario(scenario: Scenario): Promise<ScenarioResult> {
expect(await terminal.snapshot({ includeScrollback: true }))
.toContain('/compact — Compact older conversation history')
const compact = ctx.compact as DeferredSnapshotCompactService
const compact = ctx.compact as unknown as DeferredSnapshotCompactService
const inbox: string[] = []
manualOrder = []
ctx.on('agent/inbox/enqueue', (subject, item) => {
if (subject === agent) inbox.push(`enqueue:${item.placement}:${item.id}`)
ctx.on('agent/inbox/inserted', (subject, { message }) => {
if (subject === agent) inbox.push(`inserted:${message.id}`)
})
ctx.on('agent/inbox/dequeue', (subject, message) => {
if (subject === agent) inbox.push(`dequeue:${message.id}`)
ctx.on('agent/inbox/claimed', (subject, { message }) => {
if (subject === agent) inbox.push(`claimed:${message.id}`)
})
ctx.on('session/event', (session, event) => {
if (session !== agent.session) return
@@ -531,7 +531,7 @@ async function runScenario(scenario: Scenario): Promise<ScenarioResult> {
if (event.type === 'user/message'
&& event.data.source.kind === 'plugin'
&& event.data.source.plugin === 'compact') manualOrder?.push('checkpoint')
if (event.type === 'turn/start') manualOrder?.push(`turn/start:${event.data.trigger.kind}`)
if (event.type === 'turn/start') manualOrder?.push('turn/start')
})
ctx.on('session/flush', (session) => {
if (session === agent.session) manualOrder?.push('flush')
@@ -562,7 +562,7 @@ async function runScenario(scenario: Scenario): Promise<ScenarioResult> {
content: [{ type: 'text', text: 'Injected while compaction was running.' }],
source: { kind: 'plugin', plugin: 'snapshot-injector' },
}))
expect(inbox[0]).toMatch(/^enqueue:queued:/u)
expect(inbox[0]).toMatch(/^inserted:/u)
expect(agent.status).toBe('idle')
expect(agent.session.events.some(event => event.type === 'user/message'
&& event.data.source.kind === 'user'
@@ -575,7 +575,7 @@ async function runScenario(scenario: Scenario): Promise<ScenarioResult> {
agent.session.events.slice(-12).map(event => event.type).join(',')
}`)
await settleTerminal(terminal)
expect(inbox).toEqual([inbox[0], `dequeue:${inbox[0]?.slice('enqueue:queued:'.length) ?? ''}`])
expect(inbox).toEqual([inbox[0], `claimed:${inbox[0]?.slice('inserted:'.length) ?? ''}`])
}
const events: SessionEvent[] = [...agent.session.events]
@@ -641,7 +641,7 @@ async function runScenario(scenario: Scenario): Promise<ScenarioResult> {
const compactStartIndex = manualTimeline.indexOf('compact/start')
const compactEndIndex = manualTimeline.indexOf('compact/end')
const firstFlushIndex = manualTimeline.indexOf('flush')
const queuedTurnIndex = manualTimeline.indexOf('turn/start:message')
const queuedTurnIndex = manualTimeline.indexOf('turn/start')
const commandDoneIndex = manualTimeline.indexOf('command/done')
expect(manualTimeline.filter(item => item === 'command/run')).toHaveLength(1)
expect(manualTimeline.filter(item => item === 'command/done')).toHaveLength(1)