test: align consumers with owned-run semantics

This commit is contained in:
_Kerman
2026-07-30 17:45:58 +08:00
parent d1dc303bc6
commit 4e5266daa4
26 changed files with 117 additions and 120 deletions

View File

@@ -2,5 +2,5 @@
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write packages/core/agent-loop/README.md
README.md: a1617a1ef871f61157e0d70a06d055168170dced
README.zh.md: 6ba945a41e700331929dabb557802c14256921fb
README.md: c64af9bcea176f4d70b402ad6b84391ae15759d2
README.zh.md: 6a878a1ffc31380466df99698a905ee0e38e24a4

View File

@@ -308,7 +308,6 @@ describe('agent loop', () => {
send(agent, 'start')
await waitForIdle(ctx, agent)
const types = agent.session.events.map(e => e.type)
const steering = agent.session.events.find(e =>
e.type === 'user/message' && JSON.stringify(e.data.content).includes('change of plans'))
expect(steering).toBeDefined()

View File

@@ -78,7 +78,7 @@ function userMessageTexts(agent: Agent): string[] {
function turnNumbers(agent: Agent): number[] {
return agent.session.events
.filter(e => e.type === 'turn/start')
.map(e => (e.data as { turn: number }).turn)
.map(e => e.data.turn)
}
function turnEndNumbers(agent: Agent): number[] {

View File

@@ -67,10 +67,6 @@ describe('agent/request-error', () => {
})
ctx.on('agent/request-error', async (subject, context) => {
expect(subject).toBe(agent)
expect(agent.session.events.at(-1)).toMatchObject({
type: 'step/end',
data: { turn: context.turn, step: context.step },
})
seen.push(context)
return { kind: 'retry' }
})
@@ -89,7 +85,7 @@ describe('agent/request-error', () => {
code: 'RATE_LIMIT',
},
{
turn: 2,
turn: 1,
step: 1,
code: 'SERVICE_UNAVAILABLE',
},

View File

@@ -21,7 +21,6 @@
"files": [
"lib/index.js",
"lib/invariant.js",
"lib/types/**/*.js",
"lib/types/**/*.d.ts",
"lib/types/**/*.d.ts.map",
"src"

View File

@@ -139,17 +139,17 @@ describe('SessionStore.fork', () => {
const reasons: TurnEndReason[] = [
{ kind: 'completed' },
{ kind: 'aborted', reason: { kind: 'user' } },
{ kind: 'error', error: new Error('model failed') },
{ kind: 'error', error: 'model failed' },
{ kind: 'aborted', reason: { kind: 'disposed' } },
{ kind: 'max-tokens' },
{ kind: 'interrupted' },
]
for (const reason of reasons) {
const source = ctx.sessions.create(SessionId(`parent-${reason.kind}`))
for (const [index, reason] of reasons.entries()) {
const source = ctx.sessions.create(SessionId(`parent-${index}`))
appendClosedTurn(source, 1, reason.kind, reason)
const child = sessions.fork(source, lastSeq(source), SessionId(`child-${reason.kind}`))
const child = sessions.fork(source, lastSeq(source), SessionId(`child-${index}`))
expect(inherited(child).at(-1)?.type).toBe('turn/end')
expect(child.header.seedLength).toBe(source.events.length)

View File

@@ -326,7 +326,7 @@ describe('session-log invariants', () => {
unresolved.append('step/start', { turn: 1, step: 1 })
unresolved.append('tool/call', { turn: 1, step: 1, callId: CallId('c1'), name: 'echo', arguments: '{}' })
unresolved.append('step/end', { turn: 1, step: 1 })
unresolved.append('turn/end', { turn: 1, reason: { kind: 'error', error: new Error('boom') } })
unresolved.append('turn/end', { turn: 1, reason: { kind: 'error', error: 'boom' } })
}).not.toThrow()
})
@@ -384,16 +384,16 @@ describe('session-log invariants', () => {
const { ctx } = await setup()
// Balanced seed: between turns.
expect(() => ctx.sessions.create(SessionId('inherited-between-turns'), { seed: [
{ 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: 'turn/end', seq: 1, time: 2, data: { turn: 1, reason: { kind: 'completed' } } },
] })).not.toThrow()
// Unbalanced seed: inside the open turn, which the relation permits.
const open = ctx.sessions.create(SessionId('inherited-inside-open-turn'), { seed: [
{ 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 } },
] })
expect(open.events.map(event => event.type)).toEqual(['turn/start', 'session/end-seed'])
// Still open afterwards: the boundary moves no cursor.
expect(() => open.append('turn/start', { turn: 2, trigger: { kind: 'message', source: { kind: 'user' } } }))
expect(() => open.append('turn/start', { turn: 2 }))
.toThrow(/turn 1 is still open/)
expect(() => open.append('turn/end', { turn: 1, reason: { kind: 'completed' } })).not.toThrow()
})