Merge remote-tracking branch 'origin/master' into feat/send-unify

# Conflicts:
#	examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl
#	examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/stdout.expected.jsonl
#	packages/cordis/tool-cordis/src/api-catalog.ts
#	packages/pty/pty-local/tests/index.spec.ts
#	packages/session-query/session-query/tests/tracing.spec.ts
This commit is contained in:
Turtle
2026-07-23 22:41:45 +08:00
333 changed files with 10751 additions and 907 deletions

View File

@@ -47,6 +47,7 @@ interface Scenario {
expectedEventCounts?: Record<string, number>
childSessions?: number
enterPlanMode?: boolean
leavePlanModeAfterFirstTurn?: boolean
recorded: boolean
seedWorkspace?: boolean
/**
@@ -62,8 +63,9 @@ const SCENARIOS: Scenario[] = [
name: 'multi-turn-conversation',
composition: 'native',
expectedTools: [],
expectedEventCounts: { 'plan/mode': 1 },
expectedEventCounts: { 'plan/mode': 2 },
enterPlanMode: true,
leavePlanModeAfterFirstTurn: true,
recorded: true,
},
{
@@ -294,6 +296,12 @@ async function runScenario(scenario: Scenario): Promise<ScenarioResult> {
remainingPrompts = prompts.slice(1)
}
if (scenario.leavePlanModeAfterFirstTurn === true) {
terminal.send('/plan off')
terminal.send('\r')
await settleTerminal(terminal)
}
for (const prompt of remainingPrompts) {
terminal.send(prompt)
terminal.send('\r')
@@ -310,7 +318,9 @@ async function runScenario(scenario: Scenario): Promise<ScenarioResult> {
expect(events.filter(event => event.type === type), `${scenario.name} must emit ${type}`).toHaveLength(count)
}
if (scenario.enterPlanMode === true) {
expect(ctx.planMode.get(agent)).toEqual({ active: true })
expect(ctx.planMode.get(agent)).toEqual({
active: scenario.leavePlanModeAfterFirstTurn !== true,
})
const planMode = events.find(event => event.type === 'plan/mode')
if (planMode === undefined || firstHeader === undefined) {
throw new Error('plan-mode command snapshot needs plan/mode before its first request/header')
@@ -320,6 +330,20 @@ async function runScenario(scenario: Scenario): Promise<ScenarioResult> {
const firstMessage = events.find(event => event.type === 'user/message')
expect(firstMessage?.data.content).toEqual([{ type: 'text', text: prompts[0] }])
}
if (scenario.leavePlanModeAfterFirstTurn === true) {
const planModes = events.filter(event => event.type === 'plan/mode')
expect(planModes.map(event => event.data.active)).toEqual([true, false])
const headers = events.filter(event => event.type === 'request/header')
const exit = planModes[1]
const afterExit = headers[1]
if (exit === undefined || afterExit === undefined) {
throw new Error('active plan exit snapshot needs a committed exit and changed request header')
}
expect(exit.seq).toBeLessThan(afterExit.seq)
expect(afterExit.data.header.system).not.toContain('Snapshot plan mode instructions.')
expect(events.filter(event => event.type === 'user/message' && event.data.source.kind === 'plugin').map(event => (event.data as { content: unknown }).content))
.toContainEqual([{ type: 'text', text: 'The user switched this session back to the default mode.' }])
}
expect(events.filter(event => event.type === 'tool/result').every(event => !event.data.isError)).toBe(true)
expect(events.filter(event => event.type === 'turn/end').every(event => event.data.reason.kind !== 'error')).toBe(true)
if (scenario.name === 'dynamic-workflow' || scenario.name === 'cordis-dynamic-toolchain') {