fix(tools): make code result cards authoritative

This commit is contained in:
Tianyi Cui
2026-07-21 18:38:22 +08:00
parent f9b938a4a8
commit 449e3cf298
19 changed files with 1526 additions and 374 deletions

View File

@@ -146,7 +146,6 @@ export function createRunCodeTool(registry: ToolRegistry, requireRuntime: () =>
const parts = [value.logs.join('\n'), rendered].filter(part => part.length > 0)
return [{ type: 'text', text: parts.length > 0 ? parts.join('\n') : '(run_code completed with no output)' }]
},
presentationMeta: (_args, value) => ({ logs: value.logs }),
},
async execute(args, exec): Promise<RunCodeOutput> {
const runtime = requireRuntime()

View File

@@ -346,7 +346,7 @@ describe('the run_code dispatch bridge', () => {
{ parentCallId: 'call-1', subCallId: 'call-1:code:1', name: 'echo', arguments: { value: 'one' }, isError: false, resultSummary: 'echo:one' },
{ parentCallId: 'call-1', subCallId: 'call-1:code:2', name: 'echo', arguments: { value: 'two' }, isError: false, resultSummary: 'echo:two' },
])
expect(result.meta).toEqual({ logs: ['saw echo:one'] })
expect(result.meta).toBeUndefined()
})
it('exposes only an opaque parent token to nested result observers', async () => {
@@ -683,7 +683,6 @@ describe('the run_code dispatch bridge', () => {
['result only', 'returned', false],
['logs plus result', 'printed\nreturned', false],
['no output', '(run_code completed with no output)', false],
['failure', 'Error: code run failed (output-limit): outer output exceeded 8 bytes', true],
['spilled result', 'HEAD\n\n(Omitted 100 bytes. Full formatted result stored at: /tmp/run-code.txt.)\n\nTAIL', false],
] as const)('presents %s from the final post-policy content', async (_name, text, isError) => {
const { ctx } = await setup({ mode: 'code' })
@@ -700,6 +699,27 @@ describe('the run_code dispatch bridge', () => {
})).toEqual({ card: 'generic', content })
})
it('presents failure content produced by the canonical execution pipeline', async () => {
const { ctx, runtime } = await setup({ mode: 'code' })
runtime.behavior = () => Promise.resolve({
logs: ['captured before failure'],
error: { kind: 'output-limit', message: 'outer output exceeded 8 bytes' },
})
const result = await runCode(ctx, 'return 1')
const tool = ctx.tools.get(RUN_CODE_NAME)!
expect(result.isError).toBe(true)
expect(result.content).toEqual([{
type: 'text',
text: 'Error: code run failed (output-limit): outer output exceeded 8 bytes\nCaptured output:\ncaptured before failure',
}])
expect(tool.presentResult?.({ code: 'return 1' }, result)).toEqual({
card: 'generic',
content: result.content,
})
})
it('renders non-text sub-result blocks as placeholders and truncates long event summaries', async () => {
const { ctx, runtime } = await setup({ mode: 'code' })
const { agent, events } = fakeAgent()