Merge origin/master into worktree/schedule-conversational-after

# Conflicts:
#	docs/event-producer-consumer.i18n.yaml
#	docs/event-producer-consumer.md
#	docs/event-producer-consumer.zh.md
This commit is contained in:
Tianyi Cui
2026-08-09 21:07:50 +08:00
267 changed files with 12096 additions and 4837 deletions

View File

@@ -785,11 +785,11 @@ describe('the run_code dispatch bridge', () => {
const dispatches = events.filter(event => event.type === 'tool/code-dispatch')
expect(dispatches.map(event => event.data)).toEqual([
{
parentCallId: 'call-1', subCallId: 'call-1:code:1', name: 'echo',
rootCallId: 'call-1', parentCallId: 'call-1', subCallId: 'call-1:code:1', name: 'echo',
arguments: { value: 'one' }, isError: false, content: [{ type: 'text', text: 'echo:one' }],
},
{
parentCallId: 'call-1', subCallId: 'call-1:code:2', name: 'echo',
rootCallId: 'call-1', parentCallId: 'call-1', subCallId: 'call-1:code:2', name: 'echo',
arguments: { value: 'two' }, isError: false, content: [{ type: 'text', text: 'echo:two' }],
},
])
@@ -1526,6 +1526,7 @@ describe('the run_code dispatch bridge', () => {
content: [{ type: 'text', text: 'hi' }], source: { kind: 'user' },
}), { surfaceOp: 'append' })
session.append('tool/code-dispatch', {
rootCallId: CallId('p1'),
parentCallId: CallId('p1'),
subCallId: CallId('p1:code:1'),
name: 'echo',

View File

@@ -2,7 +2,7 @@ import { describe, expect, it } from 'vitest'
import { Context } from 'cordis'
import { scopeTarget } from '@deepseek-ai/dsh-scope'
import { CallId } from '@deepseek-ai/dsh-llm'
import SessionStore from '@deepseek-ai/dsh-session'
import SessionStore, { Session, SessionId } from '@deepseek-ai/dsh-session'
import type { ToolExecution, ToolExecutionResult, ToolExecutionToken } from '@deepseek-ai/dsh-tools'
import * as ToolsInvariant from '@deepseek-ai/dsh-tools/invariant'
import InvariantService from '@deepseek-ai/dsh-invariants'
@@ -24,6 +24,7 @@ const execution = (overrides: Partial<ToolExecution> = {}): ToolExecution => ({
arguments: Object.freeze({ text: 'hi' }),
...overrides,
signal: overrides.signal ?? testToolSignal,
rootCallId: overrides.rootCallId ?? overrides.callId ?? CallId('call-1'),
})
const outcome = (): ToolExecutionResult => Object.freeze({
@@ -92,6 +93,7 @@ describe('tool-pipeline invariants', () => {
const ctx = await setup()
const session = ctx.sessions.create()
const data = {
rootCallId: CallId('parent'),
parentCallId: CallId('parent'),
subCallId: CallId('child'),
name: 'echo',
@@ -103,12 +105,112 @@ describe('tool-pipeline invariants', () => {
session.append('turn/end', { turn: 1, reason: { kind: 'completed' } })
})
it('does not commit a rejected dispatch edge into the root index', async () => {
const ctx = await setup()
const session = ctx.sessions.create()
expect(() => session.append('tool/code-dispatch-start', {
rootCallId: CallId('rejected-root'),
parentCallId: CallId('rejected-root'),
subCallId: CallId('reused-child'),
name: 'echo',
arguments: {},
})).toThrow(/outside any open turn/)
session.append('turn/start', { turn: 1 })
expect(() => session.append('tool/code-dispatch-start', {
rootCallId: CallId('accepted-root'),
parentCallId: CallId('accepted-root'),
subCallId: CallId('reused-child'),
name: 'echo',
arguments: {},
})).not.toThrow()
})
it('rejects a nested code dispatch that changes its parent chain root before append', async () => {
const ctx = await setup()
const session = ctx.sessions.create()
session.append('turn/start', { turn: 1 })
session.append('tool/code-dispatch-start', {
rootCallId: CallId('root'),
parentCallId: CallId('root'),
subCallId: CallId('child'),
name: 'run_code',
arguments: {},
})
session.append('tool/code-dispatch-start', {
rootCallId: CallId('root'),
parentCallId: CallId('child'),
subCallId: CallId('grandchild'),
name: 'echo',
arguments: {},
})
expect(() => session.append('tool/code-dispatch-start', {
rootCallId: CallId('another-root'),
parentCallId: CallId('child'),
subCallId: CallId('invalid-grandchild'),
name: 'echo',
arguments: {},
})).toThrow(/parentCallId child does not belong to rootCallId another-root/)
expect(session.events.some(event => event.type === 'tool/code-dispatch-start'
&& String(event.data.subCallId) === 'invalid-grandchild')).toBe(false)
})
it('requires non-empty dispatch identities and keeps one subcall on one root', async () => {
const ctx = await setup()
const session = ctx.sessions.create()
session.append('turn/start', { turn: 1 })
expect(() => session.append('tool/code-dispatch-start', {
rootCallId: CallId(''),
parentCallId: CallId('root'),
subCallId: CallId('child'),
name: 'echo',
arguments: {},
})).toThrow(/must carry non-empty rootCallId/)
session.append('tool/code-dispatch-start', {
rootCallId: CallId('root'),
parentCallId: CallId('root'),
subCallId: CallId('child'),
name: 'echo',
arguments: {},
})
expect(() => session.append('tool/code-dispatch-start', {
rootCallId: CallId('other-root'),
parentCallId: CallId('other-root'),
subCallId: CallId('child'),
name: 'echo',
arguments: {},
})).toThrow(/changed rootCallId for subCallId child/)
})
it('indexes dispatch records emitted for a bare session', async () => {
const ctx = await setup()
const session = Session.create(SessionId('bare-dispatch-session'))
session.append('turn/start', { turn: 1 })
expect(() => {
ctx.emit('session/event', session as never, {
type: 'tool/code-dispatch-start',
seq: 1,
time: 1,
data: {
rootCallId: CallId('root'),
parentCallId: CallId('root'),
subCallId: CallId('child'),
name: 'echo',
arguments: {},
},
} as never)
}).not.toThrow()
})
it('replays enclosed code-dispatch records on late registration', async () => {
const ctx = new Context()
await ctx.plugin(SessionStore)
const session = ctx.sessions.create()
session.append('turn/start', { turn: 1 })
session.append('tool/code-dispatch', {
rootCallId: CallId('parent'),
parentCallId: CallId('parent'),
subCallId: CallId('child'),
name: 'echo',
@@ -125,6 +227,7 @@ describe('tool-pipeline invariants', () => {
const ctx = new Context()
await ctx.plugin(SessionStore)
ctx.sessions.create().append('tool/code-dispatch-start', {
rootCallId: CallId('parent'),
parentCallId: CallId('parent'),
subCallId: CallId('child'),
name: 'echo',