Merge branch 'codex/tool-json-schema-dsl' into codex/canonical-tool-output
# Conflicts: # .agents/notes/implemented/feature/2026-06-30-interception-seams.md # docs/config-catalog.md # docs/cookbook/adding-a-tool.i18n.yaml # docs/cookbook/adding-a-tool.md # docs/cookbook/adding-a-tool.zh.md # docs/cordis-catalog/events.md # docs/cordis-catalog/services.md # docs/core-data-structures/tools.md # docs/event-producer-consumer.md # docs/persistence-catalog.md # examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/session.jsonl # examples/acp-agent/tests/snapshots/cordis-inspect-jsdoc/stdout.expected.jsonl # packages/bash/tool-bash/src/index.ts # packages/core/agent-loop/src/tool-calls.ts # packages/core/agent-loop/tests/cancel.spec.ts # packages/core/agent-loop/tests/contract-regressions.spec.ts # packages/core/agent-loop/tests/tool-calls.spec.ts # packages/core/tools/README.md # packages/core/tools/src/index.ts # packages/core/tools/tests/code-mode.spec.ts # packages/core/tools/tests/tools.spec.ts # packages/fs/tool-fs-search/tests/integration.spec.ts # packages/fs/tool-fs-search/tests/tools.spec.ts # packages/fs/tool-fs/tests/integration.spec.ts # packages/mcp/mcp-client/src/tools.ts # packages/timeout/timeout-policy/tests/timeout-policy.spec.ts # packages/web/tool-web/tests/integration.spec.ts # packages/web/tool-web/tests/tool-web.spec.ts
This commit is contained in:
@@ -13,6 +13,8 @@ import ToolRegistry from '@deepseek-ai/dsh-tools'
|
||||
import type { ToolExecutionResult } from '@deepseek-ai/dsh-tools'
|
||||
import * as toolGoal from '@deepseek-ai/dsh-tool-goal'
|
||||
|
||||
const testToolSignal = new AbortController().signal
|
||||
|
||||
interface StubAgent {
|
||||
readonly agent: Agent
|
||||
readonly session: Session
|
||||
@@ -84,6 +86,7 @@ async function execute(
|
||||
initiator: Agent | undefined = agent,
|
||||
): Promise<ToolExecutionResult> {
|
||||
const run = () => ctx.tools.execute({
|
||||
signal: testToolSignal,
|
||||
callId: CallId(`call-${Math.random()}`),
|
||||
name,
|
||||
arguments: args,
|
||||
@@ -116,7 +119,7 @@ describe('goal tool registration and presentation', () => {
|
||||
expect(['create_goal', 'get_goal', 'update_goal'].map(name => ctx.tools.get(name)?.name))
|
||||
.toEqual(['create_goal', 'get_goal', 'update_goal'])
|
||||
for (const name of ['create_goal', 'get_goal', 'update_goal']) {
|
||||
expect(ctx.tools.executionMode({ callId: CallId(name), name, arguments: {} }))
|
||||
expect(ctx.tools.executionMode({ signal: testToolSignal, callId: CallId(name), name, arguments: {} }))
|
||||
.toEqual({ kind: 'exclusive' })
|
||||
}
|
||||
const section = (await ctx.systemPrompt.assemble()).sections.find(item => item.name === 'tool:goal')
|
||||
@@ -200,6 +203,7 @@ describe('goal tool execution authority', () => {
|
||||
|
||||
openTurn(root, { kind: 'user' })
|
||||
const driverless = await ctx.tools.execute({
|
||||
signal: testToolSignal,
|
||||
callId: CallId('call-driverless'),
|
||||
name: 'get_goal',
|
||||
arguments: {},
|
||||
@@ -329,7 +333,7 @@ describe('goal tool state transitions', () => {
|
||||
goal_id: goal['id'], revision: goal['revision'], action: 'resume',
|
||||
}, root.agent))
|
||||
expect(goal).toMatchObject({ phase: 'active', revision: 4 })
|
||||
expect(await agentEvents(ctx, root.agent).serial('agent/turn-stop', 1)).toBeUndefined()
|
||||
expect(await agentEvents(ctx, root.agent).serial('agent/turn-stop', 1, testToolSignal)).toBeUndefined()
|
||||
})
|
||||
|
||||
it('terminal-stops an autonomous completion but leaves a human pause interactive', async () => {
|
||||
@@ -340,7 +344,7 @@ describe('goal tool state transitions', () => {
|
||||
goal_id: created.id, revision: created.revision, action: 'pause',
|
||||
}, root.agent)
|
||||
expect(resultGoal(paused)).toMatchObject({ phase: 'paused' })
|
||||
expect(await agentEvents(ctx, root.agent).serial('agent/turn-stop', humanTurn)).toBeUndefined()
|
||||
expect(await agentEvents(ctx, root.agent).serial('agent/turn-stop', humanTurn, testToolSignal)).toBeUndefined()
|
||||
const resumed = resultGoal(await execute(ctx, 'update_goal', {
|
||||
goal_id: created.id, revision: 2, action: 'resume',
|
||||
}, root.agent))
|
||||
@@ -353,8 +357,8 @@ describe('goal tool state transitions', () => {
|
||||
goal_id: created.id, revision: resumed['revision'], action: 'complete',
|
||||
}, root.agent)
|
||||
expect(resultGoal(complete)).toMatchObject({ phase: 'complete' })
|
||||
expect(await agentEvents(ctx, root.agent).serial('agent/turn-stop', roundTurn)).toEqual({ action: 'stop' })
|
||||
expect(await agentEvents(ctx, root.agent).serial('agent/turn-stop', roundTurn)).toBeUndefined()
|
||||
expect(await agentEvents(ctx, root.agent).serial('agent/turn-stop', roundTurn, testToolSignal)).toEqual({ action: 'stop' })
|
||||
expect(await agentEvents(ctx, root.agent).serial('agent/turn-stop', roundTurn, testToolSignal)).toBeUndefined()
|
||||
})
|
||||
|
||||
it('rearms a restored active goal only after a new direct human prompt', async () => {
|
||||
|
||||
Reference in New Issue
Block a user