mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
Merge pull request #2428 from deepseek-harness/fix/run-code-description-contract
让 run_code 的模型面说明点名必填的 description 参数
This commit is contained in:
@@ -2,5 +2,5 @@
|
|||||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||||
# after editing either side, bring the other along and re-record with:
|
# after editing either side, bring the other along and re-record with:
|
||||||
# pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-06-15-code-mode.md
|
# pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-06-15-code-mode.md
|
||||||
2026-06-15-code-mode.md: bc019c0b9acc6d834da41ceff2b1d1930fb34027
|
2026-06-15-code-mode.md: adabf80ab03bdae57bba84957cdacf648c16c2f6
|
||||||
2026-06-15-code-mode.zh.md: c19562b828089b6deeb048d30a08ce8681f150da
|
2026-06-15-code-mode.zh.md: 24d83b9f896a73b449852d28c3e0a376fb6ace5a
|
||||||
|
|||||||
@@ -87,6 +87,8 @@ The worker runtime provides containment, not a security boundary: model code can
|
|||||||
|
|
||||||
The SDK instructs the model to write an async body in the loaded runtime's language (an erasable-TypeScript body by default; a Python `async` body under a Python runtime — see the [language-dispatch note](2026-07-31-code-mode-language-dispatch.md)), call tools through `await tools.name(args)`, catch rejected tool calls when needed, and return or log only the output that should re-enter context. Both flavors state the same contract in their own primitive: independent read-only calls MAY overlap under `Promise.all` (TypeScript) or `asyncio.gather` (Python), mutating calls run alone in submission order, and dependent work sequences with `await`. The declaration prefix can be as large as native schemas, especially in `'both'`, but remains stable for provider caching.
|
The SDK instructs the model to write an async body in the loaded runtime's language (an erasable-TypeScript body by default; a Python `async` body under a Python runtime — see the [language-dispatch note](2026-07-31-code-mode-language-dispatch.md)), call tools through `await tools.name(args)`, catch rejected tool calls when needed, and return or log only the output that should re-enter context. Both flavors state the same contract in their own primitive: independent read-only calls MAY overlap under `Promise.all` (TypeScript) or `asyncio.gather` (Python), mutating calls run alone in submission order, and dependent work sequences with `await`. The declaration prefix can be as large as native schemas, especially in `'both'`, but remains stable for provider caching.
|
||||||
|
|
||||||
|
The transport's own `description` and both SDK instruction flavors open by naming `code` and `description` as the call's two required arguments. Prose that describes the call as passing a program leaves the second argument discoverable only through the parameter schema, and a model that emits `{code}` alone loses the whole written program to an `INVALID_ARGS` rejection.
|
||||||
|
|
||||||
## Consequences
|
## Consequences
|
||||||
|
|
||||||
Deployments switching to `'code'` must update any native-only `toolOrder`. Assembly listeners own the integrity of any rewritten protocol messages. Sub-dispatch starts in submission order under a bounded overlap pool, while per-call contexts retain their source, envelope, and metadata through the outer result.
|
Deployments switching to `'code'` must update any native-only `toolOrder`. Assembly listeners own the integrity of any rewritten protocol messages. Sub-dispatch starts in submission order under a bounded overlap pool, while per-call contexts retain their source, envelope, and metadata through the outer result.
|
||||||
|
|||||||
@@ -87,6 +87,8 @@ worker 运行时只能约束程序的运行,而不构成安全边界:模型
|
|||||||
|
|
||||||
SDK 指示模型编写一个所加载运行时语言的异步函数体(默认可擦除 TypeScript;Python 运行时下为 Python `async` 函数体——见[语言分发 note](2026-07-31-code-mode-language-dispatch.md)),通过 `await tools.name(args)` 调用工具,在需要时捕获被拒绝的工具调用,并仅 return 或 log 应重新进入上下文的输出。两种 flavor 用各自的原语陈述同一约定:相互独立的只读调用可以(MAY)在 `Promise.all`(TypeScript)或 `asyncio.gather`(Python)下重叠,有副作用的调用按提交顺序单独运行,有依赖的工作用 `await` 排序。声明前缀可能与原生 schema 一样大,尤其在 `'both'` 下,但对提供方缓存保持稳定。
|
SDK 指示模型编写一个所加载运行时语言的异步函数体(默认可擦除 TypeScript;Python 运行时下为 Python `async` 函数体——见[语言分发 note](2026-07-31-code-mode-language-dispatch.md)),通过 `await tools.name(args)` 调用工具,在需要时捕获被拒绝的工具调用,并仅 return 或 log 应重新进入上下文的输出。两种 flavor 用各自的原语陈述同一约定:相互独立的只读调用可以(MAY)在 `Promise.all`(TypeScript)或 `asyncio.gather`(Python)下重叠,有副作用的调用按提交顺序单独运行,有依赖的工作用 `await` 排序。声明前缀可能与原生 schema 一样大,尤其在 `'both'` 下,但对提供方缓存保持稳定。
|
||||||
|
|
||||||
|
传输自身的 `description` 与两种 flavor 的 SDK 说明都以点名 `code` 和 `description` 这两个必填参数开头。把该调用描述成「传入一个程序」的散文会让第二个参数只能从参数 schema 中发现,而只发出 `{code}` 的模型会因 `INVALID_ARGS` 被拒,连同已写好的整个程序一起丢失。
|
||||||
|
|
||||||
## 后果
|
## 后果
|
||||||
|
|
||||||
切换到 `'code'` 的部署必须更新任何仅限 native 的 `toolOrder`。组装监听器有责任维护任何被重写的协议消息的完整性。子分发在有界的重叠池下按提交顺序启动,而每次调用的上下文会通过外层结果保留其 source、信封与元数据。
|
切换到 `'code'` 的部署必须更新任何仅限 native 的 `toolOrder`。组装监听器有责任维护任何被重写的协议消息的完整性。子分发在有界的重叠池下按提交顺序启动,而每次调用的上下文会通过外层结果保留其 source、信封与元数据。
|
||||||
|
|||||||
@@ -2,5 +2,5 @@
|
|||||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||||
# after editing either side, bring the other along and re-record with:
|
# after editing either side, bring the other along and re-record with:
|
||||||
# pnpm run verify-translation-pairing --write docs/tool-catalog.md
|
# pnpm run verify-translation-pairing --write docs/tool-catalog.md
|
||||||
tool-catalog.md: ea89508500ec6e73e6e56c4e5d0ac2c35897b342
|
tool-catalog.md: 3d73ed1ef5346f620808e9d6b04299291ba1ed4c
|
||||||
tool-catalog.zh.md: 076cc63151e3b9ee8b3828ded65df9ebf09c9430
|
tool-catalog.zh.md: 90573928a24630e802d98441bc0e340baf582b23
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ ask_user_question pauses the tool call until the active UI provider returns a hu
|
|||||||
|
|
||||||
### `run_code`
|
### `run_code`
|
||||||
|
|
||||||
Execute a TypeScript program against the available tools. Write the BODY of an async function (erasable syntax only; top-level `await` and `return` work) and call tools as `await tools.name(args)` per the declarations in the system prompt. Only what you print or return comes back — curate it.
|
Execute a TypeScript program against the available tools. Takes two required arguments: `code`, the BODY of an async function (erasable syntax only; top-level `await` and `return` work), and `description`, a short summary of what the program does. Call tools as `await tools.name(args)` per the declarations in the system prompt. Only what you print or return comes back — curate it.
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -118,7 +118,7 @@ ask_user_question 会暂停工具调用,直到当前 UI 提供方返回人类
|
|||||||
|
|
||||||
### `run_code`
|
### `run_code`
|
||||||
|
|
||||||
针对可用工具执行 TypeScript 程序。请编写异步函数的**函数体**(仅使用可擦除语法;支持顶层 `await` 和 `return`),并根据系统提示词中的声明,以 `await tools.name(args)` 形式调用工具。只有打印或返回的内容会传回,请谨慎筛选。
|
针对可用工具执行 TypeScript 程序。接受两个必填参数:`code`,即异步函数的**函数体**(仅使用可擦除语法;支持顶层 `await` 和 `return`);以及 `description`,简要说明该程序做什么。请根据系统提示词中的声明,以 `await tools.name(args)` 形式调用工具。只有打印或返回的内容会传回,请谨慎筛选。
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ Use subagent in the background by default. Start independent delegations togethe
|
|||||||
|
|
||||||
## Writing code for run_code
|
## Writing code for run_code
|
||||||
|
|
||||||
Pass `run_code` the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped). Inside the program:
|
`run_code` takes two required arguments: `code` — the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped) — and `description`, a short summary of what the program does. Inside the program:
|
||||||
|
|
||||||
- Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON.
|
- Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON.
|
||||||
- A FAILED tool call rejects with `ToolCallError`, whose `toolName` identifies the failed tool and whose `message` is human-readable — `try/catch` it to handle and continue.
|
- A FAILED tool call rejects with `ToolCallError`, whose `toolName` identifies the failed tool and whose `message` is human-readable — `try/catch` it to handle and continue.
|
||||||
|
|||||||
@@ -443,7 +443,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "run_code",
|
"name": "run_code",
|
||||||
"description": "Execute a TypeScript program against the available tools. Write the BODY of an async function (erasable syntax only; top-level `await` and `return` work) and call tools as `await tools.name(args)` per the declarations in the system prompt. Only what you print or return comes back — curate it.",
|
"description": "Execute a TypeScript program against the available tools. Takes two required arguments: `code`, the BODY of an async function (erasable syntax only; top-level `await` and `return` work), and `description`, a short summary of what the program does. Call tools as `await tools.name(args)` per the declarations in the system prompt. Only what you print or return comes back — curate it.",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ Use subagent in the background by default. Start independent delegations togethe
|
|||||||
|
|
||||||
## Writing code for run_code
|
## Writing code for run_code
|
||||||
|
|
||||||
Pass `run_code` the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped). Inside the program:
|
`run_code` takes two required arguments: `code` — the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped) — and `description`, a short summary of what the program does. Inside the program:
|
||||||
|
|
||||||
- Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON.
|
- Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON.
|
||||||
- A FAILED tool call rejects with `ToolCallError`, whose `toolName` identifies the failed tool and whose `message` is human-readable — `try/catch` it to handle and continue.
|
- A FAILED tool call rejects with `ToolCallError`, whose `toolName` identifies the failed tool and whose `message` is human-readable — `try/catch` it to handle and continue.
|
||||||
|
|||||||
@@ -246,7 +246,7 @@
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "run_code",
|
"name": "run_code",
|
||||||
"description": "Execute a TypeScript program against the available tools. Write the BODY of an async function (erasable syntax only; top-level `await` and `return` work) and call tools as `await tools.name(args)` per the declarations in the system prompt. Only what you print or return comes back — curate it.",
|
"description": "Execute a TypeScript program against the available tools. Takes two required arguments: `code`, the BODY of an async function (erasable syntax only; top-level `await` and `return` work), and `description`, a short summary of what the program does. Call tools as `await tools.name(args)` per the declarations in the system prompt. Only what you print or return comes back — curate it.",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ Use subagent in the background by default. Start independent delegations togethe
|
|||||||
|
|
||||||
## Writing code for run_code
|
## Writing code for run_code
|
||||||
|
|
||||||
Pass `run_code` the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped). Inside the program:
|
`run_code` takes two required arguments: `code` — the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped) — and `description`, a short summary of what the program does. Inside the program:
|
||||||
|
|
||||||
- Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON.
|
- Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON.
|
||||||
- A FAILED tool call rejects with `ToolCallError`, whose `toolName` identifies the failed tool and whose `message` is human-readable — `try/catch` it to handle and continue.
|
- A FAILED tool call rejects with `ToolCallError`, whose `toolName` identifies the failed tool and whose `message` is human-readable — `try/catch` it to handle and continue.
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
"initial": [
|
"initial": [
|
||||||
{
|
{
|
||||||
"name": "run_code",
|
"name": "run_code",
|
||||||
"description": "Execute a TypeScript program against the available tools. Write the BODY of an async function (erasable syntax only; top-level `await` and `return` work) and call tools as `await tools.name(args)` per the declarations in the system prompt. Only what you print or return comes back — curate it.",
|
"description": "Execute a TypeScript program against the available tools. Takes two required arguments: `code`, the BODY of an async function (erasable syntax only; top-level `await` and `return` work), and `description`, a short summary of what the program does. Call tools as `await tools.name(args)` per the declarations in the system prompt. Only what you print or return comes back — curate it.",
|
||||||
"parameters": {
|
"parameters": {
|
||||||
"type": "object",
|
"type": "object",
|
||||||
"properties": {
|
"properties": {
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -2,5 +2,5 @@
|
|||||||
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
# side as of the last confirmed-consistent state. Both languages carry equal authority;
|
||||||
# after editing either side, bring the other along and re-record with:
|
# after editing either side, bring the other along and re-record with:
|
||||||
# pnpm run verify-translation-pairing --write packages/core/tools/README.md
|
# pnpm run verify-translation-pairing --write packages/core/tools/README.md
|
||||||
README.md: 120931c9f4b4f5e1c39c3ddd8da4b8cae42dbe69
|
README.md: 60841513ad5ad439ae8851dffc34e8d250acaa67
|
||||||
README.zh.md: 7a8ca63a607d2fdc841382ace3f7adcbfd721d76
|
README.zh.md: ba2947337285ec5bba3a124cfeb4f105ad623877
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ Code Mode exposes the generated [`run_code` schema](../../../docs/tool-catalog.m
|
|||||||
```markdown
|
```markdown
|
||||||
## Writing code for run_code
|
## Writing code for run_code
|
||||||
|
|
||||||
Pass `run_code` the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped). Inside the program:
|
`run_code` takes two required arguments: `code` — the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped) — and `description`, a short summary of what the program does. Inside the program:
|
||||||
|
|
||||||
- Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON.
|
- Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON.
|
||||||
- A FAILED tool call rejects with `ToolCallError`, whose `toolName` identifies the failed tool and whose `message` is human-readable — `try/catch` it to handle and continue.
|
- A FAILED tool call rejects with `ToolCallError`, whose `toolName` identifies the failed tool and whose `message` is human-readable — `try/catch` it to handle and continue.
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ Code Mode 会公开生成的 [`run_code` schema](../../../docs/tool-catalog.md#d
|
|||||||
```markdown
|
```markdown
|
||||||
## Writing code for run_code
|
## Writing code for run_code
|
||||||
|
|
||||||
Pass `run_code` the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped). Inside the program:
|
`run_code` takes two required arguments: `code` — the body of an async TypeScript function (erasable syntax only — no `enum` or namespaces; type annotations are advisory, the code runs type-stripped) — and `description`, a short summary of what the program does. Inside the program:
|
||||||
|
|
||||||
- Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON.
|
- Call tools as `await tools.name(args)` — quoted access for exotic names: `tools["my-tool"](args)`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON.
|
||||||
- A FAILED tool call rejects with `ToolCallError`, whose `toolName` identifies the failed tool and whose `message` is human-readable — `try/catch` it to handle and continue.
|
- A FAILED tool call rejects with `ToolCallError`, whose `toolName` identifies the failed tool and whose `message` is human-readable — `try/catch` it to handle and continue.
|
||||||
|
|||||||
@@ -45,10 +45,11 @@ interface RunCodeFlavor {
|
|||||||
*/
|
*/
|
||||||
const TYPESCRIPT_FLAVOR: RunCodeFlavor = {
|
const TYPESCRIPT_FLAVOR: RunCodeFlavor = {
|
||||||
description:
|
description:
|
||||||
'Execute a TypeScript program against the available tools. Write the BODY of an '
|
'Execute a TypeScript program against the available tools. Takes two required '
|
||||||
+ 'async function (erasable syntax only; top-level `await` and `return` work) and '
|
+ 'arguments: `code`, the BODY of an async function (erasable syntax only; top-level '
|
||||||
+ 'call tools as `await tools.name(args)` per the declarations in the system prompt. '
|
+ '`await` and `return` work), and `description`, a short summary of what the program '
|
||||||
+ 'Only what you print or return comes back — curate it.',
|
+ 'does. Call tools as `await tools.name(args)` per the declarations in the system '
|
||||||
|
+ 'prompt. Only what you print or return comes back — curate it.',
|
||||||
codeDescription: 'The program: the body of an async TypeScript function.',
|
codeDescription: 'The program: the body of an async TypeScript function.',
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,8 +60,9 @@ const TYPESCRIPT_FLAVOR: RunCodeFlavor = {
|
|||||||
*/
|
*/
|
||||||
const PYTHON_FLAVOR: RunCodeFlavor = {
|
const PYTHON_FLAVOR: RunCodeFlavor = {
|
||||||
description:
|
description:
|
||||||
'Execute a Python program against the available tools. Write the BODY of an '
|
'Execute a Python program against the available tools. Takes two required '
|
||||||
+ 'async function (top-level `await` and `return` work) and call tools as '
|
+ 'arguments: `code`, the BODY of an async function (top-level `await` and `return` '
|
||||||
|
+ 'work), and `description`, a short summary of what the program does. Call tools as '
|
||||||
+ '`await tools.name(args)` per the declarations in the system prompt. Answer '
|
+ '`await tools.name(args)` per the declarations in the system prompt. Answer '
|
||||||
+ 'with `print(...)` and/or `return <value>` — only that comes back, so curate it.',
|
+ 'with `print(...)` and/or `return <value>` — only that comes back, so curate it.',
|
||||||
codeDescription: 'The program: the body of an async Python function.',
|
codeDescription: 'The program: the body of an async Python function.',
|
||||||
|
|||||||
@@ -733,7 +733,7 @@ export function jsonSchemaToPy(schema: unknown): string {
|
|||||||
/** The fixed model-facing usage contract rendered above the declarations. */
|
/** The fixed model-facing usage contract rendered above the declarations. */
|
||||||
const SDK_INSTRUCTIONS = `## Writing code for run_code
|
const SDK_INSTRUCTIONS = `## Writing code for run_code
|
||||||
|
|
||||||
Pass \`run_code\` the body of an async Python function (top-level \`await\` and \`return\` both work). At run time exactly two of the names declared below are bound: \`tools\` and \`ToolCallError\`. Everything else is a STATIC STUB describing argument and return types — in particular the \`TypedDict\` classes do NOT exist at run time, so build arguments as plain \`dict\`/\`list\` JSON values: \`await tools.name({"field": 1})\`, never \`FooArgs(field=1)\`, which raises \`NameError\`. Inside the program:
|
\`run_code\` takes two required arguments: \`code\` — the body of an async Python function (top-level \`await\` and \`return\` both work) — and \`description\`, a short summary of what the program does. At run time exactly two of the names declared below are bound: \`tools\` and \`ToolCallError\`. Everything else is a STATIC STUB describing argument and return types — in particular the \`TypedDict\` classes do NOT exist at run time, so build arguments as plain \`dict\`/\`list\` JSON values: \`await tools.name({"field": 1})\`, never \`FooArgs(field=1)\`, which raises \`NameError\`. Inside the program:
|
||||||
|
|
||||||
- Call tools as \`await tools.name(args)\` — subscript access for exotic, reserved, or underscore-leading names: \`await tools["my-tool"](args)\`. Every call resolves to the tool's typed canonical JSON value (each method's return type below). Tool arguments must be lossless JSON.
|
- Call tools as \`await tools.name(args)\` — subscript access for exotic, reserved, or underscore-leading names: \`await tools["my-tool"](args)\`. Every call resolves to the tool's typed canonical JSON value (each method's return type below). Tool arguments must be lossless JSON.
|
||||||
- A FAILED tool call raises \`ToolCallError\`, whose \`toolName\` identifies the failed tool and whose message is human-readable — wrap in \`try/except\` to handle and continue.
|
- A FAILED tool call raises \`ToolCallError\`, whose \`toolName\` identifies the failed tool and whose message is human-readable — wrap in \`try/except\` to handle and continue.
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ export function jsonSchemaToTs(schema: unknown, indent = 0): string {
|
|||||||
/** The fixed model-facing usage contract rendered above the declarations (see the Code Mode Agent Note's "What the model sees"). */
|
/** The fixed model-facing usage contract rendered above the declarations (see the Code Mode Agent Note's "What the model sees"). */
|
||||||
const SDK_INSTRUCTIONS = `## Writing code for run_code
|
const SDK_INSTRUCTIONS = `## Writing code for run_code
|
||||||
|
|
||||||
Pass \`run_code\` the body of an async TypeScript function (erasable syntax only — no \`enum\` or namespaces; type annotations are advisory, the code runs type-stripped). Inside the program:
|
\`run_code\` takes two required arguments: \`code\` — the body of an async TypeScript function (erasable syntax only — no \`enum\` or namespaces; type annotations are advisory, the code runs type-stripped) — and \`description\`, a short summary of what the program does. Inside the program:
|
||||||
|
|
||||||
- Call tools as \`await tools.name(args)\` — quoted access for exotic names: \`tools["my-tool"](args)\`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON.
|
- Call tools as \`await tools.name(args)\` — quoted access for exotic names: \`tools["my-tool"](args)\`. Every call resolves to the tool's typed canonical JSON value. Tool arguments must be lossless JSON.
|
||||||
- A FAILED tool call rejects with \`ToolCallError\`, whose \`toolName\` identifies the failed tool and whose \`message\` is human-readable — \`try/catch\` it to handle and continue.
|
- A FAILED tool call rejects with \`ToolCallError\`, whose \`toolName\` identifies the failed tool and whose \`message\` is human-readable — \`try/catch\` it to handle and continue.
|
||||||
|
|||||||
@@ -399,6 +399,10 @@ describe('mode-aware wire contribution', () => {
|
|||||||
const runCodeSchema = assembly.tools.find(tool => tool.name === RUN_CODE_NAME)
|
const runCodeSchema = assembly.tools.find(tool => tool.name === RUN_CODE_NAME)
|
||||||
expect(runCodeSchema?.description).toContain('Execute a TypeScript program')
|
expect(runCodeSchema?.description).toContain('Execute a TypeScript program')
|
||||||
expect(runCodeSchema?.description).toContain('BODY of an')
|
expect(runCodeSchema?.description).toContain('BODY of an')
|
||||||
|
// Both required arguments are named here, not only in the parameter
|
||||||
|
// schema: prose that describes the call as "pass the program" is what
|
||||||
|
// leads a model to emit `{code}` alone and fail INVALID_ARGS.
|
||||||
|
expect(runCodeSchema?.description).toContain('`description`')
|
||||||
const codeParam = (runCodeSchema?.parameters as { properties: { code: { description: string } } }).properties.code
|
const codeParam = (runCodeSchema?.parameters as { properties: { code: { description: string } } }).properties.code
|
||||||
expect(codeParam.description).toBe('The program: the body of an async TypeScript function.')
|
expect(codeParam.description).toBe('The program: the body of an async TypeScript function.')
|
||||||
})
|
})
|
||||||
@@ -410,6 +414,7 @@ describe('mode-aware wire contribution', () => {
|
|||||||
const runCodeSchema = assembly.tools.find(tool => tool.name === RUN_CODE_NAME)
|
const runCodeSchema = assembly.tools.find(tool => tool.name === RUN_CODE_NAME)
|
||||||
expect(runCodeSchema?.description).toContain('Execute a Python program')
|
expect(runCodeSchema?.description).toContain('Execute a Python program')
|
||||||
expect(runCodeSchema?.description).toContain('`return <value>`')
|
expect(runCodeSchema?.description).toContain('`return <value>`')
|
||||||
|
expect(runCodeSchema?.description).toContain('`description`')
|
||||||
expect(runCodeSchema?.description).not.toContain('TypeScript')
|
expect(runCodeSchema?.description).not.toContain('TypeScript')
|
||||||
const codeParam = (runCodeSchema?.parameters as { properties: { code: { description: string } } }).properties.code
|
const codeParam = (runCodeSchema?.parameters as { properties: { code: { description: string } } }).properties.code
|
||||||
expect(codeParam.description).toBe('The program: the body of an async Python function.')
|
expect(codeParam.description).toBe('The program: the body of an async Python function.')
|
||||||
|
|||||||
@@ -166,6 +166,15 @@ describe('renderToolsSdkPy', () => {
|
|||||||
expect(text).toContain('tools: Tools')
|
expect(text).toContain('tools: Tools')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('names both required call arguments, not just the program', () => {
|
||||||
|
// The schema requires `code` AND `description`; instructions that mention
|
||||||
|
// only the program let a model emit `{code}` alone and fail INVALID_ARGS.
|
||||||
|
const text = renderToolsSdkPy([bash])
|
||||||
|
expect(text).toContain('`code`')
|
||||||
|
expect(text).toContain('`description`')
|
||||||
|
expect(text).toContain('two required arguments')
|
||||||
|
})
|
||||||
|
|
||||||
it('renders required as plain fields and optional as NotRequired, with per-field description comments', () => {
|
it('renders required as plain fields and optional as NotRequired, with per-field description comments', () => {
|
||||||
const tool: ToolSdkSchema = {
|
const tool: ToolSdkSchema = {
|
||||||
name: 'search',
|
name: 'search',
|
||||||
|
|||||||
@@ -148,6 +148,15 @@ describe('renderToolsSdk', () => {
|
|||||||
expect(text).toContain('lossless JSON')
|
expect(text).toContain('lossless JSON')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('names both required call arguments, not just the program', () => {
|
||||||
|
// The schema requires `code` AND `description`; instructions that mention
|
||||||
|
// only the program let a model emit `{code}` alone and fail INVALID_ARGS.
|
||||||
|
const text = renderToolsSdk([bash])
|
||||||
|
expect(text).toContain('`code`')
|
||||||
|
expect(text).toContain('`description`')
|
||||||
|
expect(text).toContain('two required arguments')
|
||||||
|
})
|
||||||
|
|
||||||
it('is deterministic: same tool set, byte-identical text regardless of input order', () => {
|
it('is deterministic: same tool set, byte-identical text regardless of input order', () => {
|
||||||
expect(renderToolsSdk([bash, exotic])).toBe(renderToolsSdk([exotic, bash]))
|
expect(renderToolsSdk([bash, exotic])).toBe(renderToolsSdk([exotic, bash]))
|
||||||
// Equal names sort stably (the comparator's equal arm).
|
// Equal names sort stably (the comparator's equal arm).
|
||||||
|
|||||||
Reference in New Issue
Block a user