@dsh-cc/tools 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.i18n.yaml +6 -0
- package/README.md +209 -0
- package/README.zh.md +200 -0
- package/lib/abort-utils.d.ts +80 -0
- package/lib/abort-utils.d.ts.map +1 -0
- package/lib/abort-utils.js +186 -0
- package/lib/abort-utils.js.map +1 -0
- package/lib/cc-names.d.ts +100 -0
- package/lib/cc-names.d.ts.map +1 -0
- package/lib/cc-names.js +197 -0
- package/lib/cc-names.js.map +1 -0
- package/lib/code-mode.d.ts +46 -0
- package/lib/code-mode.d.ts.map +1 -0
- package/lib/code-mode.js +380 -0
- package/lib/code-mode.js.map +1 -0
- package/lib/define-tool.d.ts +103 -0
- package/lib/define-tool.d.ts.map +1 -0
- package/lib/define-tool.js +354 -0
- package/lib/define-tool.js.map +1 -0
- package/lib/index.d.ts +348 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +289 -0
- package/lib/index.js.map +1 -0
- package/lib/invariant.d.ts +13 -0
- package/lib/invariant.d.ts.map +1 -0
- package/lib/invariant.js +123 -0
- package/lib/invariant.js.map +1 -0
- package/lib/json-render.d.ts +18 -0
- package/lib/json-render.d.ts.map +1 -0
- package/lib/json-render.js +111 -0
- package/lib/json-render.js.map +1 -0
- package/lib/json-schema-value.d.ts +18 -0
- package/lib/json-schema-value.d.ts.map +1 -0
- package/lib/json-schema-value.js +238 -0
- package/lib/json-schema-value.js.map +1 -0
- package/lib/json-schema.d.ts +101 -0
- package/lib/json-schema.d.ts.map +1 -0
- package/lib/json-schema.js +351 -0
- package/lib/json-schema.js.map +1 -0
- package/lib/presentation.d.ts +367 -0
- package/lib/presentation.d.ts.map +1 -0
- package/lib/presentation.js +8 -0
- package/lib/presentation.js.map +1 -0
- package/lib/py-names.d.ts +163 -0
- package/lib/py-names.d.ts.map +1 -0
- package/lib/py-names.js +236 -0
- package/lib/py-names.js.map +1 -0
- package/lib/py-render.d.ts +23 -0
- package/lib/py-render.d.ts.map +1 -0
- package/lib/py-render.js +434 -0
- package/lib/py-render.js.map +1 -0
- package/lib/py-sdk-doc.d.ts +29 -0
- package/lib/py-sdk-doc.d.ts.map +1 -0
- package/lib/py-sdk-doc.js +114 -0
- package/lib/py-sdk-doc.js.map +1 -0
- package/lib/py-types.d.ts +34 -0
- package/lib/py-types.d.ts.map +1 -0
- package/lib/py-types.js +40 -0
- package/lib/py-types.js.map +1 -0
- package/lib/run-code-defs.d.ts +77 -0
- package/lib/run-code-defs.d.ts.map +1 -0
- package/lib/run-code-defs.js +98 -0
- package/lib/run-code-defs.js.map +1 -0
- package/lib/runtime-code.d.ts +65 -0
- package/lib/runtime-code.d.ts.map +1 -0
- package/lib/runtime-code.js +129 -0
- package/lib/runtime-code.js.map +1 -0
- package/lib/runtime-core.d.ts +130 -0
- package/lib/runtime-core.d.ts.map +1 -0
- package/lib/runtime-core.js +33 -0
- package/lib/runtime-core.js.map +1 -0
- package/lib/runtime-execute.d.ts +82 -0
- package/lib/runtime-execute.d.ts.map +1 -0
- package/lib/runtime-execute.js +333 -0
- package/lib/runtime-execute.js.map +1 -0
- package/lib/runtime-registry.d.ts +131 -0
- package/lib/runtime-registry.d.ts.map +1 -0
- package/lib/runtime-registry.js +269 -0
- package/lib/runtime-registry.js.map +1 -0
- package/lib/runtime-results.d.ts +32 -0
- package/lib/runtime-results.d.ts.map +1 -0
- package/lib/runtime-results.js +163 -0
- package/lib/runtime-results.js.map +1 -0
- package/lib/runtime-schemas.d.ts +112 -0
- package/lib/runtime-schemas.d.ts.map +1 -0
- package/lib/runtime-schemas.js +222 -0
- package/lib/runtime-schemas.js.map +1 -0
- package/lib/scheduler.d.ts +22 -0
- package/lib/scheduler.d.ts.map +1 -0
- package/lib/scheduler.js +21 -0
- package/lib/scheduler.js.map +1 -0
- package/lib/schema-spec.d.ts +154 -0
- package/lib/schema-spec.d.ts.map +1 -0
- package/lib/schema-spec.js +9 -0
- package/lib/schema-spec.js.map +1 -0
- package/lib/schema.d.ts +5 -0
- package/lib/schema.d.ts.map +1 -0
- package/lib/schema.js +3 -0
- package/lib/schema.js.map +1 -0
- package/lib/testing.d.ts +25 -0
- package/lib/testing.d.ts.map +1 -0
- package/lib/testing.js +25 -0
- package/lib/testing.js.map +1 -0
- package/lib/tool-layer.d.ts +49 -0
- package/lib/tool-layer.d.ts.map +1 -0
- package/lib/tool-layer.js +57 -0
- package/lib/tool-layer.js.map +1 -0
- package/lib/tool-types.d.ts +385 -0
- package/lib/tool-types.d.ts.map +1 -0
- package/lib/tool-types.js +11 -0
- package/lib/tool-types.js.map +1 -0
- package/lib/ts-types.d.ts +37 -0
- package/lib/ts-types.d.ts.map +1 -0
- package/lib/ts-types.js +265 -0
- package/lib/ts-types.js.map +1 -0
- package/lib/types.d.ts +55 -0
- package/lib/types.d.ts.map +1 -0
- package/lib/types.js +7 -0
- package/lib/types.js.map +1 -0
- package/package.json +65 -0
package/lib/py-render.js
ADDED
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Python type-expression renderer: {@link renderType}, the explicit-stack
|
|
3
|
+
* walker that maps one validated JSON-Schema node to a Python type expression
|
|
4
|
+
* while threading a {@link RenderState} to collect the `TypedDict` class
|
|
5
|
+
* declarations and `typing` symbols a full render needs. Split out of
|
|
6
|
+
* `py-types.ts` for the line budget; `jsonSchemaToPy` and `renderToolsSdkPy`
|
|
7
|
+
* remain the public entries, re-exported from `py-types.ts`.
|
|
8
|
+
* @module @dsh-cc/tools/src/py-render
|
|
9
|
+
*/
|
|
10
|
+
import { assertSupportedJsonSchema } from "./json-schema.js";
|
|
11
|
+
import { describe, camelCase, isBareIdentifier, pad, RESERVED } from "./py-names.js";
|
|
12
|
+
/** Class-name base cap keeping each emitted name — and total text — linear in schema depth. */
|
|
13
|
+
const MAX_CLASS_NAME_BASE = 120;
|
|
14
|
+
/**
|
|
15
|
+
* Deepest `list[…]` nesting emitted into one annotation before the item type
|
|
16
|
+
* degrades to `Any`. CPython's tokenizer rejects a logical line holding more
|
|
17
|
+
* than 200 simultaneously-open brackets (`MAXLEVEL`, `SyntaxError: too many
|
|
18
|
+
* nested parentheses`), so an array chain deeper than that would render an SDK
|
|
19
|
+
* block that is not valid Python at all — the same failure the docstring
|
|
20
|
+
* escaping in the SDK doc renderer exists to prevent. 180 leaves headroom for
|
|
21
|
+
* the few brackets an annotation can add around the chain, all of which count
|
|
22
|
+
* toward the same limit. Per emission site, counting brackets open at the
|
|
23
|
+
* chain's innermost point:
|
|
24
|
+
*
|
|
25
|
+
* - Return annotation, `async def f(self, args: X) -> chain:` — 180 `list[`
|
|
26
|
+
* plus an innermost `Literal[`. The parameter list's `(` closed at the `)`
|
|
27
|
+
* before the `->`, so it is NOT open here: 181.
|
|
28
|
+
* - TypedDict field, `field: NotRequired[chain]` — a class-body line with no
|
|
29
|
+
* other open bracket, and its children start at `listDepth: 1` to reserve
|
|
30
|
+
* the `NotRequired[`, so 179 `list[` plus `Literal[`: 181. Required fields
|
|
31
|
+
* share that start for uniformity, spending one level of representable depth
|
|
32
|
+
* on a bracket they never emit.
|
|
33
|
+
* - Argument annotation, `async def f(self, args: chain) -> Y:` — the `(` IS
|
|
34
|
+
* still open around it: 180 `list[` plus `Literal[` plus the paren, 182, the
|
|
35
|
+
* worst case. Reachable only through a raw `register()` whose `parameters`
|
|
36
|
+
* is an array reached from the root through `oneOf` arms alone — the root
|
|
37
|
+
* array itself, or one nested under any depth of unions, since an arm
|
|
38
|
+
* inherits the enclosing depth unchanged (`A | B` opens no bracket). An
|
|
39
|
+
* object ancestor takes it out of this case: its fields restart the chain at
|
|
40
|
+
* the 181 site. `defineTool` compiles an object root, so the annotation is a
|
|
41
|
+
* bare TypedDict class name or a one-bracket `dict[str, Any]` when that
|
|
42
|
+
* object degrades — never a chain.
|
|
43
|
+
*
|
|
44
|
+
* A CPython grammar limit, not a deployment choice, so it is fixed rather than
|
|
45
|
+
* configurable. The sibling `ts-types` renderer needs no counterpart: nothing
|
|
46
|
+
* in the TypeScript grammar bounds nesting, and its SDK block is never type-
|
|
47
|
+
* checked. Only bracket nesting counts — a `oneOf` renders as a flat `A | B`
|
|
48
|
+
* chain and nested objects render as separate `class` statements, so neither
|
|
49
|
+
* accumulates open brackets at any depth. The invariant this cap serves is
|
|
50
|
+
* grammatical validity; see the `oneOf` arm in {@link renderType} for the one
|
|
51
|
+
* interpreter limit deliberately left uncapped.
|
|
52
|
+
*/
|
|
53
|
+
const MAX_LIST_NESTING = 180;
|
|
54
|
+
/**
|
|
55
|
+
* Cap a class-name base at {@link MAX_CLASS_NAME_BASE} (see the callers for
|
|
56
|
+
* why capping keeps the render linear). `slice` counts UTF-16 code units, so
|
|
57
|
+
* an astral character straddling the boundary would be cut in half and leave a
|
|
58
|
+
* lone surrogate — not an identifier character, and not even well-formed text;
|
|
59
|
+
* drop it rather than emit it.
|
|
60
|
+
*/
|
|
61
|
+
function capClassNameBase(base) {
|
|
62
|
+
if (base.length <= MAX_CLASS_NAME_BASE)
|
|
63
|
+
return base;
|
|
64
|
+
const capped = base.slice(0, MAX_CLASS_NAME_BASE);
|
|
65
|
+
return /[\uD800-\uDBFF]$/.test(capped) ? capped.slice(0, -1) : capped;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Reserve a unique class name from a base, suffixing `2`, `3`, … on collision.
|
|
69
|
+
* The base is capped at {@link MAX_CLASS_NAME_BASE} first: child class names
|
|
70
|
+
* derive from their parent's allocated name (`ParentChild`), so an unbounded
|
|
71
|
+
* schema of single-field objects would otherwise grow each name by one field
|
|
72
|
+
* per level and the sum of all names to Θ(depth²). Capping the base keeps each
|
|
73
|
+
* name — and the total emitted text — linear in depth. Collisions resume from
|
|
74
|
+
* the per-base counter in `state.nextClassCounter` rather than rescanning from
|
|
75
|
+
* `2`, so a deep chain sharing one capped base stays O(1) per allocation
|
|
76
|
+
* (amortized) instead of Θ(depth²) in time.
|
|
77
|
+
*/
|
|
78
|
+
function allocateClassName(base, state) {
|
|
79
|
+
const capped = capClassNameBase(base);
|
|
80
|
+
let name = capped;
|
|
81
|
+
if (state.usedClassNames.has(name)) {
|
|
82
|
+
let n = state.nextClassCounter.get(capped) ?? 2;
|
|
83
|
+
while (state.usedClassNames.has(`${capped}${n}`))
|
|
84
|
+
n++;
|
|
85
|
+
name = `${capped}${n}`;
|
|
86
|
+
state.nextClassCounter.set(capped, n + 1);
|
|
87
|
+
}
|
|
88
|
+
state.usedClassNames.add(name);
|
|
89
|
+
return name;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Append a child-name segment to a parent class-name base, capping the result
|
|
93
|
+
* at {@link MAX_CLASS_NAME_BASE}. Capping AT PROPAGATION (not only inside
|
|
94
|
+
* {@link allocateClassName}) keeps each level O(1): a deep `oneOf`- or
|
|
95
|
+
* object-chain would otherwise carry an ever-growing ConsString down the tree
|
|
96
|
+
* and re-materialize it (via `.length`/`.slice`) at every level — Θ(depth²).
|
|
97
|
+
* The bounded base plus the collision counter still yields unique names.
|
|
98
|
+
*
|
|
99
|
+
* The join is NFKC-normalized because both sides are separately normalized yet
|
|
100
|
+
* their concatenation need not be: a base ending in a Hangul L jamo or LV
|
|
101
|
+
* syllable composes with a following V or T jamo head (`가` + `ᆨ` gives `각`),
|
|
102
|
+
* so the emitted class name would differ from the symbol CPython compiles, and
|
|
103
|
+
* two byte-distinct names could fold onto one — `usedClassNames` dedupes by the
|
|
104
|
+
* raw bytes, so the collision counter would not see it. Normalizing costs
|
|
105
|
+
* O(cap + segment) per level, the same order as the `slice` it feeds. The other
|
|
106
|
+
* two join points need no counterpart: `Args`/`Output` start with `A`/`O` and
|
|
107
|
+
* {@link allocateClassName}'s suffix is digits, none of which compose backwards.
|
|
108
|
+
*/
|
|
109
|
+
function childClassName(base, segment) {
|
|
110
|
+
return capClassNameBase(`${base}${segment}`.normalize('NFKC'));
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Render one validated scalar as Python literal text (`True`/`False`,
|
|
114
|
+
* JSON-quoted strings, bare numbers). `null` cannot reach here: the `null`
|
|
115
|
+
* type renders directly as `None`, and the unified validator rejects a null
|
|
116
|
+
* `const`/`enum` entry on every other scalar type.
|
|
117
|
+
*
|
|
118
|
+
* A beyond-safe-range integral number takes `BigInt` digits rather than
|
|
119
|
+
* `String`: Python integers are arbitrary-precision, so the emitted digits ARE
|
|
120
|
+
* the value the model programs against, and `String` can give a different
|
|
121
|
+
* integer than the double holds (`2 ** 60` prints the rounded `...847000`, not
|
|
122
|
+
* the exact `...846976`) or no integer literal at all (`1e21` prints `1e+21`).
|
|
123
|
+
* `String`'s rounding is not a bug in it: `Number::toString` emits the shortest
|
|
124
|
+
* decimal string that re-reads to the same double, then pads to the exponent
|
|
125
|
+
* with zeros (1 significant digit for `1e20`, 16 for `2 ** 60`) — and when the
|
|
126
|
+
* shortest string is shorter than the double's exact value, those padded digits
|
|
127
|
+
* name an integer no double holds. Passing one back would have to cross the
|
|
128
|
+
* argument boundary as a JSON number — a double again — so the SDK would
|
|
129
|
+
* document a value no program can pass. `BigInt` needs no case split: where
|
|
130
|
+
* `String` is already exact (`2 ** 53`, `1e20`) the two agree byte for byte,
|
|
131
|
+
* and where it is not, `BigInt` is the exact one. The TS flavor needs no
|
|
132
|
+
* counterpart at all: its literal is re-read by a JS parser back into the same
|
|
133
|
+
* double.
|
|
134
|
+
*
|
|
135
|
+
* `JSON.stringify` is also what keeps this path's output parseable, and it is
|
|
136
|
+
* the only thing that does. It covers both classes of hazard: the two kinds of
|
|
137
|
+
* code point CPython refuses anywhere in source — NUL among the C0 controls,
|
|
138
|
+
* and the whole D800–DFFF unpaired-surrogate block, escaped under ES2019
|
|
139
|
+
* well-formed stringification, which the engines range guarantees — and the
|
|
140
|
+
* ones that break this line in particular, a bare `"` closing the literal
|
|
141
|
+
* early, a trailing odd backslash eating the closing quote, and a bare LF/CR
|
|
142
|
+
* ending it before its terminator. The `description` path carries
|
|
143
|
+
* the unprintable-character and lone-surrogate rules because nothing quotes it,
|
|
144
|
+
* and folds newlines in {@link describe}.
|
|
145
|
+
*
|
|
146
|
+
* That leans on a coincidence worth naming: every escape `JSON.stringify` can
|
|
147
|
+
* emit (`\"`, `\\`, `\b`, `\f`, `\n`, `\r`, `\t`, `\uXXXX`) is also a Python
|
|
148
|
+
* escape denoting the same character, so the emitted `Literal[...]` both
|
|
149
|
+
* parses and decodes back to the value the schema declared. DEL, the C1
|
|
150
|
+
* controls (NEL among them), and LS/PS (U+2028/U+2029) do reach it raw —
|
|
151
|
+
* legal but invisible, byte-for-byte as in the TS flavor; escaping them is a
|
|
152
|
+
* both-flavors change. Those last three are legal here for the reason
|
|
153
|
+
* the unprintable rule records: they are `str.splitlines()` boundaries, not
|
|
154
|
+
* tokenizer line terminators. The subscript tool-name comment quotes its name
|
|
155
|
+
* through its own call to the same `JSON.stringify`, never through this
|
|
156
|
+
* function, and inherits both halves — escapes and pass-throughs alike.
|
|
157
|
+
*/
|
|
158
|
+
function pyScalar(value) {
|
|
159
|
+
if (value === true)
|
|
160
|
+
return 'True';
|
|
161
|
+
if (value === false)
|
|
162
|
+
return 'False';
|
|
163
|
+
if (typeof value === 'string')
|
|
164
|
+
return JSON.stringify(value);
|
|
165
|
+
if (typeof value === 'number' && Number.isInteger(value) && !Number.isSafeInteger(value)) {
|
|
166
|
+
return BigInt(value).toString();
|
|
167
|
+
}
|
|
168
|
+
return String(value);
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Render a validated scalar `const`/`enum` as `Literal[...]`, falling back to
|
|
172
|
+
* the broad type. Deliberately deviates from PEP 586, which restricts `Literal`
|
|
173
|
+
* parameters to int/bool/str/bytes/enum/None: a non-integral number
|
|
174
|
+
* `const`/`enum` emits a float literal (`Literal[1.5]`) a strict checker would
|
|
175
|
+
* reject. An integral one does not deviate — {@link pyScalar} emits int digits,
|
|
176
|
+
* including for the beyond-safe-range values it widens through `BigInt`, and
|
|
177
|
+
* PEP 586 admits int parameters. Harmless either way — the stub is advisory
|
|
178
|
+
* prompt text, only required to parse — and keeping the exact value
|
|
179
|
+
* communicates the constraint to the model.
|
|
180
|
+
*/
|
|
181
|
+
function renderConstrainedScalar(node, broad, state) {
|
|
182
|
+
if (node.const !== undefined) {
|
|
183
|
+
state.typing.add('Literal');
|
|
184
|
+
return `Literal[${pyScalar(node.const)}]`;
|
|
185
|
+
}
|
|
186
|
+
if (node.enum !== undefined) {
|
|
187
|
+
state.typing.add('Literal');
|
|
188
|
+
return `Literal[${node.enum.map(pyScalar).join(', ')}]`;
|
|
189
|
+
}
|
|
190
|
+
return broad;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Map one JSON-Schema node to a Python type expression, threading `state` to
|
|
194
|
+
* collect the `TypedDict` declarations and `typing` symbols a full render
|
|
195
|
+
* needs. `className` is the name to give an object node with properties (and
|
|
196
|
+
* the prefix for its nested objects). Handles every unified schema construct —
|
|
197
|
+
* `oneOf` (→ `X | Y`), `const`/`enum` (→ `Literal[...]`), `integer` (→ `int`),
|
|
198
|
+
* `null` (→ `None`) — and degrades an unsupported or malformed schema to `Any`
|
|
199
|
+
* without throwing, the same trusted-after-validation stance as the sibling
|
|
200
|
+
* {@link ./ts-types.ts | ts-types} renderer. `jsonSchemaToPy` is the
|
|
201
|
+
* context-free entry point; this is the collecting core.
|
|
202
|
+
*/
|
|
203
|
+
export function renderType(schema, className, state) {
|
|
204
|
+
const newFrame = (schema, className, listDepth) => ({ schema, className, phase: 'start', listDepth, children: [], childIndex: 0, childTypes: [], entries: [] });
|
|
205
|
+
try {
|
|
206
|
+
// Validate the WHOLE tree once, then trust it — the same contract the
|
|
207
|
+
// sibling ts-types renderer follows at a typed same-process boundary. Every
|
|
208
|
+
// node past this point is a validated JSON-schema node, so the walk reads
|
|
209
|
+
// its fields without re-checking. An unsupported or malformed schema throws
|
|
210
|
+
// here (before anything is emitted) and degrades to `Any`, the Python
|
|
211
|
+
// counterpart of the TS flavor's `unknown`.
|
|
212
|
+
assertSupportedJsonSchema(schema);
|
|
213
|
+
const frames = [newFrame(schema, className, 0)];
|
|
214
|
+
let result;
|
|
215
|
+
/* jscpd:ignore-start -- the explicit-stack walk skeleton deliberately parallels
|
|
216
|
+
ts-types.ts's renderSupportedSchema; the two sibling renderers keep symmetric shapes. */
|
|
217
|
+
const finish = (type) => {
|
|
218
|
+
frames.pop();
|
|
219
|
+
const parent = frames.at(-1);
|
|
220
|
+
if (parent === undefined)
|
|
221
|
+
result = type;
|
|
222
|
+
else
|
|
223
|
+
parent.childTypes.push(type);
|
|
224
|
+
};
|
|
225
|
+
while (frames.length > 0) {
|
|
226
|
+
const frame = frames.at(-1);
|
|
227
|
+
/* v8 ignore next -- the loop condition guarantees a current frame. */
|
|
228
|
+
if (frame === undefined)
|
|
229
|
+
break;
|
|
230
|
+
if (frame.phase === 'children') {
|
|
231
|
+
if (frame.childIndex < frame.children.length) {
|
|
232
|
+
const child = frame.children[frame.childIndex];
|
|
233
|
+
/* v8 ignore next -- childIndex is bounded by children.length. */
|
|
234
|
+
if (child === undefined)
|
|
235
|
+
throw new Error('missing python render child');
|
|
236
|
+
frame.childIndex++;
|
|
237
|
+
frames.push(newFrame(child.schema, child.className, child.listDepth));
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
if (frame.kind === 'oneOf') {
|
|
241
|
+
// Concatenate incrementally (template literal, not `Array.join`): V8
|
|
242
|
+
// builds a lazy ConsString, so a deep oneOf chain materializes once
|
|
243
|
+
// at the root instead of re-materializing the accumulated string at
|
|
244
|
+
// every level (which `join` would, making it Θ(depth²)). This matches
|
|
245
|
+
// the array arm's template-literal laziness and ts-types' composable-
|
|
246
|
+
// document approach — the whole walk stays linear in schema depth.
|
|
247
|
+
let union = '';
|
|
248
|
+
for (const [index, childType] of frame.childTypes.entries()) {
|
|
249
|
+
union = index === 0 ? childType : `${union} | ${childType}`;
|
|
250
|
+
}
|
|
251
|
+
finish(union);
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
/* jscpd:ignore-end */
|
|
255
|
+
if (frame.kind === 'array') {
|
|
256
|
+
// `list[A | B]` needs no parentheses in Python. Array frames always
|
|
257
|
+
// schedule exactly one child, so its type is present.
|
|
258
|
+
/* v8 ignore next -- the ?? arm needs a childless array frame, which start never builds. */
|
|
259
|
+
finish(`list[${frame.childTypes[0] ?? 'Any'}]`);
|
|
260
|
+
continue;
|
|
261
|
+
}
|
|
262
|
+
// typeddict: assemble AFTER the children so any nested class this one
|
|
263
|
+
// references is already declared (declaration order = reference order).
|
|
264
|
+
const node = frame.node;
|
|
265
|
+
const name = frame.allocated;
|
|
266
|
+
/* v8 ignore next -- typeddict frames always set node and allocated at start. */
|
|
267
|
+
if (node === undefined || name === undefined)
|
|
268
|
+
throw new Error('missing typeddict frame state');
|
|
269
|
+
const required = new Set(node.required);
|
|
270
|
+
const lines = [`class ${name}(TypedDict):`];
|
|
271
|
+
for (let index = 0; index < frame.entries.length; index++) {
|
|
272
|
+
const entry = frame.entries[index];
|
|
273
|
+
const fieldType = frame.childTypes[index];
|
|
274
|
+
/* v8 ignore next -- entries and childTypes correspond one-to-one. */
|
|
275
|
+
if (entry === undefined || fieldType === undefined)
|
|
276
|
+
throw new Error('missing typeddict field type');
|
|
277
|
+
const [field, fieldSchema] = entry;
|
|
278
|
+
// The parent node passed assertSupportedJsonSchema, so every property
|
|
279
|
+
// value is a validated schema node.
|
|
280
|
+
const description = describe(fieldSchema);
|
|
281
|
+
if (description !== undefined)
|
|
282
|
+
lines.push(`${pad(1)}# ${description}`);
|
|
283
|
+
if (required.has(field)) {
|
|
284
|
+
lines.push(`${pad(1)}${field}: ${fieldType}`);
|
|
285
|
+
}
|
|
286
|
+
else {
|
|
287
|
+
state.typing.add('NotRequired');
|
|
288
|
+
lines.push(`${pad(1)}${field}: NotRequired[${fieldType}]`);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
// TypedDict syntax cannot express openness, so an open object states it
|
|
292
|
+
// in-band: the annotation is advisory either way, and `mode: 'code'`
|
|
293
|
+
// omits the native schemas, making this line the model's only signal
|
|
294
|
+
// that extra keys are accepted.
|
|
295
|
+
if (node.additionalProperties !== false) {
|
|
296
|
+
lines.push(`${pad(1)}# Additional keys beyond those declared are allowed.`);
|
|
297
|
+
}
|
|
298
|
+
// A closed empty object still needs a class body (`pass`) to be valid
|
|
299
|
+
// Python; the declared emptiness is the information.
|
|
300
|
+
if (lines.length === 1)
|
|
301
|
+
lines.push(`${pad(1)}pass`);
|
|
302
|
+
state.classes.push(lines.join('\n'));
|
|
303
|
+
finish(name);
|
|
304
|
+
continue;
|
|
305
|
+
}
|
|
306
|
+
frame.phase = 'children';
|
|
307
|
+
const node = frame.schema;
|
|
308
|
+
if (node.oneOf !== undefined) {
|
|
309
|
+
frame.kind = 'oneOf';
|
|
310
|
+
// A union renders as `A | B` — no brackets of its own, so the branches
|
|
311
|
+
// inherit the enclosing depth unchanged.
|
|
312
|
+
//
|
|
313
|
+
// Union LENGTH is deliberately uncapped, unlike list nesting. The two
|
|
314
|
+
// limits are different in kind: >200 open brackets is a SyntaxError
|
|
315
|
+
// from the tokenizer, so the text is not Python; a long `A | B | …`
|
|
316
|
+
// chain is grammatically valid at any length and only defeats CPython's
|
|
317
|
+
// C-recursion when `compile()` walks the left-nested BinOp spine
|
|
318
|
+
// (measured: 1,000 branches compile, 5,000 raise RecursionError). This
|
|
319
|
+
// block is prompt text — nothing compiles it — so that limit costs
|
|
320
|
+
// nothing here, while capping would retire the deep-chain tests that
|
|
321
|
+
// pin the walk's linear time and the class-name propagation cap. The
|
|
322
|
+
// standard this renderer holds is grammatical validity, not
|
|
323
|
+
// compilability under one interpreter's stack.
|
|
324
|
+
frame.children = node.oneOf.map((branch, index) => ({ schema: branch, className: childClassName(frame.className, `${index + 1}`), listDepth: frame.listDepth }));
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
if (node.type === undefined) {
|
|
328
|
+
state.typing.add('Any');
|
|
329
|
+
finish('Any');
|
|
330
|
+
continue;
|
|
331
|
+
}
|
|
332
|
+
switch (node.type) {
|
|
333
|
+
case 'string':
|
|
334
|
+
finish(renderConstrainedScalar(node, 'str', state));
|
|
335
|
+
break;
|
|
336
|
+
case 'number':
|
|
337
|
+
finish(renderConstrainedScalar(node, 'float', state));
|
|
338
|
+
break;
|
|
339
|
+
case 'integer':
|
|
340
|
+
finish(renderConstrainedScalar(node, 'int', state));
|
|
341
|
+
break;
|
|
342
|
+
case 'boolean':
|
|
343
|
+
finish(renderConstrainedScalar(node, 'bool', state));
|
|
344
|
+
break;
|
|
345
|
+
case 'null':
|
|
346
|
+
finish('None');
|
|
347
|
+
break;
|
|
348
|
+
case 'array': {
|
|
349
|
+
if (node.items === undefined) {
|
|
350
|
+
state.typing.add('Any');
|
|
351
|
+
finish('list[Any]');
|
|
352
|
+
break;
|
|
353
|
+
}
|
|
354
|
+
// Past MAX_LIST_NESTING another `list[` would push the annotation
|
|
355
|
+
// beyond CPython's open-bracket limit and make the whole SDK block
|
|
356
|
+
// unparseable, so the chain degrades here instead — an unusable
|
|
357
|
+
// annotation either way, and this one is valid Python.
|
|
358
|
+
if (frame.listDepth >= MAX_LIST_NESTING) {
|
|
359
|
+
state.typing.add('Any');
|
|
360
|
+
finish('Any');
|
|
361
|
+
break;
|
|
362
|
+
}
|
|
363
|
+
// An array of objects names its item type after the array field.
|
|
364
|
+
frame.kind = 'array';
|
|
365
|
+
frame.children = [{ schema: node.items, className: frame.className, listDepth: frame.listDepth + 1 }];
|
|
366
|
+
break;
|
|
367
|
+
}
|
|
368
|
+
case 'object': {
|
|
369
|
+
// A missing `properties` is an empty property map, exactly as the
|
|
370
|
+
// unified validator and the TS renderer read it — NOT an unknown
|
|
371
|
+
// shape. The openness of the resulting empty object is decided below,
|
|
372
|
+
// so a closed empty object still declares an empty TypedDict rather
|
|
373
|
+
// than a permissive `dict[str, Any]`.
|
|
374
|
+
const entries = Object.entries(node.properties ?? {});
|
|
375
|
+
// An empty `className` marks the context-free `jsonSchemaToPy` entry:
|
|
376
|
+
// there is no naming context to declare into, so degrade. This reads
|
|
377
|
+
// the CALL's className, not `frame.className`: the marker belongs to
|
|
378
|
+
// the whole walk, and frames propagate a derived name (a `oneOf`
|
|
379
|
+
// branch of the context-free root gets the index-derived name `1` —
|
|
380
|
+
// `childClassName` concatenates and caps, it does not go through
|
|
381
|
+
// `camelCase`), so a per-frame read would declare classes the caller
|
|
382
|
+
// has no way to receive, under a name that is not even a legal
|
|
383
|
+
// identifier: `class 1(TypedDict):`. A field
|
|
384
|
+
// name that is not a legal Python attribute is inexpressible as a
|
|
385
|
+
// class-syntax `TypedDict` field, so such an object degrades whole.
|
|
386
|
+
// A leading-double-underscore non-dunder field (`__token`) would be
|
|
387
|
+
// NAME-MANGLED inside class syntax (`_ClassName__token`), describing a
|
|
388
|
+
// different JSON key than the registered schema — degrade like any
|
|
389
|
+
// other inexpressible field name.
|
|
390
|
+
if (className === '' || !entries.every(([name]) => isBareIdentifier(name) && !RESERVED.has(name) && !(name.startsWith('__') && !name.endsWith('__')))) {
|
|
391
|
+
state.typing.add('Any');
|
|
392
|
+
finish('dict[str, Any]');
|
|
393
|
+
break;
|
|
394
|
+
}
|
|
395
|
+
// An OPEN empty object is any dict; a CLOSED empty object declares an
|
|
396
|
+
// empty TypedDict so "no keys accepted" survives into the SDK.
|
|
397
|
+
if (entries.length === 0 && node.additionalProperties !== false) {
|
|
398
|
+
state.typing.add('Any');
|
|
399
|
+
finish('dict[str, Any]');
|
|
400
|
+
break;
|
|
401
|
+
}
|
|
402
|
+
frame.kind = 'typeddict';
|
|
403
|
+
frame.node = node;
|
|
404
|
+
frame.allocated = allocateClassName(frame.className, state);
|
|
405
|
+
state.typing.add('TypedDict');
|
|
406
|
+
frame.entries = entries;
|
|
407
|
+
// A field annotation is its own logical line, so nesting restarts —
|
|
408
|
+
// at 1, reserving the bracket an optional field's `NotRequired[…]`
|
|
409
|
+
// wraps around it. frame.allocated was assigned three statements up;
|
|
410
|
+
// the ?? arm is for the type system only.
|
|
411
|
+
/* v8 ignore next -- allocated is always set before children are built. */
|
|
412
|
+
frame.children = entries.map(([field, child]) => ({ schema: child, className: childClassName(frame.allocated ?? '', camelCase(field)), listDepth: 1 }));
|
|
413
|
+
break;
|
|
414
|
+
}
|
|
415
|
+
/* v8 ignore next 4 -- assertSupportedJsonSchema narrowed this closed type union. */
|
|
416
|
+
default: {
|
|
417
|
+
state.typing.add('Any');
|
|
418
|
+
finish('Any');
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
/* v8 ignore next -- every root frame produces one expression. */
|
|
423
|
+
return result ?? 'Any';
|
|
424
|
+
}
|
|
425
|
+
catch {
|
|
426
|
+
// An unsupported or malformed schema failed validation (before any
|
|
427
|
+
// emission), or an unreachable internal invariant tripped. Either degrades
|
|
428
|
+
// the node to `Any` rather than crashing prompt assembly — the Python
|
|
429
|
+
// counterpart of the TS flavor's `unknown` fallback.
|
|
430
|
+
state.typing.add('Any');
|
|
431
|
+
return 'Any';
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
//# sourceMappingURL=py-render.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"py-render.js","sourceRoot":"","sources":["../src/py-render.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Python SDK document renderer: `renderToolsSdkPy`, the `tools:sdk` prompt
|
|
3
|
+
* section rendered under `runtime.language === 'python'` — the fixed usage
|
|
4
|
+
* instructions plus one named `TypedDict` per tool argument or output object
|
|
5
|
+
* and one awaitable method per visible tool on a `Tools` protocol. Split out
|
|
6
|
+
* of `py-types.ts` for the line budget; re-exported from `py-types.ts`.
|
|
7
|
+
* @module @dsh-cc/tools/src/py-sdk-doc
|
|
8
|
+
*/
|
|
9
|
+
import type { ToolSdkSchema } from './ts-types.ts';
|
|
10
|
+
/**
|
|
11
|
+
* Render the full `tools:sdk` prompt section under `runtime.language ===
|
|
12
|
+
* 'python'`: the Python-flavored usage instructions plus one named `TypedDict`
|
|
13
|
+
* per tool argument or output object (and per nested object) and one awaitable
|
|
14
|
+
* method per visible tool on a `Tools` protocol — typed args in, the tool's
|
|
15
|
+
* canonical output value out — with a `tools: Tools` singleton the model calls
|
|
16
|
+
* into. The `typing` import line lists exactly the symbols the render used.
|
|
17
|
+
* Deterministic — tools are emitted in lexicographic name order, and class
|
|
18
|
+
* declarations precede the protocol in that same order (nested classes before
|
|
19
|
+
* the parent that references them), so an unchanged tool set produces
|
|
20
|
+
* byte-identical text across assemblies. The sort is not a total order on
|
|
21
|
+
* byte-equal names, so two schemas sharing a name would render in argument
|
|
22
|
+
* order; the caller's visible-capability map is keyed by name, so the input
|
|
23
|
+
* never carries a duplicate.
|
|
24
|
+
* @param schemas - the tool schemas plus canonical output schemas to declare
|
|
25
|
+
* (the caller excludes `run_code` itself).
|
|
26
|
+
* @returns the complete section text.
|
|
27
|
+
*/
|
|
28
|
+
export declare function renderToolsSdkPy(schemas: ToolSdkSchema[]): string;
|
|
29
|
+
//# sourceMappingURL=py-sdk-doc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"py-sdk-doc.d.ts","sourceRoot":"","sources":["../src/py-sdk-doc.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAA;AAkClD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,MAAM,CAuDjE"}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The Python SDK document renderer: `renderToolsSdkPy`, the `tools:sdk` prompt
|
|
3
|
+
* section rendered under `runtime.language === 'python'` — the fixed usage
|
|
4
|
+
* instructions plus one named `TypedDict` per tool argument or output object
|
|
5
|
+
* and one awaitable method per visible tool on a `Tools` protocol. Split out
|
|
6
|
+
* of `py-types.ts` for the line budget; re-exported from `py-types.ts`.
|
|
7
|
+
* @module @dsh-cc/tools/src/py-sdk-doc
|
|
8
|
+
*/
|
|
9
|
+
import { describe, camelCase, isBareIdentifier, pad, RESERVED } from "./py-names.js";
|
|
10
|
+
import { renderType } from "./py-render.js";
|
|
11
|
+
/** `typing` symbols this module may emit, in the deterministic import order. */
|
|
12
|
+
const TYPING_ORDER = ['Any', 'Literal', 'NotRequired', 'Protocol', 'TypedDict'];
|
|
13
|
+
/**
|
|
14
|
+
* One-line docstring for a tool `description`, or no lines when there is none.
|
|
15
|
+
* Backslashes are doubled first, every quote is escaped, and a trailing
|
|
16
|
+
* backslash cannot survive: a description ending in `"` or an odd backslash
|
|
17
|
+
* would otherwise merge with (or escape) the closing triple quote and make
|
|
18
|
+
* the generated block — Code Mode's only SDK — syntactically invalid Python.
|
|
19
|
+
*/
|
|
20
|
+
function docLines(description, indent) {
|
|
21
|
+
const collapsed = describe({ description });
|
|
22
|
+
if (collapsed === undefined)
|
|
23
|
+
return [];
|
|
24
|
+
const escaped = collapsed.replaceAll('\\', '\\\\').replaceAll('"', '\\"');
|
|
25
|
+
return [`${pad(indent)}"""${escaped}"""`];
|
|
26
|
+
}
|
|
27
|
+
/** The fixed model-facing usage contract rendered above the declarations. */
|
|
28
|
+
const SDK_INSTRUCTIONS = `## Writing code for run_code
|
|
29
|
+
|
|
30
|
+
\`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:
|
|
31
|
+
|
|
32
|
+
- 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.
|
|
33
|
+
- 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.
|
|
34
|
+
- Independent read-only calls MAY overlap under \`asyncio.gather\` (safe calls run concurrently; mutating calls run alone, in submission order). Sequence dependent work with \`await\`.
|
|
35
|
+
- Emit the run's answer with \`print(...)\` and/or a top-level \`return <value>\`; the returned value must be lossless JSON. ONLY what you print and the returned value come back — intermediate tool results never enter the conversation, so extract just what you need.
|
|
36
|
+
|
|
37
|
+
The available tools:`;
|
|
38
|
+
/**
|
|
39
|
+
* Render the full `tools:sdk` prompt section under `runtime.language ===
|
|
40
|
+
* 'python'`: the Python-flavored usage instructions plus one named `TypedDict`
|
|
41
|
+
* per tool argument or output object (and per nested object) and one awaitable
|
|
42
|
+
* method per visible tool on a `Tools` protocol — typed args in, the tool's
|
|
43
|
+
* canonical output value out — with a `tools: Tools` singleton the model calls
|
|
44
|
+
* into. The `typing` import line lists exactly the symbols the render used.
|
|
45
|
+
* Deterministic — tools are emitted in lexicographic name order, and class
|
|
46
|
+
* declarations precede the protocol in that same order (nested classes before
|
|
47
|
+
* the parent that references them), so an unchanged tool set produces
|
|
48
|
+
* byte-identical text across assemblies. The sort is not a total order on
|
|
49
|
+
* byte-equal names, so two schemas sharing a name would render in argument
|
|
50
|
+
* order; the caller's visible-capability map is keyed by name, so the input
|
|
51
|
+
* never carries a duplicate.
|
|
52
|
+
* @param schemas - the tool schemas plus canonical output schemas to declare
|
|
53
|
+
* (the caller excludes `run_code` itself).
|
|
54
|
+
* @returns the complete section text.
|
|
55
|
+
*/
|
|
56
|
+
export function renderToolsSdkPy(schemas) {
|
|
57
|
+
const sorted = [...schemas].sort((a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0);
|
|
58
|
+
const state = { classes: [], usedClassNames: new Set(), nextClassCounter: new Map(), typing: new Set(['Protocol']) };
|
|
59
|
+
// ONE ordered member stream, matching the documented lexicographic contract
|
|
60
|
+
// and the TypeScript flavor (which quotes exotic keys in place rather than
|
|
61
|
+
// partitioning them out). Interleaving is free here: a comment line between
|
|
62
|
+
// two `async def` lines is not a statement, so it changes nothing about how
|
|
63
|
+
// the class body parses.
|
|
64
|
+
const members = [];
|
|
65
|
+
let statements = 0;
|
|
66
|
+
for (const schema of sorted) {
|
|
67
|
+
const argType = renderType(schema.parameters, `${camelCase(schema.name)}Args`, state);
|
|
68
|
+
const outputType = renderType(schema.output, `${camelCase(schema.name)}Output`, state);
|
|
69
|
+
if (isBareIdentifier(schema.name) && !RESERVED.has(schema.name) && !schema.name.startsWith('_')) {
|
|
70
|
+
// A docstring only documents its method when it is the FIRST statement
|
|
71
|
+
// of that method's body. Emitted before the `async def` it would instead
|
|
72
|
+
// become the `Tools` class docstring (for the first tool) or a dead
|
|
73
|
+
// expression (for every later one), leaving every method undocumented —
|
|
74
|
+
// and under `mode: 'code'` this SDK is the model's only description of
|
|
75
|
+
// what a tool does. A docstring is a complete body, so the `...` stub is
|
|
76
|
+
// only for the description-less case.
|
|
77
|
+
const doc = docLines(schema.description, 2);
|
|
78
|
+
members.push(doc.length > 0
|
|
79
|
+
? `${pad(1)}async def ${schema.name}(self, args: ${argType}) -> ${outputType}:`
|
|
80
|
+
: `${pad(1)}async def ${schema.name}(self, args: ${argType}) -> ${outputType}: ...`);
|
|
81
|
+
members.push(...doc);
|
|
82
|
+
statements += 1;
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
// Not reachable as ``tools.name`` — the model reaches it via
|
|
86
|
+
// ``tools[name]``. Exotic names and hard keywords are not legal
|
|
87
|
+
// attributes at all; an underscore-leading name (``_foo``) IS a legal
|
|
88
|
+
// attribute and is routed here anyway, because the forms that break
|
|
89
|
+
// split three ways — a non-dunder ``__token`` name-mangles at the CALL
|
|
90
|
+
// site, a dunder that exists on ``object``/``type`` (``__class__``,
|
|
91
|
+
// ``__doc__``) resolves before ``__getattr__`` ever runs, and implicit
|
|
92
|
+
// special-method lookup skips the hook entirely — and one rule over the
|
|
93
|
+
// whole family costs nothing while a per-form rule would have to
|
|
94
|
+
// enumerate them (see {@link RESERVED}). The stub lists it as a subscript comment
|
|
95
|
+
// (referencing the named TypedDicts too) so a reader sees what is
|
|
96
|
+
// accessible; runtime resolution goes through the proxy's __getitem__.
|
|
97
|
+
members.push(`${pad(1)}# tools[${JSON.stringify(schema.name)}](args: ${argType}) -> ${outputType}`);
|
|
98
|
+
const description = describe(schema);
|
|
99
|
+
if (description !== undefined)
|
|
100
|
+
members.push(`${pad(1)}# ${description}`);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// Subscript entries are COMMENTS, not statements: a class body of only
|
|
104
|
+
// comments fails to parse, so `pass` is required whenever no method was
|
|
105
|
+
// emitted — including the subscript-only tool set.
|
|
106
|
+
const bodyLines = statements > 0 ? members : [`${pad(1)}pass`, ...members];
|
|
107
|
+
const body = bodyLines.join('\n');
|
|
108
|
+
const imports = TYPING_ORDER.filter(symbol => state.typing.has(symbol));
|
|
109
|
+
const classBlock = state.classes.length > 0 ? `${state.classes.join('\n\n')}\n\n` : '';
|
|
110
|
+
const errorDeclaration = 'class ToolCallError(Exception):\n toolName: str';
|
|
111
|
+
const declaration = `from typing import ${imports.join(', ')}\n\n${errorDeclaration}\n\n${classBlock}class Tools(Protocol):\n${body}\n\ntools: Tools`;
|
|
112
|
+
return `${SDK_INSTRUCTIONS}\n\n\`\`\`python\n${declaration}\n\`\`\``;
|
|
113
|
+
}
|
|
114
|
+
//# sourceMappingURL=py-sdk-doc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"py-sdk-doc.js","sourceRoot":"","sources":["../src/py-sdk-doc.ts"],"names":[],"mappings":"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"}
|