fix(tools): correct Python SDK fidelity and language-dispatch contract
Address ds-review-bot v5/v6 review on the Python SDK renderer:
- resolveFlavor now takes a peekRuntime() reader: undefined (no runtime,
the doc-catalog harvest) degrades to the TS flavor, but a mounted
runtime whose language is absent from RUN_CODE_FLAVORS fails loud. This
removes the try/catch that silently swallowed the invalid-language path
and drops the /* v8 ignore */ that hid the flavor guard from coverage;
wireSchemas validates the runtime before projecting schemas so the
renderer-table rejection stays the canonical assembly error.
- py-types RESERVED drops the soft keywords match/case: they are legal as
TypedDict fields and methods, so keeping them needlessly degraded
common search/regex arg objects to dict[str, Any].
- py-types treats an object with omitted properties as {} like the unified
validator and TS renderer do, so a closed empty object declares an empty
TypedDict instead of a permissive dict[str, Any].
- README: symmetric jsonSchemaToPy->Any note; a stale zh SDK bullet and
limitation corrected; link the service-wide-language limitation to its
Agent Note.
This commit is contained in:
@@ -373,13 +373,27 @@ describe('mode-aware wire contribution', () => {
|
||||
expect(codeParam.description).toBe('The program: the body of an async Python function.')
|
||||
})
|
||||
|
||||
it('fails loud when the runtime language has no run_code schema flavor', async () => {
|
||||
// A language with an SDK renderer registered but (hypothetically) no schema
|
||||
// flavor would fail here; a language with neither fails earlier at
|
||||
// requireCodeRuntime. Both guards keep the two tables coupled.
|
||||
const { ctx, systemPrompt } = await setup({ mode: 'code', runtime: { language: 'ruby' } })
|
||||
registerEcho(ctx)
|
||||
await expect(systemPrompt.assemble()).rejects.toThrow(/no SDK renderer registered for runtime language "ruby"/)
|
||||
it('resolves the run_code schema flavor lazily and fails loud on a language absent from the flavor table', async () => {
|
||||
// The flavor getter reads the runtime directly (peekRuntime), so it — not
|
||||
// requireCodeRuntime — owns the flavor-table guard. A language with no
|
||||
// flavor entry throws when the schema is projected, keeping
|
||||
// RUN_CODE_FLAVORS coupled to SDK_RENDERERS. Assembly's requireCodeRuntime
|
||||
// rejects such a language earlier; this reaches the guard on its own.
|
||||
const { ctx } = await setup({ mode: 'code', runtime: { language: 'ruby' } })
|
||||
const definition = ctx.tools.get(RUN_CODE_NAME)
|
||||
expect(() => definition?.description).toThrow(/no run_code schema flavor registered for runtime language "ruby"/)
|
||||
})
|
||||
|
||||
it('degrades the run_code flavor to TypeScript when no runtime is mounted (doc-catalog schema harvest)', async () => {
|
||||
// The tool-catalog generator boots the registry under `mode: code` and
|
||||
// reads run_code's schema WITHOUT a runtime; peekRuntime returns undefined
|
||||
// there, so the flavor getter degrades to the TS default rather than
|
||||
// throwing (that harvest never feeds a model).
|
||||
const { ctx } = await setup({ mode: 'code', runtime: false })
|
||||
const definition = ctx.tools.get(RUN_CODE_NAME)
|
||||
expect(definition?.description).toContain('Execute a TypeScript program')
|
||||
const params = definition?.parameters as { properties: { code: { description: string } } }
|
||||
expect(params.properties.code.description).toBe('The program: the body of an async TypeScript function.')
|
||||
})
|
||||
|
||||
it("rejects the assembly when toolOrder names a native tool that mode 'code' no longer contributes", async () => {
|
||||
|
||||
Reference in New Issue
Block a user