refactor(agent): unify agent-scoped event signatures as payload objects

All agent/* and agent-loop/config-start-failed events take one payload
object carrying the agent subject; waterfall/serial payloads require a
signal and keep next as the final argument. PreStepContext and
RequestFailureContext are unfolded into payloads and retired.
goal/changed follows the same shape so agentEvents keeps its listener
error containment. ReactLoopAgent builds its scope carrier once in the
constructor. Regenerates scope resolvers, tool-cordis api catalog, and
docs catalogs; updates all affected listeners, tests, and the
core-data-structures docs (en + zh).
This commit is contained in:
_Kerman
2026-08-06 12:13:14 +08:00
parent bb53e25ed0
commit ccebba2349
91 changed files with 574 additions and 618 deletions

View File

@@ -8,20 +8,20 @@
type ScopedSubjectResolver = (args: readonly unknown[]) => unknown
const scopedSubjectResolvers: Readonly<Record<string, ScopedSubjectResolver | null>> = Object.freeze({
'agent/created': args => args[0],
'agent/disposed': args => args[0],
'agent/error': args => args[0],
'agent/inbox/claimed': args => args[0],
'agent/inbox/discarded': args => args[0],
'agent/inbox/inserted': args => args[0],
'agent/pre-step': args => args[0],
'agent/request': args => args[0],
'agent/request-error': args => args[0],
'agent/session-start': args => args[0],
'agent/status': args => args[0],
'agent/turn-stopping': args => args[0],
'agent/created': args => (args[0] as Record<string, unknown>)['agent'],
'agent/disposed': args => (args[0] as Record<string, unknown>)['agent'],
'agent/error': args => (args[0] as Record<string, unknown>)['agent'],
'agent/inbox/claimed': args => (args[0] as Record<string, unknown>)['agent'],
'agent/inbox/discarded': args => (args[0] as Record<string, unknown>)['agent'],
'agent/inbox/inserted': args => (args[0] as Record<string, unknown>)['agent'],
'agent/pre-step': args => (args[0] as Record<string, unknown>)['agent'],
'agent/request': args => (args[0] as Record<string, unknown>)['agent'],
'agent/request-error': args => (args[0] as Record<string, unknown>)['agent'],
'agent/session-start': args => (args[0] as Record<string, unknown>)['agent'],
'agent/status': args => (args[0] as Record<string, unknown>)['agent'],
'agent/turn-stopping': args => (args[0] as Record<string, unknown>)['agent'],
'approval/request': args => (args[0] as Record<string, unknown>)['agent'],
'goal/changed': args => args[0],
'goal/changed': args => (args[0] as Record<string, unknown>)['agent'],
'session/created': null,
'session/disposed': null,
'session/event': null,

View File

@@ -28,7 +28,7 @@ describe('scoped-dispatch invariants', () => {
const ctx = await setup()
expect(() => { emit(ctx, undefined, 'ordinary/event', []) }).not.toThrow()
const agent = { id: 'a1' }
expect(() => { emit(ctx, undefined, 'agent/error', [agent, 1, 0, new Error('x')]) })
expect(() => { emit(ctx, undefined, 'agent/error', [{ agent, turn: 1, step: 0, error: new Error('x') }]) })
.toThrow(/dispatched without a scope carrier/)
})
@@ -45,34 +45,34 @@ describe('scoped-dispatch invariants', () => {
source: { kind: 'user' },
})
const agentRows = {
'agent/created': [agent],
'agent/disposed': [agent],
'agent/status': [agent, 'idle'],
'agent/inbox/inserted': [agent, { message }],
'agent/inbox/claimed': [agent, { message, turn: 1 }],
'agent/inbox/discarded': [agent, { message }],
'agent/session-start': [agent, 'startup'],
'agent/pre-step': [agent, [message], { turn: 1, step: 1, signal }, () => Promise.resolve({ kind: 'enter', messages: [message] })],
'agent/request': [agent, 1, 1, signal, () => Promise.resolve(config)],
'agent/created': [{ agent }],
'agent/disposed': [{ agent }],
'agent/status': [{ agent, status: 'idle' }],
'agent/inbox/inserted': [{ agent, message }],
'agent/inbox/claimed': [{ agent, message, turn: 1 }],
'agent/inbox/discarded': [{ agent, message }],
'agent/session-start': [{ agent, source: 'startup' }],
'agent/pre-step': [{ agent, messages: [message], turn: 1, step: 1, signal }, () => Promise.resolve({ kind: 'enter', messages: [message] })],
'agent/request': [{ agent, turn: 1, step: 1, signal }, () => Promise.resolve(config)],
'agent/request-error': [
agent,
{
agent,
turn: 1,
step: 1,
provider: 'p',
failure: { message: 'request', code: 'UNKNOWN' },
retryPolicy: undefined,
signal,
},
signal,
() => Promise.resolve(undefined),
],
'agent/turn-stopping': [agent, 1, signal],
'agent/error': [agent, 1, 0, new Error('x')],
'agent/turn-stopping': [{ agent, turn: 1, signal }],
'agent/error': [{ agent, turn: 1, step: 0, error: new Error('x') }],
} satisfies { [K in AgentEventName]: EventArgs<K> }
const rows: Array<[string, unknown[]]> = [
...Object.entries(agentRows),
['approval/request', [{ agent, toolName: 'echo' }, () => Promise.resolve('unavailable')]],
['goal/changed', [agent, { operation: 'create', ref: { id: 'goal-a', revision: 1 } }]],
['goal/changed', [{ agent, change: { operation: 'create', ref: { id: 'goal-a', revision: 1 } } }]],
['system-prompt/assemble', [[], { scope: agent }]],
['tools/code-dispatch-log', [{ exec: { callId: 'c', name: 't', arguments: {} }, agent, subCallId: 'c:code:1', name: 't', isError: false, content: [] }, () => Promise.resolve([])]],
['tools/execute', [{ callId: 'c', name: 't', arguments: {}, agent }, () => Promise.resolve({ content: [], isError: false })]],