refactor(agent-loop): simplify message machine

This commit is contained in:
_Kerman
2026-07-30 13:49:57 +08:00
parent d554ae3019
commit f2e20c1ef0
212 changed files with 1326 additions and 2382 deletions
+10 -10
View File
@@ -19,7 +19,7 @@ import {
/** Build a minimal session with turn boundaries and a single user message. */
function surfaceSession(): Session {
const s = new Session(SessionId('ss'))
s.append('turn/start', { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } })
s.append('turn/start', { turn: 1 })
s.append('user/message', createUserMessage({
content: [{ type: 'text', text: 'hello' }], source: { kind: 'user' },
}), { surfaceOp: 'append' })
@@ -93,7 +93,7 @@ describe('foldSurface provenance', () => {
type: 'turn/start',
seq: 0,
time: 1,
data: { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } },
data: { turn: 1 },
sourceEventSeqs: [0],
} as unknown as SessionEvent
expect(() => foldSurface([event])).toThrow(/cannot carry sourceEventSeqs/)
@@ -378,7 +378,7 @@ describe('SurfaceManager', () => {
type: 'turn/start',
seq: 0,
time: 1,
data: { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } },
data: { turn: 1 },
surfaceOp: 'append',
} as unknown as SessionEvent
@@ -396,7 +396,7 @@ describe('SurfaceManager', () => {
it('empty surface yields empty nodes', () => {
const s = new Session(SessionId('empty'))
s.append('turn/start', { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } })
s.append('turn/start', { turn: 1 })
s.append('step/start', { turn: 1, step: 1 })
s.append('step/end', { turn: 1, step: 1 })
s.append('turn/end', { turn: 1, reason: { kind: 'completed' } })
@@ -665,7 +665,7 @@ describe('deriveMessages with surface', () => {
it('surface path skips non-surface events (chunks, boundaries)', () => {
const s = new Session(SessionId('filter'))
s.append('turn/start', { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } })
s.append('turn/start', { turn: 1 })
s.append('assistant/chunk', { turn: 1, step: 1, chunk: { type: 'text-delta', index: 0, text: 'h' } })
s.append('assistant/chunk', { turn: 1, step: 1, chunk: { type: 'text-delta', index: 1, text: 'i' } })
s.append('user/message', createUserMessage({
@@ -731,7 +731,7 @@ describe('deriveMessages with surface', () => {
describe('Session.append surface opts', () => {
it('records sourceEventSeqs and surfaceOp on the event', () => {
const s = new Session(SessionId('opts'))
s.append('turn/start', { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } })
s.append('turn/start', { turn: 1 })
s.append('step/start', { turn: 1, step: 1 })
const event = s.append('assistant/message',
{
@@ -759,7 +759,7 @@ describe('Session.append surface opts', () => {
// but _deriveOneMessage returns null for it, so the surface derivation path's
// null-check is exercised — the node is on the surface yet produces no message.
const seed: SessionEvent[] = [
{ type: 'turn/start', seq: 0, time: 1, data: { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } } },
{ type: 'turn/start', seq: 0, time: 1, data: { turn: 1 } },
{ type: 'step/start', seq: 1, time: 2, data: { turn: 1, step: 1 } },
{ type: 'assistant/message', seq: 2, time: 3, data: {
turn: 1, step: 1,
@@ -782,7 +782,7 @@ describe('Session.append surface opts', () => {
it('a non-surface event carries no surface fields', () => {
const s = new Session(SessionId('noopts'))
s.append('turn/start', { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } })
s.append('turn/start', { turn: 1 })
expect((s.events[0] as SessionEvent<SurfaceEventType>).sourceEventSeqs).toBeUndefined()
expect((s.events[0] as SessionEvent<SurfaceEventType>).surfaceOp).toBeUndefined()
})
@@ -816,7 +816,7 @@ describe('Session.append surface opts', () => {
}
expect(isSurfaceEvent(noMarker)).toBe(false)
// A non-surface type is rejected too (the type gate).
const boundary: SessionEvent = { type: 'turn/start', seq: 1, time: 1, data: { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } } }
const boundary: SessionEvent = { type: 'turn/start', seq: 1, time: 1, data: { turn: 1 } }
expect(isSurfaceEvent(boundary)).toBe(false)
// A properly-marked surface event narrows.
const marked = { ...noMarker, surfaceOp: 'append' } as SurfaceEvent
@@ -866,7 +866,7 @@ describe('surface type guards', () => {
describe('SurfaceManager.replaceGeneration', () => {
it('folds the pending log delta on access and counts replaces', () => {
const s = new Session(SessionId('gen'))
s.append('turn/start', { turn: 1, trigger: { kind: 'message', source: { kind: 'user' } } })
s.append('turn/start', { turn: 1 })
s.append('user/message', createUserMessage({
content: [{ type: 'text', text: 'one' }], source: { kind: 'user' },
}), { surfaceOp: 'append' })