refactor(agent): complete inbox lifecycle migration

This commit is contained in:
_Kerman
2026-08-03 12:25:33 +08:00
parent dc1d542092
commit 49e90695cc
214 changed files with 6019 additions and 4235 deletions

View File

@@ -62,12 +62,12 @@ buffer
style 0-17 fg=bright-magenta bold
31| "Enter send • Shift/Alt+Enter newline • Up/Down prompt history "
style 0-60 dim
32| "Esc cancel turn • Ctrl+O cycle cards (collapse/expand/hide) • Ctrl+R toggle reasoning • Ctrl+L "
32| "Esc cancel active work • Ctrl+O cycle cards (collapse/expand/hide) • Ctrl+R toggle reasoning • "
style 0-99 dim
33| "redraw "
style 0-5 dim
34| "Ctrl+C cancel while running; clear input or exit while idle • Ctrl+D exit "
style 0-72 dim
33| "Ctrl+L redraw "
style 0-12 dim
34| "Ctrl+C cancel active work; clear input or exit while idle • Ctrl+D exit "
style 0-70 dim
35| " "
36| "/clear — Clear the transcript view (session history is unchanged) "
style 0-64 dim
@@ -92,20 +92,20 @@ buffer
46| "/skill:<name> [instructions] — load a skill into the conversation "
style 0-64 dim
47| <blank>
48| "Context · snapshot-injector"
style 0-26 dim
49| "Injected while compaction was running. "
style 0-37 dim
50| <blank>
51| "… earlier context was compacted … "
48| "… earlier context was compacted … "
style 0-32 dim
52| <blank>
53| "You "
style 0-2 fg=bright-magenta bold underline
54| "Reply with exactly the word: TWO. No tools. "
55| <blank>
56| "Compacted 2 history items (~387 tokens). "
49| <blank>
50| "Compacted 2 history items (~387 tokens). "
style 0-39 dim
51| <blank>
52| "Context · snapshot-injector"
style 0-26 dim
53| "Injected while compaction was running. "
style 0-37 dim
54| <blank>
55| "You "
style 0-2 fg=bright-magenta bold underline
56| "Reply with exactly the word: TWO. No tools. "
57| <blank>
58| "Assistant "
style 0-8 fg=bright-magenta bold underline

View File

@@ -613,7 +613,14 @@ 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], `claimed:${inbox[0]?.slice('inserted:'.length) ?? ''}`])
const first = inbox[0]?.slice('inserted:'.length)
const second = inbox[1]?.slice('inserted:'.length)
expect(inbox).toEqual([
`inserted:${first}`,
`inserted:${second}`,
`claimed:${second}`,
`claimed:${first}`,
])
}
const events: SessionEvent[] = [...agent.session.events]
@@ -660,23 +667,28 @@ async function runScenario(scenario: Scenario): Promise<ScenarioResult> {
const compactSummary = events.find(event => event.type === 'compact/summary')
const compactCheckpoint = events.find(event => event.type === 'user/message'
&& event.data.source.kind === 'plugin' && event.data.source.plugin === 'compact')
const injectedEvent = events.find(event => event.type === 'user/message'
const queuedInjection = events.find(event => event.type === 'agent/inbox/spliced'
&& event.data.inserted?.some(message => message.source.kind === 'plugin'
&& message.source.plugin === 'snapshot-injector'))
const admittedInjection = events.find(event => event.type === 'user/message'
&& event.data.source.kind === 'plugin' && event.data.source.plugin === 'snapshot-injector')
const compactEnd = events.find(event => event.type === 'compact/end')
expect(compactStart?.data.turn).toBeNull()
expect(compactEnd?.data.turn).toBeNull()
expect(events.filter(event => event.type === 'compact/summary')).toHaveLength(1)
if (compactStart === undefined || compactSummary === undefined
|| compactCheckpoint === undefined || injectedEvent === undefined
|| compactCheckpoint === undefined || queuedInjection === undefined
|| admittedInjection === undefined
|| compactEnd === undefined) {
throw new Error('manual compaction snapshot is missing its durable marker, summary, checkpoint, or injection')
}
// The markers are time points, not an exclusive container: unrelated
// idle injection is allowed between them while the selected span stays stable.
expect(compactStart.seq).toBeLessThan(injectedEvent.seq)
expect(injectedEvent.seq).toBeLessThan(compactSummary.seq)
// Injection commits to the inbox during maintenance, then becomes
// model-visible only after the standalone compaction closes.
expect(compactStart.seq).toBeLessThan(queuedInjection.seq)
expect(queuedInjection.seq).toBeLessThan(compactSummary.seq)
expect(compactSummary.seq).toBeLessThan(compactCheckpoint.seq)
expect(compactCheckpoint.seq).toBeLessThan(compactEnd.seq)
expect(compactEnd.seq).toBeLessThan(admittedInjection.seq)
const manualTimeline = manualOrder ?? []
const commandRunIndex = manualTimeline.indexOf('command/run')
@@ -732,7 +744,7 @@ async function runScenario(scenario: Scenario): Promise<ScenarioResult> {
expect(derived).not.toContain('/compact')
expect(derived).not.toContain('Compacted 2 history items (~387 tokens).')
expect(derived.filter(text => text.includes('Injected while compaction was running.'))).toHaveLength(1)
expect(compactSummary.data.shadowedSeqs).not.toContain(injectedEvent.seq)
expect(compactSummary.data.shadowedSeqs).not.toContain(admittedInjection.seq)
const queuedTurn = events.findLast(event => event.type === 'turn/start')
expect(queuedTurn !== undefined && compactEnd.seq < queuedTurn.seq).toBe(true)
}