docs(tools): qualify the three remaining mode-dependent only-claims

The `mode: 'code'` qualification landed on the module header and
`isBareIdentifier` but not on the other three sites the same reviews
enumerated. `UNPRINTABLE`'s "only declaration of the tools", the open-object
comment's "only signal that extra keys are accepted", and the docstring
comment's "only description of what a tool does" are each false under
`mode: 'both'`, where the native schemas ship alongside the SDK.

Widen the note's predicate-path sentence past head and last position: a
character added to `XID_Continue` passes `IDENTIFIER`'s trailing quantifier
anywhere after the head, the middle of a name included.

Record the ƛ test's table provenance. U+A7DC and the U+019B mapping to it
both arrive in Unicode 16.0, and the engines floor sits exactly there:
Node 22.19.0 reports Unicode 16.0 (ICU 77.1) and produces the mapping.
This commit is contained in:
Chinesezjc
2026-08-05 21:53:32 +08:00
parent be98a0b978
commit 0891556cb4
5 changed files with 20 additions and 12 deletions

View File

@@ -155,8 +155,8 @@ interface RenderState {
* CPython rejects source containing a NUL outright
* (`SyntaxError: source code string cannot contain null bytes`), whether it
* sits in a docstring or in a comment, so one such byte anywhere in a schema
* description would make the whole generated SDK unparseable — the model's only
* declaration of the tools. The rest are legal but invisible; escaping them
* description would make the whole generated SDK unparseable — under
* `mode: 'code'`, the model's only declaration of the tools. The rest are legal but invisible; escaping them
* with the same rule keeps the emitted text readable and the treatment uniform.
*
* The boundary is the category, not per-code-point addressability: `\xNN`
@@ -557,9 +557,9 @@ function renderType(schema: unknown, className: string, state: RenderState): str
}
}
// TypedDict syntax cannot express openness, so an open object states it
// in-band: the annotation is advisory either way, and Code Mode omits
// the native schemas, making this line the model's only signal that
// extra keys are accepted.
// in-band: the annotation is advisory either way, and `mode: 'code'`
// omits the native schemas, making this line the model's only signal
// that extra keys are accepted.
if (node.additionalProperties !== false) {
lines.push(`${pad(1)}# Additional keys beyond those declared are allowed.`)
}
@@ -753,9 +753,9 @@ export function renderToolsSdkPy(schemas: ToolSdkSchema[]): string {
// of that method's body. Emitted before the `async def` it would instead
// become the `Tools` class docstring (for the first tool) or a dead
// expression (for every later one), leaving every method undocumented —
// and this SDK is the model's only description of what a tool does. A
// docstring is a complete body, so the `...` stub is only for the
// description-less case.
// and under `mode: 'code'` this SDK is the model's only description of
// what a tool does. A docstring is a complete body, so the `...` stub is
// only for the description-less case.
const doc = docLines(schema.description, 2)
members.push(doc.length > 0
? `${pad(1)}async def ${schema.name}(self, args: ${argType}) -> ${outputType}:`

View File

@@ -480,6 +480,14 @@ describe('renderToolsSdkPy', () => {
// an older interpreter's do not. This pins which table produced the name,
// so a change to the mapping step shows up here rather than only in a
// downstream Python parse.
//
// Unlike the other Unicode cases in this file, the table row is recent:
// U+A7DC and the U+019B uppercase mapping to it both arrive in Unicode
// 16.0 (`DerivedAge.txt`; CPython 3.12.13's 15.0.0 has neither). The
// engines floor sits exactly there with no margin — Node 22.19.0 reports
// Unicode 16.0 (ICU 77.1) and maps U+019B to U+A7DC, measured — so an
// engine below the floor fails here as a renderer regression whose real
// cause is the table version.
const text = renderToolsSdkPy([
{
name: 'ƛ',