From 631d3f930e17703050344ad4cf7b6a0524afbd10 Mon Sep 17 00:00:00 2001 From: Chinesezjc Date: Thu, 6 Aug 2026 02:22:51 +0800 Subject: [PATCH] test(tools): escape U+200C in the new case and name both carriers of the 15.1 requirement The file's convention is a \uXXXX escape for a character with no visible width (\u0301, \u1100, \u1161, \ud800 are all written that way) and a literal only for a visible one; the new case wrote nine raw ZWNJ. The comment also named only the field as needing 15.1 tables. Two emitted code positions do: the bare field, once in each class, and the Tool\u200CbArgs class name. The subscript comment is not one. --- packages/core/tools/tests/py-types.spec.ts | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/packages/core/tools/tests/py-types.spec.ts b/packages/core/tools/tests/py-types.spec.ts index 7a3a573349..56c0fc2274 100644 --- a/packages/core/tools/tests/py-types.spec.ts +++ b/packages/core/tools/tests/py-types.spec.ts @@ -476,23 +476,25 @@ describe('renderToolsSdkPy', () => { // docstring's four other characters record, reached in a tail position // instead of at a head: CPython reads XID_Continue out of the // `DerivedCoreProperties.txt` of the UCD it was built against (13.0.0 on - // 3.9.6 and 15.0.0 on 3.12.13 both lack the row, and `'a‌b'.isidentifier()` - // is False on both, measured), so the field emitted bare here needs an - // interpreter with 15.1 tables or newer. + // 3.9.6 and 15.0.0 on 3.12.13 both lack the row, and + // `'a\u200Cb'.isidentifier()` is False on both, measured). Two emitted + // positions then need 15.1 tables or newer: the bare field, once in each + // class, and the `Tool\u200CbArgs` class name. The subscript comment + // quoting the tool name is not one: it is not parsed as an identifier. const of = (name: string): ToolSdkSchema => ({ name, description: `Tool ${name}.`, - parameters: { type: 'object', additionalProperties: false, properties: { 'a‌b': { type: 'string' } } }, + parameters: { type: 'object', additionalProperties: false, properties: { 'a\u200Cb': { type: 'string' } } }, output: { type: 'string' }, }) - const text = renderToolsSdkPy([of('ping'), of('‌b')]) + const text = renderToolsSdkPy([of('ping'), of('\u200Cb')]) expect(text).toContain('async def ping(self, args: PingArgs) -> str:') - expect(text).toContain(' a‌b: NotRequired[str]') + expect(text).toContain(' a\u200Cb: NotRequired[str]') // A head that is XID_Continue but not XID_Start takes the subscript path, // and `camelCase` prefixes `Tool` to make the class name start legally. - expect(text).toContain('# tools["‌b"](args: Tool‌bArgs) -> str') - expect(text).toContain('class Tool‌bArgs(TypedDict):') - expect(text).not.toContain('async def ‌b') + expect(text).toContain('# tools["\u200Cb"](args: Tool\u200CbArgs) -> str') + expect(text).toContain('class Tool\u200CbArgs(TypedDict):') + expect(text).not.toContain('async def \u200Cb') }) it('subscripts a tool name that NFKC-normalizes to something else, while declaring a plain Unicode one', () => {