From a1d7b9a3cd864d56e7d015bedc8fbf73709736f9 Mon Sep 17 00:00:00 2001 From: Chinesezjc Date: Wed, 5 Aug 2026 14:05:02 +0800 Subject: [PATCH] fix(tools): treat a whitespace-only description as absent in the Python SDK It collapsed to '' rather than undefined, so the renderer emitted an empty `""""""` docstring or a bare `# ` line for a node that documents nothing. --- packages/core/tools/src/py-types.ts | 10 +++++++--- packages/core/tools/tests/py-types.spec.ts | 7 +++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/core/tools/src/py-types.ts b/packages/core/tools/src/py-types.ts index 9f08d4dc3f..26deed174f 100644 --- a/packages/core/tools/src/py-types.ts +++ b/packages/core/tools/src/py-types.ts @@ -82,7 +82,10 @@ const UNPRINTABLE = /[\u0000-\u0008\u000e-\u001f\u007f]/g * The collapsed one-line `description` of a schema node (byte-stable across * formatting churn), or `undefined` when the node carries none. Every caller * passes an object (validated property nodes, or the ToolSdkSchema itself), - * so only the description field needs guarding. + * so only the description field needs guarding. A description that collapses + * to nothing (empty, or whitespace only) is `undefined` too: it documents the + * node no better than an absent one, and emitting it would leave an empty + * `"""` docstring or a bare `# ` line in the SDK. * * Control characters left over after the whitespace collapse are rendered as * their `\xNN` escapes (see {@link UNPRINTABLE}); the escape's own backslash is @@ -91,11 +94,12 @@ const UNPRINTABLE = /[\u0000-\u0008\u000e-\u001f\u007f]/g */ function describe(schema: object): string | undefined { const description = (schema as Record).description - if (typeof description !== 'string' || description.length === 0) return undefined - return description + if (typeof description !== 'string') return undefined + const collapsed = description .replace(/\s+/g, ' ') .replace(UNPRINTABLE, char => `\\x${char.charCodeAt(0).toString(16).padStart(2, '0')}`) .trim() + return collapsed.length === 0 ? undefined : collapsed } /** diff --git a/packages/core/tools/tests/py-types.spec.ts b/packages/core/tools/tests/py-types.spec.ts index deb2bb6cd1..5a4b7f625a 100644 --- a/packages/core/tools/tests/py-types.spec.ts +++ b/packages/core/tools/tests/py-types.spec.ts @@ -464,6 +464,13 @@ describe('renderToolsSdkPy', () => { // Subscript entry appears without the "# ..." description follow-up. expect(text).toContain('# tools["weird-name"]') expect(text.split('\n').every(line => !line.startsWith(' # '))).toBe(true) + // A whitespace-only description collapses to nothing and is treated as + // absent: no empty `""""""` docstring, no bare `# ` line. + const blank = renderToolsSdkPy([ + { ...undescribedIdentifier, description: ' \t\n ' }, + { ...undescribedExotic, description: ' ' }, + ]) + expect(blank).toBe(text) }) it('marks an open object TypedDict and declares a closed empty object', () => {