mirror of
https://github.com/deepseek-ai/deepseek-harness
synced 2026-08-15 21:04:50 +00:00
docs(tools): name the boundary that rejects a padded integer, and what the flavor-guard test actually reads
pyScalar's docstring attributed the rejection of a String-spelled beyond-safe-range integer to "the Python runtime". No published backend makes that call on this base. The fact that does not depend on one: the padded digits name an integer no double holds, and passing it back would have to cross the argument boundary as a JSON number. Say that, and say why String rounds at all -- Number::toString is shortest round-trip, so 2 ** 60 emits the 16 digits that re-read to the same double and pads. Mirror both in the test comment. The note's Decision sentence said a test covers the flavor guard through ctx.tools.schemas(). The test reads the definition's getter directly, under a language absent from both tables; schemas() reaches the same getter but has no assertion. Name what is read, and record that a renderer-without-flavor language is drift this guards against rather than an existing input -- the two key sets are identical today.
This commit is contained in:
@@ -2,5 +2,5 @@
|
||||
# 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:
|
||||
# pnpm run verify-translation-pairing --write .agents/notes/implemented/feature/2026-07-31-code-mode-language-dispatch.md
|
||||
2026-07-31-code-mode-language-dispatch.md: 3b78783744e2e30cf34c0603332c050252bda447
|
||||
2026-07-31-code-mode-language-dispatch.zh.md: 17fb63d686ae695b564e9283c413f8e589d56810
|
||||
2026-07-31-code-mode-language-dispatch.md: c2010ec368da82d8c41df8d00a8e32f0064afde3
|
||||
2026-07-31-code-mode-language-dispatch.zh.md: 3cc3bae8c683e8434f48dd251b9dd5dd580bc3ce
|
||||
|
||||
@@ -17,7 +17,7 @@ Language selection is a lookup on `ctx.codeRuntime.language`, resolved lazily at
|
||||
- `SDK_RENDERERS` (index.ts) maps a language to its `tools:sdk` renderer — `typescript → renderToolsSdk`, `python → renderToolsSdkPy`. The `tools:sdk` section reads the loaded runtime's language and picks the renderer; `requireCodeRuntime` rejects a `mode: code`/`both` runtime whose language is absent from the table, naming the known languages.
|
||||
- `RUN_CODE_FLAVORS` (code-mode.ts) maps a language to its two model-facing `run_code` strings (tool `description` and the `code` parameter description), so a language's SDK section and its transport schema always agree.
|
||||
|
||||
Both tables are read with `Object.hasOwn` before use so a language named `toString`/`constructor` cannot resolve an inherited `Object.prototype` member as a renderer. The two guards differ in reachability: `SDK_RENDERERS`' in-callback guard is unreachable because `requireCodeRuntime` validated the same `const` table earlier in the same callback (it carries a `/* v8 ignore */`), while `RUN_CODE_FLAVORS`' guard is the primary, publicly reachable rejection — any language absent from the flavor table hits it through `run_code`'s language-aware getters, which `schemas()` reaches without passing `requireCodeRuntime` first, and a test covers it. Schema emission reads the runtime through `peekRuntime()` rather than `requireRuntime()`: `undefined` (no runtime mounted, the doc-catalog schema harvest that never reaches a model) degrades to the TypeScript flavor, whereas a mounted unknown language fails loud — this is NOT the silent fallback rejected below, which concerns emitting a wrong-language SDK for a real runtime. Adding a backend language is two table entries plus its renderer — no `agent-loop` or registry-structure change.
|
||||
Both tables are read with `Object.hasOwn` before use so a language named `toString`/`constructor` cannot resolve an inherited `Object.prototype` member as a renderer. The two guards differ in reachability: `SDK_RENDERERS`' in-callback guard is unreachable because `requireCodeRuntime` validated the same `const` table earlier in the same callback (it carries a `/* v8 ignore */`), while `RUN_CODE_FLAVORS`' guard is the primary, publicly reachable rejection — any language absent from the flavor table hits it through `run_code`'s language-aware getters, which the public `schemas()` reaches without passing `requireCodeRuntime` first; the test reads one of those getters off the definition directly, under a language absent from both tables. A language present in `SDK_RENDERERS` but not `RUN_CODE_FLAVORS` is the drift this guards against, not an input that exists — the two tables' key sets are identical today. Schema emission reads the runtime through `peekRuntime()` rather than `requireRuntime()`: `undefined` (no runtime mounted, the doc-catalog schema harvest that never reaches a model) degrades to the TypeScript flavor, whereas a mounted unknown language fails loud — this is NOT the silent fallback rejected below, which concerns emitting a wrong-language SDK for a real runtime. Adding a backend language is two table entries plus its renderer — no `agent-loop` or registry-structure change.
|
||||
|
||||
`code-mode.ts` depends only on the runtime seam (`@deepseek-ai/dsh-code-runtime`), never on a concrete backend; dispatch is by `runtime.language` at run time. The tool layer therefore lands independently of the protocol and backend PRs — it needs only the seam's `language` field, which is already on master.
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ Code Mode 只生成一种 SDK 形态:TypeScript。`ToolRegistry` 为 `tools:sd
|
||||
- `SDK_RENDERERS`(index.ts)把语言映射到它的 `tools:sdk` 渲染器——`typescript → renderToolsSdk`、`python → renderToolsSdkPy`。`tools:sdk` 段读取所加载运行时的语言并选出渲染器;`requireCodeRuntime` 拒绝其语言不在表中的 `mode: code`/`both` 运行时,并列出已知语言。
|
||||
- `RUN_CODE_FLAVORS`(code-mode.ts)把语言映射到它那两条面向模型的 `run_code` 字符串(工具 `description` 与 `code` 参数描述),使一种语言的 SDK 段与它的传输 schema 始终一致。
|
||||
|
||||
两张表在使用前都以 `Object.hasOwn` 读取,这样名为 `toString`/`constructor` 的语言不会把继承自 `Object.prototype` 的成员解析成渲染器。两个守卫的可达性不同:`SDK_RENDERERS` 的段内守卫不可达,因为 `requireCodeRuntime` 已在同一回调更早处校验过同一张 `const` 表(它带 `/* v8 ignore */`);而 `RUN_CODE_FLAVORS` 的守卫是主要的、可公开到达的拒绝路径——任何缺席 flavor 表的语言都经 `run_code` 的语言感知 getter 到达它,而 `schemas()` 抵达那些 getter 时并未先过 `requireCodeRuntime`,且有测试覆盖。schema 发射通过 `peekRuntime()` 而非 `requireRuntime()` 读取运行时:`undefined`(无运行时,即永不喂给模型的 doc-catalog schema 采集)降级到 TypeScript flavor,而挂载了未知语言则 fail loud——这不是下方被否决的静默回退,那指的是为真实运行时发出错误语言的 SDK。新增一门后端语言就是两条表项加它的渲染器——不动 `agent-loop`,也不动注册表结构。
|
||||
两张表在使用前都以 `Object.hasOwn` 读取,这样名为 `toString`/`constructor` 的语言不会把继承自 `Object.prototype` 的成员解析成渲染器。两个守卫的可达性不同:`SDK_RENDERERS` 的段内守卫不可达,因为 `requireCodeRuntime` 已在同一回调更早处校验过同一张 `const` 表(它带 `/* v8 ignore */`);而 `RUN_CODE_FLAVORS` 的守卫是主要的、可公开到达的拒绝路径——任何缺席 flavor 表的语言都经 `run_code` 的语言感知 getter 到达它,而公共 `schemas()` 抵达那些 getter 时并未先过 `requireCodeRuntime`;测试直读 definition 上的其中一个 getter,用的是对两张表都缺席的语言。「在 `SDK_RENDERERS` 里却不在 `RUN_CODE_FLAVORS` 里」是这个守卫所防的表漂移,不是已存在的输入——两张表当前键集相同。schema 发射通过 `peekRuntime()` 而非 `requireRuntime()` 读取运行时:`undefined`(无运行时,即永不喂给模型的 doc-catalog schema 采集)降级到 TypeScript flavor,而挂载了未知语言则 fail loud——这不是下方被否决的静默回退,那指的是为真实运行时发出错误语言的 SDK。新增一门后端语言就是两条表项加它的渲染器——不动 `agent-loop`,也不动注册表结构。
|
||||
|
||||
`code-mode.ts` 只依赖运行时 seam(`@deepseek-ai/dsh-code-runtime`),绝不依赖具体后端;分发在运行时按 `runtime.language` 进行。因此工具层独立于协议和后端 PR 落地——它只需要 seam 的 `language` 字段,而该字段已在 master 上。
|
||||
|
||||
|
||||
@@ -259,11 +259,14 @@ function childClassName(base: string, segment: string): string {
|
||||
* `String`: Python integers are arbitrary-precision, so the emitted digits ARE
|
||||
* the value the model programs against, and `String` gives a different integer
|
||||
* than the double holds (`2 ** 60` prints the rounded `...847000`, not the
|
||||
* exact `...846976`) or no integer literal at all (`1e21` prints `1e+21`). The
|
||||
* Python runtime then rejects the advertised literal as not exactly
|
||||
* representable as a JavaScript number, so the SDK would document a value no
|
||||
* program can pass. The TS flavor needs no counterpart: its literal is re-read
|
||||
* by a JS parser back into the same double.
|
||||
* exact `...846976`) or no integer literal at all (`1e21` prints `1e+21`).
|
||||
* `String`'s rounding is not a bug in it: `Number::toString` is shortest
|
||||
* round-trip, so it emits the 16 digits that re-read to the same double and
|
||||
* pads with zeros, and those padded digits name an integer no double holds.
|
||||
* Passing one back would have to cross the argument boundary as a JSON number
|
||||
* — a double again — so the SDK would document a value no program can pass.
|
||||
* The TS flavor needs no counterpart: its literal is re-read by a JS parser
|
||||
* back into the same double.
|
||||
*
|
||||
* `JSON.stringify` is also what keeps this path's output parseable, and it is
|
||||
* the only thing that does. It covers both classes of hazard: the two kinds of
|
||||
|
||||
@@ -71,9 +71,13 @@ describe('jsonSchemaToPy', () => {
|
||||
// Python integers are arbitrary-precision, so the emitted digits ARE the
|
||||
// value the model programs against. `String(2 ** 60)` prints the rounded
|
||||
// ...847000, which is a DIFFERENT integer from the double's exact
|
||||
// ...846976 — the Python runtime would reject the advertised literal as
|
||||
// not exactly representable as a JavaScript number, so the SDK would
|
||||
// document a value no program can pass.
|
||||
// ...846976: `Number::toString` is shortest round-trip, so it emits the 16
|
||||
// digits that re-read to the same double and pads with zeros, and those
|
||||
// padded digits name an integer no double holds. Passing one back would
|
||||
// have to cross the argument boundary as a JSON number, so the SDK would
|
||||
// document a value no program can pass. This assertion is what separates
|
||||
// the two spellings; the 1e21 case below separates them again on the other
|
||||
// failure mode, where `String` gives no integer literal at all.
|
||||
expect(jsonSchemaToPy({ type: 'integer', const: 2 ** 60 })).toBe('Literal[1152921504606846976]')
|
||||
expect(jsonSchemaToPy({ type: 'integer', enum: [2 ** 60, -(2 ** 60)] }))
|
||||
.toBe('Literal[1152921504606846976, -1152921504606846976]')
|
||||
|
||||
Reference in New Issue
Block a user