Merge remote-tracking branch 'origin/codex/enforce-tool-cancellation' into worktree/explicit-turn-signal

# Conflicts:
#	docs/architecture.md
#	docs/cordis-catalog/events.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/cordis/tool-cordis/src/api-catalog.ts
#	packages/core/agent-loop/README.md
#	packages/core/agent-loop/src/loop.ts
#	packages/core/agent/README.md
#	packages/examples/cli-demo/src/cli.ts
#	packages/ui/tui/tests/tui.spec.ts
This commit is contained in:
Tianyi Cui
2026-07-21 00:02:17 +08:00
191 changed files with 5505 additions and 728 deletions

View File

@@ -16,6 +16,8 @@ import {
STRUCTURED_OUTPUT_TOOL,
} from '../src/structured.ts'
const testToolSignal = new AbortController().signal
type Script = ConstructorParameters<typeof MockAdapter>[0]
interface CodeRunRequestLike {
@@ -640,6 +642,7 @@ describe('in-process structured output', () => {
it('a structured_output call from an agent WITHOUT a structured run is UNKNOWN_TOOL (the tool does not exist for it)', async () => {
const { ctx, parent } = await setup([])
const result = await ctx.tools.execute({
signal: testToolSignal,
callId: 'x' as never,
name: STRUCTURED_OUTPUT_TOOL,
arguments: { answer: 1 },
@@ -652,6 +655,7 @@ describe('in-process structured output', () => {
it('a structured_output call with NO calling agent at all is UNKNOWN_TOOL', async () => {
const { ctx } = await setup([])
const result = await ctx.tools.execute({
signal: testToolSignal,
callId: 'x' as never,
name: STRUCTURED_OUTPUT_TOOL,
arguments: { answer: 1 },
@@ -684,6 +688,7 @@ describe('in-process structured output', () => {
// …and a LATER invalid call (its own body staged nothing) must not
// resurrect c1's discarded value: drive the pipeline directly.
const invalid = await ctx.tools.execute({
signal: testToolSignal,
callId: 'c2' as never,
name: STRUCTURED_OUTPUT_TOOL,
arguments: { answer: 'not-a-number' },
@@ -692,6 +697,7 @@ describe('in-process structured output', () => {
expect(invalid.isError).toBe(true)
// A fresh valid call still captures ITS OWN value.
const valid = await ctx.tools.execute({
signal: testToolSignal,
callId: 'c3' as never,
name: STRUCTURED_OUTPUT_TOOL,
arguments: { answer: 9 },
@@ -722,6 +728,7 @@ describe('in-process structured output', () => {
// (invalid args throw before the stage): the discarded value must not ride
// its acceptance.
const reused = await ctx.tools.execute({
signal: testToolSignal,
callId: 'c1' as never,
name: STRUCTURED_OUTPUT_TOOL,
arguments: { answer: 'not-a-number' },
@@ -730,6 +737,7 @@ describe('in-process structured output', () => {
expect(reused.isError).toBe(true)
// Nothing was ever committed: a fresh valid call is still required.
const valid = await ctx.tools.execute({
signal: testToolSignal,
callId: 'c1' as never,
name: STRUCTURED_OUTPUT_TOOL,
arguments: { answer: 5 },
@@ -764,6 +772,7 @@ describe('in-process structured output', () => {
return undefined as never
}, { prepend: true })
const denied = await ctx.tools.execute({
signal: testToolSignal,
callId: 'c1' as never,
name: STRUCTURED_OUTPUT_TOOL,
arguments: { answer: 2 },
@@ -774,6 +783,7 @@ describe('in-process structured output', () => {
// The discarded value was never promoted: a fresh valid call is required
// (and succeeds, proving the runtime is not wedged).
const valid = await ctx.tools.execute({
signal: testToolSignal,
callId: 'c1' as never,
name: STRUCTURED_OUTPUT_TOOL,
arguments: { answer: 5 },