@caupulican/pi-ai 0.81.13 → 0.81.16
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/dist/models.generated.d.ts +34 -0
- package/dist/models.generated.d.ts.map +1 -1
- package/dist/models.generated.js +36 -2
- package/dist/models.generated.js.map +1 -1
- package/dist/providers/openai-completions.d.ts +1 -0
- package/dist/providers/openai-completions.d.ts.map +1 -1
- package/dist/providers/openai-completions.js +22 -1
- package/dist/providers/openai-completions.js.map +1 -1
- package/dist/stream.d.ts.map +1 -1
- package/dist/stream.js +67 -16
- package/dist/stream.js.map +1 -1
- package/dist/utils/tool-repair/analyzer.d.ts.map +1 -1
- package/dist/utils/tool-repair/analyzer.js +2 -0
- package/dist/utils/tool-repair/analyzer.js.map +1 -1
- package/dist/utils/tool-repair/registry.d.ts +1 -1
- package/dist/utils/tool-repair/registry.d.ts.map +1 -1
- package/dist/utils/tool-repair/registry.js +12 -0
- package/dist/utils/tool-repair/registry.js.map +1 -1
- package/dist/utils/tool-repair/repairer.d.ts.map +1 -1
- package/dist/utils/tool-repair/repairer.js +99 -12
- package/dist/utils/tool-repair/repairer.js.map +1 -1
- package/dist/utils/tool-repair/text-protocol.d.ts +2 -2
- package/dist/utils/tool-repair/text-protocol.d.ts.map +1 -1
- package/dist/utils/tool-repair/text-protocol.js +346 -22
- package/dist/utils/tool-repair/text-protocol.js.map +1 -1
- package/dist/utils/validation.d.ts +1 -0
- package/dist/utils/validation.d.ts.map +1 -1
- package/dist/utils/validation.js +3 -0
- package/dist/utils/validation.js.map +1 -1
- package/package.json +1 -1
package/dist/stream.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stream.js","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"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","sourcesContent":["import \"./providers/register-builtins.ts\";\n\nimport { getApiProvider } from \"./api-registry.ts\";\nimport { getEnvApiKey } from \"./env-api-keys.ts\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tContext,\n\tModel,\n\tProviderStreamOptions,\n\tSimpleStreamOptions,\n\tStreamOptions,\n\tTextToolProtocolParseEvent,\n} from \"./types.ts\";\nimport { AssistantMessageEventStream } from \"./utils/event-stream.ts\";\nimport {\n\tgenerateTextToolProtocolPrimer,\n\tnormalizeTextToolProtocolOptions,\n\tparseTextToolCalls,\n} from \"./utils/tool-repair/text-protocol.ts\";\n\nexport { getEnvApiKey } from \"./env-api-keys.ts\";\n\nfunction hasExplicitApiKey(apiKey: string | undefined): apiKey is string {\n\treturn typeof apiKey === \"string\" && apiKey.trim().length > 0;\n}\n\nfunction withEnvApiKey<TOptions extends StreamOptions>(\n\tmodel: Model<Api>,\n\toptions: TOptions | undefined,\n): TOptions | undefined {\n\tif (hasExplicitApiKey(options?.apiKey)) return options;\n\tconst apiKey = getEnvApiKey(model.provider);\n\tif (!apiKey) return options;\n\treturn { ...options, apiKey } as TOptions;\n}\n\nfunction withTextToolProtocolContext(context: Context, options: StreamOptions | undefined): Context {\n\tconst protocolOptions = normalizeTextToolProtocolOptions(options?.textToolCallProtocol);\n\tif (!protocolOptions || !context.tools?.length) return context;\n\tconst primer = generateTextToolProtocolPrimer(context.tools, protocolOptions);\n\tif (!primer) return context;\n\treturn {\n\t\t...context,\n\t\tsystemPrompt: context.systemPrompt ? `${context.systemPrompt}\\n\\n${primer}` : primer,\n\t};\n}\n\nasync function notifyTextToolProtocolParse(\n\toptions: StreamOptions | undefined,\n\tevent: TextToolProtocolParseEvent,\n): Promise<void> {\n\ttry {\n\t\tawait options?.onTextToolProtocolParse?.(event);\n\t} catch {\n\t\t// Parse telemetry must not change provider stream semantics.\n\t}\n}\n\nfunction withTextToolProtocolResult(\n\tstream: AssistantMessageEventStream,\n\tmodel: Model<Api>,\n\tcontext: Context,\n\toptions: StreamOptions | undefined,\n): AssistantMessageEventStream {\n\tconst protocolOptions = normalizeTextToolProtocolOptions(options?.textToolCallProtocol);\n\tif (!protocolOptions || !context.tools?.length) return stream;\n\tconst wrapped = new AssistantMessageEventStream();\n\tvoid (async () => {\n\t\tfor await (const event of stream) {\n\t\t\tif (event.type !== \"done\") {\n\t\t\t\twrapped.push(event);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst message = event.message;\n\t\t\tif (message.content.length !== 1 || message.content[0]?.type !== \"text\") {\n\t\t\t\twrapped.push(event);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst text = message.content[0].text;\n\t\t\tconst parsed = parseTextToolCalls(text, context.tools ?? []);\n\t\t\tif (parsed.calls.length === 0) {\n\t\t\t\tif (parsed.failure) {\n\t\t\t\t\tawait notifyTextToolProtocolParse(options, {\n\t\t\t\t\t\tprovider: model.provider,\n\t\t\t\t\t\tmodel: model.id,\n\t\t\t\t\t\tvariant: protocolOptions.variant ?? \"tool-tag\",\n\t\t\t\t\t\tstatus: \"failed\",\n\t\t\t\t\t\tcallCount: 0,\n\t\t\t\t\t\ttextLength: text.length,\n\t\t\t\t\t\treason: parsed.failure,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\twrapped.push(event);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tawait notifyTextToolProtocolParse(options, {\n\t\t\t\tprovider: model.provider,\n\t\t\t\tmodel: model.id,\n\t\t\t\tvariant: protocolOptions.variant ?? \"tool-tag\",\n\t\t\t\tstatus: \"parsed\",\n\t\t\t\tcallCount: parsed.calls.length,\n\t\t\t\ttextLength: text.length,\n\t\t\t});\n\t\t\tconst content = parsed.text ? [{ type: \"text\" as const, text: parsed.text }, ...parsed.calls] : parsed.calls;\n\t\t\twrapped.push({\n\t\t\t\ttype: \"done\",\n\t\t\t\treason: \"toolUse\",\n\t\t\t\tmessage: { ...message, content, stopReason: \"toolUse\" },\n\t\t\t});\n\t\t}\n\t})();\n\treturn wrapped;\n}\n\nfunction resolveApiProvider(api: Api) {\n\tconst provider = getApiProvider(api);\n\tif (!provider) {\n\t\tthrow new Error(`No API provider registered for api: ${api}`);\n\t}\n\treturn provider;\n}\n\nexport function stream<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: ProviderStreamOptions,\n): AssistantMessageEventStream {\n\tconst provider = resolveApiProvider(model.api);\n\tconst resolvedOptions = withEnvApiKey(model, options) as StreamOptions;\n\tconst protocolContext = withTextToolProtocolContext(context, resolvedOptions);\n\treturn withTextToolProtocolResult(\n\t\tprovider.stream(model, protocolContext, resolvedOptions),\n\t\tmodel,\n\t\tprotocolContext,\n\t\tresolvedOptions,\n\t);\n}\n\nexport async function complete<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: ProviderStreamOptions,\n): Promise<AssistantMessage> {\n\tconst s = stream(model, context, options);\n\treturn s.result();\n}\n\nexport function streamSimple<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream {\n\tconst provider = resolveApiProvider(model.api);\n\tconst resolvedOptions = withEnvApiKey(model, options);\n\tconst protocolContext = withTextToolProtocolContext(context, resolvedOptions);\n\treturn withTextToolProtocolResult(\n\t\tprovider.streamSimple(model, protocolContext, resolvedOptions),\n\t\tmodel,\n\t\tprotocolContext,\n\t\tresolvedOptions,\n\t);\n}\n\nexport async function completeSimple<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): Promise<AssistantMessage> {\n\tconst s = streamSimple(model, context, options);\n\treturn s.result();\n}\n"]}
|
|
1
|
+
{"version":3,"file":"stream.js","sourceRoot":"","sources":["../src/stream.ts"],"names":[],"mappings":"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","sourcesContent":["import \"./providers/register-builtins.ts\";\n\nimport { getApiProvider } from \"./api-registry.ts\";\nimport { getEnvApiKey } from \"./env-api-keys.ts\";\nimport type {\n\tApi,\n\tAssistantMessage,\n\tContext,\n\tMessage,\n\tModel,\n\tProviderStreamOptions,\n\tSimpleStreamOptions,\n\tStreamOptions,\n\tTextToolProtocolParseEvent,\n} from \"./types.ts\";\nimport { AssistantMessageEventStream } from \"./utils/event-stream.ts\";\nimport {\n\tgenerateTextToolProtocolPrimer,\n\tnormalizeTextToolProtocolOptions,\n\tparseTextToolCalls,\n} from \"./utils/tool-repair/text-protocol.ts\";\n\nexport { getEnvApiKey } from \"./env-api-keys.ts\";\n\nfunction hasExplicitApiKey(apiKey: string | undefined): apiKey is string {\n\treturn typeof apiKey === \"string\" && apiKey.trim().length > 0;\n}\n\nfunction withEnvApiKey<TOptions extends StreamOptions>(\n\tmodel: Model<Api>,\n\toptions: TOptions | undefined,\n): TOptions | undefined {\n\tif (hasExplicitApiKey(options?.apiKey)) return options;\n\tconst apiKey = getEnvApiKey(model.provider);\n\tif (!apiKey) return options;\n\treturn { ...options, apiKey } as TOptions;\n}\n\nfunction withTextProtocolUserReminder(message: Message): Message {\n\tif (message.role !== \"user\") return message;\n\tconst reminder =\n\t\t\"Tool-use reminder: if this request asks to read a file, call exactly one tool named read before answering; do not guess file contents.\";\n\tif (typeof message.content === \"string\") return { ...message, content: `${message.content}\\n\\n${reminder}` };\n\treturn { ...message, content: [...message.content, { type: \"text\", text: reminder }] };\n}\n\nfunction withTextProtocolCurrentTurnReminder(messages: readonly Message[]): Message[] {\n\tlet lastUserIndex = -1;\n\tfor (let index = messages.length - 1; index >= 0; index--) {\n\t\tif (messages[index]?.role === \"user\") {\n\t\t\tlastUserIndex = index;\n\t\t\tbreak;\n\t\t}\n\t}\n\treturn messages.map((message, index) => (index === lastUserIndex ? withTextProtocolUserReminder(message) : message));\n}\n\nfunction withTextToolProtocolContext(context: Context, options: StreamOptions | undefined): Context {\n\tconst protocolOptions = normalizeTextToolProtocolOptions(options?.textToolCallProtocol);\n\tif (!protocolOptions || !context.tools?.length) return context;\n\tconst primer = generateTextToolProtocolPrimer(context.tools, protocolOptions);\n\tif (!primer) return context;\n\tconst { tools: _tools, ...providerContext } = context;\n\tconst messages = context.messages.length\n\t\t? [\n\t\t\t\t{\n\t\t\t\t\trole: \"user\" as const,\n\t\t\t\t\tcontent: [\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\ttype: \"text\" as const,\n\t\t\t\t\t\t\ttext: `Tool-call instructions for this conversation:\\n${primer}\\n\\nDo not answer this instruction. Apply it to subsequent user requests. If the next user request asks to read a file, your first response must be a read tool call and nothing else.`,\n\t\t\t\t\t\t},\n\t\t\t\t\t],\n\t\t\t\t\ttimestamp: 0,\n\t\t\t\t},\n\t\t\t\t...withTextProtocolCurrentTurnReminder(context.messages),\n\t\t\t]\n\t\t: context.messages;\n\treturn {\n\t\t...providerContext,\n\t\tsystemPrompt: context.systemPrompt ? `${context.systemPrompt}\\n\\n${primer}` : primer,\n\t\tmessages,\n\t};\n}\n\nasync function notifyTextToolProtocolParse(\n\toptions: StreamOptions | undefined,\n\tevent: TextToolProtocolParseEvent,\n): Promise<void> {\n\ttry {\n\t\tawait options?.onTextToolProtocolParse?.(event);\n\t} catch {\n\t\t// Parse telemetry must not change provider stream semantics.\n\t}\n}\n\nfunction withTextToolProtocolResult(\n\tstream: AssistantMessageEventStream,\n\tmodel: Model<Api>,\n\tcontext: Context,\n\toptions: StreamOptions | undefined,\n): AssistantMessageEventStream {\n\tconst protocolOptions = normalizeTextToolProtocolOptions(options?.textToolCallProtocol);\n\tconst tools = context.tools ?? [];\n\tif (!protocolOptions || tools.length === 0) return stream;\n\tconst wrapped = new AssistantMessageEventStream();\n\tvoid (async () => {\n\t\tfor await (const event of stream) {\n\t\t\tif (event.type !== \"done\") {\n\t\t\t\twrapped.push(event);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tconst message = event.message;\n\t\t\tconst content: AssistantMessage[\"content\"] = [];\n\t\t\tlet callCount = 0;\n\t\t\tlet textLength = 0;\n\t\t\tlet failure: TextToolProtocolParseEvent[\"reason\"] | undefined;\n\t\t\tfor (const block of message.content) {\n\t\t\t\tif (block.type !== \"text\") {\n\t\t\t\t\tcontent.push(block);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\ttextLength += block.text.length;\n\t\t\t\tconst parsed = parseTextToolCalls(block.text, tools);\n\t\t\t\tif (parsed.calls.length === 0) {\n\t\t\t\t\tif (parsed.failure) failure ??= parsed.failure;\n\t\t\t\t\tcontent.push(block);\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tcallCount += parsed.calls.length;\n\t\t\t\tif (parsed.text) content.push({ ...block, text: parsed.text });\n\t\t\t\tcontent.push(...parsed.calls);\n\t\t\t}\n\t\t\tif (callCount === 0) {\n\t\t\t\tif (failure) {\n\t\t\t\t\tawait notifyTextToolProtocolParse(options, {\n\t\t\t\t\t\tprovider: model.provider,\n\t\t\t\t\t\tmodel: model.id,\n\t\t\t\t\t\tvariant: protocolOptions.variant ?? \"tool-tag\",\n\t\t\t\t\t\tstatus: \"failed\",\n\t\t\t\t\t\tcallCount: 0,\n\t\t\t\t\t\ttextLength,\n\t\t\t\t\t\treason: failure,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t\twrapped.push(event);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tawait notifyTextToolProtocolParse(options, {\n\t\t\t\tprovider: model.provider,\n\t\t\t\tmodel: model.id,\n\t\t\t\tvariant: protocolOptions.variant ?? \"tool-tag\",\n\t\t\t\tstatus: \"parsed\",\n\t\t\t\tcallCount,\n\t\t\t\ttextLength,\n\t\t\t});\n\t\t\twrapped.push({\n\t\t\t\ttype: \"done\",\n\t\t\t\treason: \"toolUse\",\n\t\t\t\tmessage: { ...message, content, stopReason: \"toolUse\" },\n\t\t\t});\n\t\t}\n\t})();\n\treturn wrapped;\n}\n\nfunction resolveApiProvider(api: Api) {\n\tconst provider = getApiProvider(api);\n\tif (!provider) {\n\t\tthrow new Error(`No API provider registered for api: ${api}`);\n\t}\n\treturn provider;\n}\n\nexport function stream<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: ProviderStreamOptions,\n): AssistantMessageEventStream {\n\tconst provider = resolveApiProvider(model.api);\n\tconst resolvedOptions = withEnvApiKey(model, options) as StreamOptions;\n\tconst protocolContext = withTextToolProtocolContext(context, resolvedOptions);\n\treturn withTextToolProtocolResult(\n\t\tprovider.stream(model, protocolContext, resolvedOptions),\n\t\tmodel,\n\t\tcontext,\n\t\tresolvedOptions,\n\t);\n}\n\nexport async function complete<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: ProviderStreamOptions,\n): Promise<AssistantMessage> {\n\tconst s = stream(model, context, options);\n\treturn s.result();\n}\n\nexport function streamSimple<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): AssistantMessageEventStream {\n\tconst provider = resolveApiProvider(model.api);\n\tconst resolvedOptions = withEnvApiKey(model, options);\n\tconst protocolContext = withTextToolProtocolContext(context, resolvedOptions);\n\treturn withTextToolProtocolResult(\n\t\tprovider.streamSimple(model, protocolContext, resolvedOptions),\n\t\tmodel,\n\t\tcontext,\n\t\tresolvedOptions,\n\t);\n}\n\nexport async function completeSimple<TApi extends Api>(\n\tmodel: Model<TApi>,\n\tcontext: Context,\n\toptions?: SimpleStreamOptions,\n): Promise<AssistantMessage> {\n\tconst s = streamSimple(model, context, options);\n\treturn s.result();\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../../../src/utils/tool-repair/analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD,MAAM,WAAW,gBAAgB;IAChC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC9C,KAAK,CAAC,EAAE,gBAAgB,GAAG,gBAAgB,EAAE,CAAC;IAC9C,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,oBAAoB,CAAC,EAAE,OAAO,GAAG,gBAAgB,CAAC;IAClD,KAAK,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC3B,KAAK,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC3B,KAAK,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC3B,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,gBAAgB,CAAC;IACzB,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,kBAAkB,EAAE,CAAC;CAC5B;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,gBAAgB,CAE5E;AAED,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,EAAE,CAOhE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAEhE;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAc/E;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,EAAE,CAuBjE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,EAAE,CAkBhE;AAED,wBAAgB,mBAAmB,CAClC,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,SAAS,MAAM,EAAE,GACrB;IACF,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB,CA8BA;AA8HD,wBAAgB,yBAAyB,CACxC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,EAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,EAAE,SAAS,mBAAmB,EAAE,GACpC,eAAe,EAAE,CAiCnB","sourcesContent":["import type { Tool } from \"../../types.ts\";\nimport type { ToolRepairModeName } from \"./registry.ts\";\n\nexport interface JsonSchemaObject {\n\ttype?: string | string[];\n\tproperties?: Record<string, JsonSchemaObject>;\n\titems?: JsonSchemaObject | JsonSchemaObject[];\n\trequired?: string[];\n\tadditionalProperties?: boolean | JsonSchemaObject;\n\tallOf?: JsonSchemaObject[];\n\tanyOf?: JsonSchemaObject[];\n\toneOf?: JsonSchemaObject[];\n\tenum?: unknown[];\n\tconst?: unknown;\n\tdefault?: unknown;\n}\n\nexport interface ValidationErrorLike {\n\tinstancePath: string;\n\tkeyword: string;\n\tmessage: string;\n}\n\nexport interface ToolRepairIssue {\n\tpath: string[];\n\tpathText: string;\n\tvalue: unknown;\n\tschema: JsonSchemaObject;\n\tparentSchema?: JsonSchemaObject;\n\tparentValue?: unknown;\n\tpropertyKey?: string;\n\trequired: boolean;\n\tmodes: ToolRepairModeName[];\n}\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nexport function isJsonSchemaObject(value: unknown): value is JsonSchemaObject {\n\treturn isRecord(value);\n}\n\nexport function parseInstancePath(instancePath: string): string[] {\n\tif (!instancePath) return [];\n\treturn instancePath\n\t\t.replace(/^\\//, \"\")\n\t\t.split(\"/\")\n\t\t.filter((segment) => segment.length > 0)\n\t\t.map((segment) => segment.replace(/~1/g, \"/\").replace(/~0/g, \"~\"));\n}\n\nexport function formatRepairPath(path: readonly string[]): string {\n\treturn path.length === 0 ? \"root\" : path.join(\".\");\n}\n\nexport function getValueAtPath(value: unknown, path: readonly string[]): unknown {\n\tlet cursor = value;\n\tfor (const segment of path) {\n\t\tif (Array.isArray(cursor)) {\n\t\t\tconst index = Number(segment);\n\t\t\tif (!Number.isInteger(index)) return undefined;\n\t\t\tcursor = cursor[index];\n\t\t} else if (isRecord(cursor)) {\n\t\t\tcursor = cursor[segment];\n\t\t} else {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\treturn cursor;\n}\n\nexport function getSchemaTypes(schema: JsonSchemaObject): string[] {\n\tconst types = new Set<string>();\n\tconst addTypes = (candidate: JsonSchemaObject): void => {\n\t\tif (typeof candidate.type === \"string\") {\n\t\t\ttypes.add(candidate.type);\n\t\t} else if (Array.isArray(candidate.type)) {\n\t\t\tfor (const type of candidate.type) {\n\t\t\t\tif (typeof type === \"string\") types.add(type);\n\t\t\t}\n\t\t}\n\t\tif (candidate.enum?.every((value) => typeof value === \"string\")) {\n\t\t\ttypes.add(\"string\");\n\t\t}\n\t\tif (typeof candidate.const === \"string\") {\n\t\t\ttypes.add(\"string\");\n\t\t}\n\t};\n\n\taddTypes(schema);\n\tfor (const nested of [...(schema.anyOf ?? []), ...(schema.oneOf ?? []), ...(schema.allOf ?? [])]) {\n\t\taddTypes(nested);\n\t}\n\treturn [...types];\n}\n\nexport function getEnumValues(schema: JsonSchemaObject): string[] {\n\tconst values: string[] = [];\n\tconst addValues = (candidate: JsonSchemaObject): void => {\n\t\tif (Array.isArray(candidate.enum)) {\n\t\t\tfor (const value of candidate.enum) {\n\t\t\t\tif (typeof value === \"string\") values.push(value);\n\t\t\t}\n\t\t}\n\t\tif (typeof candidate.const === \"string\") {\n\t\t\tvalues.push(candidate.const);\n\t\t}\n\t};\n\n\taddValues(schema);\n\tfor (const nested of [...(schema.anyOf ?? []), ...(schema.oneOf ?? [])]) {\n\t\taddValues(nested);\n\t}\n\treturn values;\n}\n\nexport function resolveSchemaAtPath(\n\tschema: JsonSchemaObject,\n\tpath: readonly string[],\n): {\n\tschema?: JsonSchemaObject;\n\tparentSchema?: JsonSchemaObject;\n\tpropertyKey?: string;\n} {\n\tlet cursor: JsonSchemaObject | undefined = schema;\n\tlet parentSchema: JsonSchemaObject | undefined;\n\tlet propertyKey: string | undefined;\n\n\tfor (const segment of path) {\n\t\tif (!cursor) return { schema: undefined, parentSchema, propertyKey };\n\t\tparentSchema = cursor;\n\t\tpropertyKey = segment;\n\t\tif (cursor.properties?.[segment]) {\n\t\t\tcursor = cursor.properties[segment];\n\t\t\tcontinue;\n\t\t}\n\t\tif (Array.isArray(cursor.items)) {\n\t\t\tconst index = Number(segment);\n\t\t\tcursor = Number.isInteger(index) ? cursor.items[index] : undefined;\n\t\t\tcontinue;\n\t\t}\n\t\tif (isJsonSchemaObject(cursor.items)) {\n\t\t\tcursor = cursor.items;\n\t\t\tcontinue;\n\t\t}\n\t\tif (isJsonSchemaObject(cursor.additionalProperties)) {\n\t\t\tcursor = cursor.additionalProperties;\n\t\t\tcontinue;\n\t\t}\n\t\treturn { schema: undefined, parentSchema, propertyKey };\n\t}\n\n\treturn { schema: cursor, parentSchema, propertyKey };\n}\n\nfunction isRequired(parentSchema: JsonSchemaObject | undefined, propertyKey: string | undefined): boolean {\n\treturn Boolean(propertyKey && parentSchema?.required?.includes(propertyKey));\n}\n\nfunction isScalarSchema(schema: JsonSchemaObject): boolean {\n\treturn getSchemaTypes(schema).some((type) => [\"string\", \"number\", \"integer\", \"boolean\"].includes(type));\n}\n\nfunction isArraySchema(schema: JsonSchemaObject): boolean {\n\treturn getSchemaTypes(schema).includes(\"array\");\n}\n\nfunction isObjectSchema(schema: JsonSchemaObject): boolean {\n\treturn getSchemaTypes(schema).includes(\"object\");\n}\n\nfunction normalizeEnumValue(value: string): string {\n\treturn value.trim().replace(/\\s+/g, \" \").toLowerCase();\n}\n\nfunction enumNormalizeHasMatch(schema: JsonSchemaObject, value: string): boolean {\n\tconst normalized = normalizeEnumValue(value);\n\treturn getEnumValues(schema).filter((candidate) => normalizeEnumValue(candidate) === normalized).length === 1;\n}\n\nfunction isEmptyObject(value: unknown): boolean {\n\treturn isRecord(value) && Object.keys(value).length === 0;\n}\n\nfunction isScalarValue(value: unknown): boolean {\n\treturn [\"string\", \"number\", \"boolean\"].includes(typeof value);\n}\n\nfunction getParentPath(path: readonly string[]): string[] {\n\treturn path.slice(0, -1);\n}\n\nfunction isNumericArrayParentIssue(\n\targs: Record<string, unknown>,\n\trootSchema: JsonSchemaObject,\n\tpath: readonly string[],\n): ToolRepairIssue | undefined {\n\tif (path.length === 0) return undefined;\n\tconst parentPath = getParentPath(path);\n\tconst parentLookup = resolveSchemaAtPath(rootSchema, parentPath);\n\tconst parentSchema = parentLookup.schema;\n\tif (!parentSchema || !isArraySchema(parentSchema) || Array.isArray(parentSchema.items)) return undefined;\n\tif (!isJsonSchemaObject(parentSchema.items)) return undefined;\n\tconst itemTypes = getSchemaTypes(parentSchema.items);\n\tif (!itemTypes.some((type) => type === \"number\" || type === \"integer\")) return undefined;\n\tconst parentValue = getValueAtPath(args, parentPath);\n\tif (!Array.isArray(parentValue) || !parentValue.every((item) => typeof item === \"string\")) return undefined;\n\treturn {\n\t\tpath: parentPath,\n\t\tpathText: formatRepairPath(parentPath),\n\t\tvalue: parentValue,\n\t\tschema: parentSchema,\n\t\tparentSchema: parentLookup.parentSchema,\n\t\tparentValue: getValueAtPath(args, getParentPath(parentPath)),\n\t\tpropertyKey: parentLookup.propertyKey,\n\t\trequired: isRequired(parentLookup.parentSchema, parentLookup.propertyKey),\n\t\tmodes: [\"stringifiedNumberInArray\"],\n\t};\n}\n\nfunction classifyModes(toolName: string, issue: Omit<ToolRepairIssue, \"modes\">): ToolRepairModeName[] {\n\tconst modes: ToolRepairModeName[] = [];\n\tconst expectedTypes = getSchemaTypes(issue.schema);\n\n\tif (toolName === \"bash\" && issue.pathText === \"command\") {\n\t\tif (Array.isArray(issue.value) && issue.value.every((item) => typeof item === \"string\")) {\n\t\t\tmodes.push(\"bashCommandArgvJoin\");\n\t\t}\n\t\tif (isRecord(issue.value)) {\n\t\t\tmodes.push(\"bashCommandUnwrap\");\n\t\t}\n\t}\n\n\tif (typeof issue.value === \"string\" && (isArraySchema(issue.schema) || isObjectSchema(issue.schema))) {\n\t\tmodes.push(\"jsonStringParse\");\n\t}\n\tif (isArraySchema(issue.schema) && isRecord(issue.value)) {\n\t\tmodes.push(\"singleObjectWrap\", \"emptyObjectPlaceholder\");\n\t}\n\tif (isArraySchema(issue.schema) && isScalarValue(issue.value)) {\n\t\tmodes.push(\"bareScalarWrap\");\n\t}\n\tif (typeof issue.value === \"string\" && expectedTypes.some((type) => type === \"number\" || type === \"integer\")) {\n\t\tmodes.push(\"numberFromString\");\n\t}\n\tif (typeof issue.value === \"string\" && expectedTypes.includes(\"boolean\")) {\n\t\tmodes.push(\"boolFromString\");\n\t}\n\tif (typeof issue.value === \"string\" && enumNormalizeHasMatch(issue.schema, issue.value)) {\n\t\tmodes.push(\"enumCaseNormalize\");\n\t}\n\tif (Array.isArray(issue.value) && issue.value.length === 1 && isScalarSchema(issue.schema)) {\n\t\tmodes.push(\"singleElementUnwrap\");\n\t}\n\tif (!issue.required && isEmptyObject(issue.value) && isScalarSchema(issue.schema)) {\n\t\tmodes.push(\"emptyObjectPlaceholder\");\n\t}\n\tif (issue.value === null) {\n\t\tmodes.push(issue.required ? \"nullRequiredBounce\" : \"nullOptionalDrop\");\n\t}\n\n\treturn modes;\n}\n\nfunction comparePaths(a: readonly string[], b: readonly string[]): number {\n\tconst length = Math.min(a.length, b.length);\n\tfor (let index = 0; index < length; index++) {\n\t\tconst left = a[index];\n\t\tconst right = b[index];\n\t\tconst leftNumber = Number(left);\n\t\tconst rightNumber = Number(right);\n\t\tif (Number.isInteger(leftNumber) && Number.isInteger(rightNumber) && leftNumber !== rightNumber) {\n\t\t\treturn leftNumber - rightNumber;\n\t\t}\n\t\tif (left !== right) return left < right ? -1 : 1;\n\t}\n\treturn a.length - b.length;\n}\n\nexport function analyzeToolArgumentErrors(\n\ttoolName: string,\n\tschema: Tool[\"parameters\"],\n\targs: Record<string, unknown>,\n\terrors: readonly ValidationErrorLike[],\n): ToolRepairIssue[] {\n\tconst rootSchema = schema as JsonSchemaObject;\n\tconst issues = new Map<string, ToolRepairIssue>();\n\n\tfor (const error of errors) {\n\t\tif (error.keyword === \"required\") continue;\n\t\tconst path = parseInstancePath(error.instancePath);\n\t\tconst numericArrayIssue = isNumericArrayParentIssue(args, rootSchema, path);\n\t\tif (numericArrayIssue) {\n\t\t\tissues.set(numericArrayIssue.pathText, numericArrayIssue);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst lookup = resolveSchemaAtPath(rootSchema, path);\n\t\tif (!lookup.schema) continue;\n\t\tconst value = getValueAtPath(args, path);\n\t\tconst issueBase = {\n\t\t\tpath,\n\t\t\tpathText: formatRepairPath(path),\n\t\t\tvalue,\n\t\t\tschema: lookup.schema,\n\t\t\tparentSchema: lookup.parentSchema,\n\t\t\tparentValue: getValueAtPath(args, getParentPath(path)),\n\t\t\tpropertyKey: lookup.propertyKey,\n\t\t\trequired: isRequired(lookup.parentSchema, lookup.propertyKey),\n\t\t};\n\t\tconst modes = classifyModes(toolName, issueBase);\n\t\tif (modes.length > 0) {\n\t\t\tissues.set(issueBase.pathText, { ...issueBase, modes });\n\t\t}\n\t}\n\n\treturn [...issues.values()].sort((left, right) => comparePaths(left.path, right.path));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"analyzer.d.ts","sourceRoot":"","sources":["../../../src/utils/tool-repair/analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD,MAAM,WAAW,gBAAgB;IAChC,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;IACzB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IAC9C,KAAK,CAAC,EAAE,gBAAgB,GAAG,gBAAgB,EAAE,CAAC;IAC9C,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,oBAAoB,CAAC,EAAE,OAAO,GAAG,gBAAgB,CAAC;IAClD,KAAK,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC3B,KAAK,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC3B,KAAK,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC3B,IAAI,CAAC,EAAE,OAAO,EAAE,CAAC;IACjB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,OAAO,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,MAAM,WAAW,mBAAmB;IACnC,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,MAAM,EAAE,gBAAgB,CAAC;IACzB,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,KAAK,EAAE,kBAAkB,EAAE,CAAC;CAC5B;AAED,wBAAgB,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAEzE;AAED,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,gBAAgB,CAE5E;AAED,wBAAgB,iBAAiB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,EAAE,CAOhE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAEhE;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,OAAO,CAc/E;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,EAAE,CAuBjE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,gBAAgB,GAAG,MAAM,EAAE,CAkBhE;AAED,wBAAgB,mBAAmB,CAClC,MAAM,EAAE,gBAAgB,EACxB,IAAI,EAAE,SAAS,MAAM,EAAE,GACrB;IACF,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,YAAY,CAAC,EAAE,gBAAgB,CAAC;IAChC,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB,CA8BA;AA+HD,wBAAgB,yBAAyB,CACxC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,EAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,EAAE,SAAS,mBAAmB,EAAE,GACpC,eAAe,EAAE,CAiCnB","sourcesContent":["import type { Tool } from \"../../types.ts\";\nimport type { ToolRepairModeName } from \"./registry.ts\";\n\nexport interface JsonSchemaObject {\n\ttype?: string | string[];\n\tproperties?: Record<string, JsonSchemaObject>;\n\titems?: JsonSchemaObject | JsonSchemaObject[];\n\trequired?: string[];\n\tadditionalProperties?: boolean | JsonSchemaObject;\n\tallOf?: JsonSchemaObject[];\n\tanyOf?: JsonSchemaObject[];\n\toneOf?: JsonSchemaObject[];\n\tenum?: unknown[];\n\tconst?: unknown;\n\tdefault?: unknown;\n}\n\nexport interface ValidationErrorLike {\n\tinstancePath: string;\n\tkeyword: string;\n\tmessage: string;\n}\n\nexport interface ToolRepairIssue {\n\tpath: string[];\n\tpathText: string;\n\tvalue: unknown;\n\tschema: JsonSchemaObject;\n\tparentSchema?: JsonSchemaObject;\n\tparentValue?: unknown;\n\tpropertyKey?: string;\n\trequired: boolean;\n\tmodes: ToolRepairModeName[];\n}\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nexport function isJsonSchemaObject(value: unknown): value is JsonSchemaObject {\n\treturn isRecord(value);\n}\n\nexport function parseInstancePath(instancePath: string): string[] {\n\tif (!instancePath) return [];\n\treturn instancePath\n\t\t.replace(/^\\//, \"\")\n\t\t.split(\"/\")\n\t\t.filter((segment) => segment.length > 0)\n\t\t.map((segment) => segment.replace(/~1/g, \"/\").replace(/~0/g, \"~\"));\n}\n\nexport function formatRepairPath(path: readonly string[]): string {\n\treturn path.length === 0 ? \"root\" : path.join(\".\");\n}\n\nexport function getValueAtPath(value: unknown, path: readonly string[]): unknown {\n\tlet cursor = value;\n\tfor (const segment of path) {\n\t\tif (Array.isArray(cursor)) {\n\t\t\tconst index = Number(segment);\n\t\t\tif (!Number.isInteger(index)) return undefined;\n\t\t\tcursor = cursor[index];\n\t\t} else if (isRecord(cursor)) {\n\t\t\tcursor = cursor[segment];\n\t\t} else {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\treturn cursor;\n}\n\nexport function getSchemaTypes(schema: JsonSchemaObject): string[] {\n\tconst types = new Set<string>();\n\tconst addTypes = (candidate: JsonSchemaObject): void => {\n\t\tif (typeof candidate.type === \"string\") {\n\t\t\ttypes.add(candidate.type);\n\t\t} else if (Array.isArray(candidate.type)) {\n\t\t\tfor (const type of candidate.type) {\n\t\t\t\tif (typeof type === \"string\") types.add(type);\n\t\t\t}\n\t\t}\n\t\tif (candidate.enum?.every((value) => typeof value === \"string\")) {\n\t\t\ttypes.add(\"string\");\n\t\t}\n\t\tif (typeof candidate.const === \"string\") {\n\t\t\ttypes.add(\"string\");\n\t\t}\n\t};\n\n\taddTypes(schema);\n\tfor (const nested of [...(schema.anyOf ?? []), ...(schema.oneOf ?? []), ...(schema.allOf ?? [])]) {\n\t\taddTypes(nested);\n\t}\n\treturn [...types];\n}\n\nexport function getEnumValues(schema: JsonSchemaObject): string[] {\n\tconst values: string[] = [];\n\tconst addValues = (candidate: JsonSchemaObject): void => {\n\t\tif (Array.isArray(candidate.enum)) {\n\t\t\tfor (const value of candidate.enum) {\n\t\t\t\tif (typeof value === \"string\") values.push(value);\n\t\t\t}\n\t\t}\n\t\tif (typeof candidate.const === \"string\") {\n\t\t\tvalues.push(candidate.const);\n\t\t}\n\t};\n\n\taddValues(schema);\n\tfor (const nested of [...(schema.anyOf ?? []), ...(schema.oneOf ?? [])]) {\n\t\taddValues(nested);\n\t}\n\treturn values;\n}\n\nexport function resolveSchemaAtPath(\n\tschema: JsonSchemaObject,\n\tpath: readonly string[],\n): {\n\tschema?: JsonSchemaObject;\n\tparentSchema?: JsonSchemaObject;\n\tpropertyKey?: string;\n} {\n\tlet cursor: JsonSchemaObject | undefined = schema;\n\tlet parentSchema: JsonSchemaObject | undefined;\n\tlet propertyKey: string | undefined;\n\n\tfor (const segment of path) {\n\t\tif (!cursor) return { schema: undefined, parentSchema, propertyKey };\n\t\tparentSchema = cursor;\n\t\tpropertyKey = segment;\n\t\tif (cursor.properties?.[segment]) {\n\t\t\tcursor = cursor.properties[segment];\n\t\t\tcontinue;\n\t\t}\n\t\tif (Array.isArray(cursor.items)) {\n\t\t\tconst index = Number(segment);\n\t\t\tcursor = Number.isInteger(index) ? cursor.items[index] : undefined;\n\t\t\tcontinue;\n\t\t}\n\t\tif (isJsonSchemaObject(cursor.items)) {\n\t\t\tcursor = cursor.items;\n\t\t\tcontinue;\n\t\t}\n\t\tif (isJsonSchemaObject(cursor.additionalProperties)) {\n\t\t\tcursor = cursor.additionalProperties;\n\t\t\tcontinue;\n\t\t}\n\t\treturn { schema: undefined, parentSchema, propertyKey };\n\t}\n\n\treturn { schema: cursor, parentSchema, propertyKey };\n}\n\nfunction isRequired(parentSchema: JsonSchemaObject | undefined, propertyKey: string | undefined): boolean {\n\treturn Boolean(propertyKey && parentSchema?.required?.includes(propertyKey));\n}\n\nfunction isScalarSchema(schema: JsonSchemaObject): boolean {\n\treturn getSchemaTypes(schema).some((type) => [\"string\", \"number\", \"integer\", \"boolean\"].includes(type));\n}\n\nfunction isArraySchema(schema: JsonSchemaObject): boolean {\n\treturn getSchemaTypes(schema).includes(\"array\");\n}\n\nfunction isObjectSchema(schema: JsonSchemaObject): boolean {\n\treturn getSchemaTypes(schema).includes(\"object\");\n}\n\nfunction normalizeEnumValue(value: string): string {\n\treturn value.trim().replace(/\\s+/g, \" \").toLowerCase();\n}\n\nfunction enumNormalizeHasMatch(schema: JsonSchemaObject, value: string): boolean {\n\tconst normalized = normalizeEnumValue(value);\n\treturn getEnumValues(schema).filter((candidate) => normalizeEnumValue(candidate) === normalized).length === 1;\n}\n\nfunction isEmptyObject(value: unknown): boolean {\n\treturn isRecord(value) && Object.keys(value).length === 0;\n}\n\nfunction isScalarValue(value: unknown): boolean {\n\treturn [\"string\", \"number\", \"boolean\"].includes(typeof value);\n}\n\nfunction getParentPath(path: readonly string[]): string[] {\n\treturn path.slice(0, -1);\n}\n\nfunction isNumericArrayParentIssue(\n\targs: Record<string, unknown>,\n\trootSchema: JsonSchemaObject,\n\tpath: readonly string[],\n): ToolRepairIssue | undefined {\n\tif (path.length === 0) return undefined;\n\tconst parentPath = getParentPath(path);\n\tconst parentLookup = resolveSchemaAtPath(rootSchema, parentPath);\n\tconst parentSchema = parentLookup.schema;\n\tif (!parentSchema || !isArraySchema(parentSchema) || Array.isArray(parentSchema.items)) return undefined;\n\tif (!isJsonSchemaObject(parentSchema.items)) return undefined;\n\tconst itemTypes = getSchemaTypes(parentSchema.items);\n\tif (!itemTypes.some((type) => type === \"number\" || type === \"integer\")) return undefined;\n\tconst parentValue = getValueAtPath(args, parentPath);\n\tif (!Array.isArray(parentValue) || !parentValue.every((item) => typeof item === \"string\")) return undefined;\n\treturn {\n\t\tpath: parentPath,\n\t\tpathText: formatRepairPath(parentPath),\n\t\tvalue: parentValue,\n\t\tschema: parentSchema,\n\t\tparentSchema: parentLookup.parentSchema,\n\t\tparentValue: getValueAtPath(args, getParentPath(parentPath)),\n\t\tpropertyKey: parentLookup.propertyKey,\n\t\trequired: isRequired(parentLookup.parentSchema, parentLookup.propertyKey),\n\t\tmodes: [\"stringifiedNumberInArray\"],\n\t};\n}\n\nfunction classifyModes(toolName: string, issue: Omit<ToolRepairIssue, \"modes\">): ToolRepairModeName[] {\n\tconst modes: ToolRepairModeName[] = [];\n\tconst expectedTypes = getSchemaTypes(issue.schema);\n\n\tif (toolName === \"bash\" && issue.pathText === \"command\") {\n\t\tif (Array.isArray(issue.value) && issue.value.every((item) => typeof item === \"string\")) {\n\t\t\tmodes.push(\"bashCommandArgvJoin\");\n\t\t}\n\t\tif (isRecord(issue.value)) {\n\t\t\tmodes.push(\"bashCommandUnwrap\");\n\t\t}\n\t}\n\n\tif (typeof issue.value === \"string\" && (isArraySchema(issue.schema) || isObjectSchema(issue.schema))) {\n\t\tmodes.push(\"jsonStringParse\");\n\t\tif (isObjectSchema(issue.schema)) modes.push(\"jsonObjectPropertySalvage\");\n\t}\n\tif (isArraySchema(issue.schema) && isRecord(issue.value)) {\n\t\tmodes.push(\"singleObjectWrap\", \"emptyObjectPlaceholder\");\n\t}\n\tif (isArraySchema(issue.schema) && isScalarValue(issue.value)) {\n\t\tmodes.push(\"bareScalarWrap\");\n\t}\n\tif (typeof issue.value === \"string\" && expectedTypes.some((type) => type === \"number\" || type === \"integer\")) {\n\t\tmodes.push(\"numberFromString\");\n\t}\n\tif (typeof issue.value === \"string\" && expectedTypes.includes(\"boolean\")) {\n\t\tmodes.push(\"boolFromString\");\n\t}\n\tif (typeof issue.value === \"string\" && enumNormalizeHasMatch(issue.schema, issue.value)) {\n\t\tmodes.push(\"enumCaseNormalize\");\n\t}\n\tif (Array.isArray(issue.value) && issue.value.length === 1 && isScalarSchema(issue.schema)) {\n\t\tmodes.push(\"singleElementUnwrap\");\n\t}\n\tif (!issue.required && isEmptyObject(issue.value) && isScalarSchema(issue.schema)) {\n\t\tmodes.push(\"emptyObjectPlaceholder\");\n\t}\n\tif (issue.value === null) {\n\t\tmodes.push(issue.required ? \"nullRequiredBounce\" : \"nullOptionalDrop\");\n\t}\n\n\treturn modes;\n}\n\nfunction comparePaths(a: readonly string[], b: readonly string[]): number {\n\tconst length = Math.min(a.length, b.length);\n\tfor (let index = 0; index < length; index++) {\n\t\tconst left = a[index];\n\t\tconst right = b[index];\n\t\tconst leftNumber = Number(left);\n\t\tconst rightNumber = Number(right);\n\t\tif (Number.isInteger(leftNumber) && Number.isInteger(rightNumber) && leftNumber !== rightNumber) {\n\t\t\treturn leftNumber - rightNumber;\n\t\t}\n\t\tif (left !== right) return left < right ? -1 : 1;\n\t}\n\treturn a.length - b.length;\n}\n\nexport function analyzeToolArgumentErrors(\n\ttoolName: string,\n\tschema: Tool[\"parameters\"],\n\targs: Record<string, unknown>,\n\terrors: readonly ValidationErrorLike[],\n): ToolRepairIssue[] {\n\tconst rootSchema = schema as JsonSchemaObject;\n\tconst issues = new Map<string, ToolRepairIssue>();\n\n\tfor (const error of errors) {\n\t\tif (error.keyword === \"required\") continue;\n\t\tconst path = parseInstancePath(error.instancePath);\n\t\tconst numericArrayIssue = isNumericArrayParentIssue(args, rootSchema, path);\n\t\tif (numericArrayIssue) {\n\t\t\tissues.set(numericArrayIssue.pathText, numericArrayIssue);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst lookup = resolveSchemaAtPath(rootSchema, path);\n\t\tif (!lookup.schema) continue;\n\t\tconst value = getValueAtPath(args, path);\n\t\tconst issueBase = {\n\t\t\tpath,\n\t\t\tpathText: formatRepairPath(path),\n\t\t\tvalue,\n\t\t\tschema: lookup.schema,\n\t\t\tparentSchema: lookup.parentSchema,\n\t\t\tparentValue: getValueAtPath(args, getParentPath(path)),\n\t\t\tpropertyKey: lookup.propertyKey,\n\t\t\trequired: isRequired(lookup.parentSchema, lookup.propertyKey),\n\t\t};\n\t\tconst modes = classifyModes(toolName, issueBase);\n\t\tif (modes.length > 0) {\n\t\t\tissues.set(issueBase.pathText, { ...issueBase, modes });\n\t\t}\n\t}\n\n\treturn [...issues.values()].sort((left, right) => comparePaths(left.path, right.path));\n}\n"]}
|
|
@@ -177,6 +177,8 @@ function classifyModes(toolName, issue) {
|
|
|
177
177
|
}
|
|
178
178
|
if (typeof issue.value === "string" && (isArraySchema(issue.schema) || isObjectSchema(issue.schema))) {
|
|
179
179
|
modes.push("jsonStringParse");
|
|
180
|
+
if (isObjectSchema(issue.schema))
|
|
181
|
+
modes.push("jsonObjectPropertySalvage");
|
|
180
182
|
}
|
|
181
183
|
if (isArraySchema(issue.schema) && isRecord(issue.value)) {
|
|
182
184
|
modes.push("singleObjectWrap", "emptyObjectPlaceholder");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analyzer.js","sourceRoot":"","sources":["../../../src/utils/tool-repair/analyzer.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Tool } from \"../../types.ts\";\nimport type { ToolRepairModeName } from \"./registry.ts\";\n\nexport interface JsonSchemaObject {\n\ttype?: string | string[];\n\tproperties?: Record<string, JsonSchemaObject>;\n\titems?: JsonSchemaObject | JsonSchemaObject[];\n\trequired?: string[];\n\tadditionalProperties?: boolean | JsonSchemaObject;\n\tallOf?: JsonSchemaObject[];\n\tanyOf?: JsonSchemaObject[];\n\toneOf?: JsonSchemaObject[];\n\tenum?: unknown[];\n\tconst?: unknown;\n\tdefault?: unknown;\n}\n\nexport interface ValidationErrorLike {\n\tinstancePath: string;\n\tkeyword: string;\n\tmessage: string;\n}\n\nexport interface ToolRepairIssue {\n\tpath: string[];\n\tpathText: string;\n\tvalue: unknown;\n\tschema: JsonSchemaObject;\n\tparentSchema?: JsonSchemaObject;\n\tparentValue?: unknown;\n\tpropertyKey?: string;\n\trequired: boolean;\n\tmodes: ToolRepairModeName[];\n}\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nexport function isJsonSchemaObject(value: unknown): value is JsonSchemaObject {\n\treturn isRecord(value);\n}\n\nexport function parseInstancePath(instancePath: string): string[] {\n\tif (!instancePath) return [];\n\treturn instancePath\n\t\t.replace(/^\\//, \"\")\n\t\t.split(\"/\")\n\t\t.filter((segment) => segment.length > 0)\n\t\t.map((segment) => segment.replace(/~1/g, \"/\").replace(/~0/g, \"~\"));\n}\n\nexport function formatRepairPath(path: readonly string[]): string {\n\treturn path.length === 0 ? \"root\" : path.join(\".\");\n}\n\nexport function getValueAtPath(value: unknown, path: readonly string[]): unknown {\n\tlet cursor = value;\n\tfor (const segment of path) {\n\t\tif (Array.isArray(cursor)) {\n\t\t\tconst index = Number(segment);\n\t\t\tif (!Number.isInteger(index)) return undefined;\n\t\t\tcursor = cursor[index];\n\t\t} else if (isRecord(cursor)) {\n\t\t\tcursor = cursor[segment];\n\t\t} else {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\treturn cursor;\n}\n\nexport function getSchemaTypes(schema: JsonSchemaObject): string[] {\n\tconst types = new Set<string>();\n\tconst addTypes = (candidate: JsonSchemaObject): void => {\n\t\tif (typeof candidate.type === \"string\") {\n\t\t\ttypes.add(candidate.type);\n\t\t} else if (Array.isArray(candidate.type)) {\n\t\t\tfor (const type of candidate.type) {\n\t\t\t\tif (typeof type === \"string\") types.add(type);\n\t\t\t}\n\t\t}\n\t\tif (candidate.enum?.every((value) => typeof value === \"string\")) {\n\t\t\ttypes.add(\"string\");\n\t\t}\n\t\tif (typeof candidate.const === \"string\") {\n\t\t\ttypes.add(\"string\");\n\t\t}\n\t};\n\n\taddTypes(schema);\n\tfor (const nested of [...(schema.anyOf ?? []), ...(schema.oneOf ?? []), ...(schema.allOf ?? [])]) {\n\t\taddTypes(nested);\n\t}\n\treturn [...types];\n}\n\nexport function getEnumValues(schema: JsonSchemaObject): string[] {\n\tconst values: string[] = [];\n\tconst addValues = (candidate: JsonSchemaObject): void => {\n\t\tif (Array.isArray(candidate.enum)) {\n\t\t\tfor (const value of candidate.enum) {\n\t\t\t\tif (typeof value === \"string\") values.push(value);\n\t\t\t}\n\t\t}\n\t\tif (typeof candidate.const === \"string\") {\n\t\t\tvalues.push(candidate.const);\n\t\t}\n\t};\n\n\taddValues(schema);\n\tfor (const nested of [...(schema.anyOf ?? []), ...(schema.oneOf ?? [])]) {\n\t\taddValues(nested);\n\t}\n\treturn values;\n}\n\nexport function resolveSchemaAtPath(\n\tschema: JsonSchemaObject,\n\tpath: readonly string[],\n): {\n\tschema?: JsonSchemaObject;\n\tparentSchema?: JsonSchemaObject;\n\tpropertyKey?: string;\n} {\n\tlet cursor: JsonSchemaObject | undefined = schema;\n\tlet parentSchema: JsonSchemaObject | undefined;\n\tlet propertyKey: string | undefined;\n\n\tfor (const segment of path) {\n\t\tif (!cursor) return { schema: undefined, parentSchema, propertyKey };\n\t\tparentSchema = cursor;\n\t\tpropertyKey = segment;\n\t\tif (cursor.properties?.[segment]) {\n\t\t\tcursor = cursor.properties[segment];\n\t\t\tcontinue;\n\t\t}\n\t\tif (Array.isArray(cursor.items)) {\n\t\t\tconst index = Number(segment);\n\t\t\tcursor = Number.isInteger(index) ? cursor.items[index] : undefined;\n\t\t\tcontinue;\n\t\t}\n\t\tif (isJsonSchemaObject(cursor.items)) {\n\t\t\tcursor = cursor.items;\n\t\t\tcontinue;\n\t\t}\n\t\tif (isJsonSchemaObject(cursor.additionalProperties)) {\n\t\t\tcursor = cursor.additionalProperties;\n\t\t\tcontinue;\n\t\t}\n\t\treturn { schema: undefined, parentSchema, propertyKey };\n\t}\n\n\treturn { schema: cursor, parentSchema, propertyKey };\n}\n\nfunction isRequired(parentSchema: JsonSchemaObject | undefined, propertyKey: string | undefined): boolean {\n\treturn Boolean(propertyKey && parentSchema?.required?.includes(propertyKey));\n}\n\nfunction isScalarSchema(schema: JsonSchemaObject): boolean {\n\treturn getSchemaTypes(schema).some((type) => [\"string\", \"number\", \"integer\", \"boolean\"].includes(type));\n}\n\nfunction isArraySchema(schema: JsonSchemaObject): boolean {\n\treturn getSchemaTypes(schema).includes(\"array\");\n}\n\nfunction isObjectSchema(schema: JsonSchemaObject): boolean {\n\treturn getSchemaTypes(schema).includes(\"object\");\n}\n\nfunction normalizeEnumValue(value: string): string {\n\treturn value.trim().replace(/\\s+/g, \" \").toLowerCase();\n}\n\nfunction enumNormalizeHasMatch(schema: JsonSchemaObject, value: string): boolean {\n\tconst normalized = normalizeEnumValue(value);\n\treturn getEnumValues(schema).filter((candidate) => normalizeEnumValue(candidate) === normalized).length === 1;\n}\n\nfunction isEmptyObject(value: unknown): boolean {\n\treturn isRecord(value) && Object.keys(value).length === 0;\n}\n\nfunction isScalarValue(value: unknown): boolean {\n\treturn [\"string\", \"number\", \"boolean\"].includes(typeof value);\n}\n\nfunction getParentPath(path: readonly string[]): string[] {\n\treturn path.slice(0, -1);\n}\n\nfunction isNumericArrayParentIssue(\n\targs: Record<string, unknown>,\n\trootSchema: JsonSchemaObject,\n\tpath: readonly string[],\n): ToolRepairIssue | undefined {\n\tif (path.length === 0) return undefined;\n\tconst parentPath = getParentPath(path);\n\tconst parentLookup = resolveSchemaAtPath(rootSchema, parentPath);\n\tconst parentSchema = parentLookup.schema;\n\tif (!parentSchema || !isArraySchema(parentSchema) || Array.isArray(parentSchema.items)) return undefined;\n\tif (!isJsonSchemaObject(parentSchema.items)) return undefined;\n\tconst itemTypes = getSchemaTypes(parentSchema.items);\n\tif (!itemTypes.some((type) => type === \"number\" || type === \"integer\")) return undefined;\n\tconst parentValue = getValueAtPath(args, parentPath);\n\tif (!Array.isArray(parentValue) || !parentValue.every((item) => typeof item === \"string\")) return undefined;\n\treturn {\n\t\tpath: parentPath,\n\t\tpathText: formatRepairPath(parentPath),\n\t\tvalue: parentValue,\n\t\tschema: parentSchema,\n\t\tparentSchema: parentLookup.parentSchema,\n\t\tparentValue: getValueAtPath(args, getParentPath(parentPath)),\n\t\tpropertyKey: parentLookup.propertyKey,\n\t\trequired: isRequired(parentLookup.parentSchema, parentLookup.propertyKey),\n\t\tmodes: [\"stringifiedNumberInArray\"],\n\t};\n}\n\nfunction classifyModes(toolName: string, issue: Omit<ToolRepairIssue, \"modes\">): ToolRepairModeName[] {\n\tconst modes: ToolRepairModeName[] = [];\n\tconst expectedTypes = getSchemaTypes(issue.schema);\n\n\tif (toolName === \"bash\" && issue.pathText === \"command\") {\n\t\tif (Array.isArray(issue.value) && issue.value.every((item) => typeof item === \"string\")) {\n\t\t\tmodes.push(\"bashCommandArgvJoin\");\n\t\t}\n\t\tif (isRecord(issue.value)) {\n\t\t\tmodes.push(\"bashCommandUnwrap\");\n\t\t}\n\t}\n\n\tif (typeof issue.value === \"string\" && (isArraySchema(issue.schema) || isObjectSchema(issue.schema))) {\n\t\tmodes.push(\"jsonStringParse\");\n\t}\n\tif (isArraySchema(issue.schema) && isRecord(issue.value)) {\n\t\tmodes.push(\"singleObjectWrap\", \"emptyObjectPlaceholder\");\n\t}\n\tif (isArraySchema(issue.schema) && isScalarValue(issue.value)) {\n\t\tmodes.push(\"bareScalarWrap\");\n\t}\n\tif (typeof issue.value === \"string\" && expectedTypes.some((type) => type === \"number\" || type === \"integer\")) {\n\t\tmodes.push(\"numberFromString\");\n\t}\n\tif (typeof issue.value === \"string\" && expectedTypes.includes(\"boolean\")) {\n\t\tmodes.push(\"boolFromString\");\n\t}\n\tif (typeof issue.value === \"string\" && enumNormalizeHasMatch(issue.schema, issue.value)) {\n\t\tmodes.push(\"enumCaseNormalize\");\n\t}\n\tif (Array.isArray(issue.value) && issue.value.length === 1 && isScalarSchema(issue.schema)) {\n\t\tmodes.push(\"singleElementUnwrap\");\n\t}\n\tif (!issue.required && isEmptyObject(issue.value) && isScalarSchema(issue.schema)) {\n\t\tmodes.push(\"emptyObjectPlaceholder\");\n\t}\n\tif (issue.value === null) {\n\t\tmodes.push(issue.required ? \"nullRequiredBounce\" : \"nullOptionalDrop\");\n\t}\n\n\treturn modes;\n}\n\nfunction comparePaths(a: readonly string[], b: readonly string[]): number {\n\tconst length = Math.min(a.length, b.length);\n\tfor (let index = 0; index < length; index++) {\n\t\tconst left = a[index];\n\t\tconst right = b[index];\n\t\tconst leftNumber = Number(left);\n\t\tconst rightNumber = Number(right);\n\t\tif (Number.isInteger(leftNumber) && Number.isInteger(rightNumber) && leftNumber !== rightNumber) {\n\t\t\treturn leftNumber - rightNumber;\n\t\t}\n\t\tif (left !== right) return left < right ? -1 : 1;\n\t}\n\treturn a.length - b.length;\n}\n\nexport function analyzeToolArgumentErrors(\n\ttoolName: string,\n\tschema: Tool[\"parameters\"],\n\targs: Record<string, unknown>,\n\terrors: readonly ValidationErrorLike[],\n): ToolRepairIssue[] {\n\tconst rootSchema = schema as JsonSchemaObject;\n\tconst issues = new Map<string, ToolRepairIssue>();\n\n\tfor (const error of errors) {\n\t\tif (error.keyword === \"required\") continue;\n\t\tconst path = parseInstancePath(error.instancePath);\n\t\tconst numericArrayIssue = isNumericArrayParentIssue(args, rootSchema, path);\n\t\tif (numericArrayIssue) {\n\t\t\tissues.set(numericArrayIssue.pathText, numericArrayIssue);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst lookup = resolveSchemaAtPath(rootSchema, path);\n\t\tif (!lookup.schema) continue;\n\t\tconst value = getValueAtPath(args, path);\n\t\tconst issueBase = {\n\t\t\tpath,\n\t\t\tpathText: formatRepairPath(path),\n\t\t\tvalue,\n\t\t\tschema: lookup.schema,\n\t\t\tparentSchema: lookup.parentSchema,\n\t\t\tparentValue: getValueAtPath(args, getParentPath(path)),\n\t\t\tpropertyKey: lookup.propertyKey,\n\t\t\trequired: isRequired(lookup.parentSchema, lookup.propertyKey),\n\t\t};\n\t\tconst modes = classifyModes(toolName, issueBase);\n\t\tif (modes.length > 0) {\n\t\t\tissues.set(issueBase.pathText, { ...issueBase, modes });\n\t\t}\n\t}\n\n\treturn [...issues.values()].sort((left, right) => comparePaths(left.path, right.path));\n}\n"]}
|
|
1
|
+
{"version":3,"file":"analyzer.js","sourceRoot":"","sources":["../../../src/utils/tool-repair/analyzer.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Tool } from \"../../types.ts\";\nimport type { ToolRepairModeName } from \"./registry.ts\";\n\nexport interface JsonSchemaObject {\n\ttype?: string | string[];\n\tproperties?: Record<string, JsonSchemaObject>;\n\titems?: JsonSchemaObject | JsonSchemaObject[];\n\trequired?: string[];\n\tadditionalProperties?: boolean | JsonSchemaObject;\n\tallOf?: JsonSchemaObject[];\n\tanyOf?: JsonSchemaObject[];\n\toneOf?: JsonSchemaObject[];\n\tenum?: unknown[];\n\tconst?: unknown;\n\tdefault?: unknown;\n}\n\nexport interface ValidationErrorLike {\n\tinstancePath: string;\n\tkeyword: string;\n\tmessage: string;\n}\n\nexport interface ToolRepairIssue {\n\tpath: string[];\n\tpathText: string;\n\tvalue: unknown;\n\tschema: JsonSchemaObject;\n\tparentSchema?: JsonSchemaObject;\n\tparentValue?: unknown;\n\tpropertyKey?: string;\n\trequired: boolean;\n\tmodes: ToolRepairModeName[];\n}\n\nexport function isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nexport function isJsonSchemaObject(value: unknown): value is JsonSchemaObject {\n\treturn isRecord(value);\n}\n\nexport function parseInstancePath(instancePath: string): string[] {\n\tif (!instancePath) return [];\n\treturn instancePath\n\t\t.replace(/^\\//, \"\")\n\t\t.split(\"/\")\n\t\t.filter((segment) => segment.length > 0)\n\t\t.map((segment) => segment.replace(/~1/g, \"/\").replace(/~0/g, \"~\"));\n}\n\nexport function formatRepairPath(path: readonly string[]): string {\n\treturn path.length === 0 ? \"root\" : path.join(\".\");\n}\n\nexport function getValueAtPath(value: unknown, path: readonly string[]): unknown {\n\tlet cursor = value;\n\tfor (const segment of path) {\n\t\tif (Array.isArray(cursor)) {\n\t\t\tconst index = Number(segment);\n\t\t\tif (!Number.isInteger(index)) return undefined;\n\t\t\tcursor = cursor[index];\n\t\t} else if (isRecord(cursor)) {\n\t\t\tcursor = cursor[segment];\n\t\t} else {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\treturn cursor;\n}\n\nexport function getSchemaTypes(schema: JsonSchemaObject): string[] {\n\tconst types = new Set<string>();\n\tconst addTypes = (candidate: JsonSchemaObject): void => {\n\t\tif (typeof candidate.type === \"string\") {\n\t\t\ttypes.add(candidate.type);\n\t\t} else if (Array.isArray(candidate.type)) {\n\t\t\tfor (const type of candidate.type) {\n\t\t\t\tif (typeof type === \"string\") types.add(type);\n\t\t\t}\n\t\t}\n\t\tif (candidate.enum?.every((value) => typeof value === \"string\")) {\n\t\t\ttypes.add(\"string\");\n\t\t}\n\t\tif (typeof candidate.const === \"string\") {\n\t\t\ttypes.add(\"string\");\n\t\t}\n\t};\n\n\taddTypes(schema);\n\tfor (const nested of [...(schema.anyOf ?? []), ...(schema.oneOf ?? []), ...(schema.allOf ?? [])]) {\n\t\taddTypes(nested);\n\t}\n\treturn [...types];\n}\n\nexport function getEnumValues(schema: JsonSchemaObject): string[] {\n\tconst values: string[] = [];\n\tconst addValues = (candidate: JsonSchemaObject): void => {\n\t\tif (Array.isArray(candidate.enum)) {\n\t\t\tfor (const value of candidate.enum) {\n\t\t\t\tif (typeof value === \"string\") values.push(value);\n\t\t\t}\n\t\t}\n\t\tif (typeof candidate.const === \"string\") {\n\t\t\tvalues.push(candidate.const);\n\t\t}\n\t};\n\n\taddValues(schema);\n\tfor (const nested of [...(schema.anyOf ?? []), ...(schema.oneOf ?? [])]) {\n\t\taddValues(nested);\n\t}\n\treturn values;\n}\n\nexport function resolveSchemaAtPath(\n\tschema: JsonSchemaObject,\n\tpath: readonly string[],\n): {\n\tschema?: JsonSchemaObject;\n\tparentSchema?: JsonSchemaObject;\n\tpropertyKey?: string;\n} {\n\tlet cursor: JsonSchemaObject | undefined = schema;\n\tlet parentSchema: JsonSchemaObject | undefined;\n\tlet propertyKey: string | undefined;\n\n\tfor (const segment of path) {\n\t\tif (!cursor) return { schema: undefined, parentSchema, propertyKey };\n\t\tparentSchema = cursor;\n\t\tpropertyKey = segment;\n\t\tif (cursor.properties?.[segment]) {\n\t\t\tcursor = cursor.properties[segment];\n\t\t\tcontinue;\n\t\t}\n\t\tif (Array.isArray(cursor.items)) {\n\t\t\tconst index = Number(segment);\n\t\t\tcursor = Number.isInteger(index) ? cursor.items[index] : undefined;\n\t\t\tcontinue;\n\t\t}\n\t\tif (isJsonSchemaObject(cursor.items)) {\n\t\t\tcursor = cursor.items;\n\t\t\tcontinue;\n\t\t}\n\t\tif (isJsonSchemaObject(cursor.additionalProperties)) {\n\t\t\tcursor = cursor.additionalProperties;\n\t\t\tcontinue;\n\t\t}\n\t\treturn { schema: undefined, parentSchema, propertyKey };\n\t}\n\n\treturn { schema: cursor, parentSchema, propertyKey };\n}\n\nfunction isRequired(parentSchema: JsonSchemaObject | undefined, propertyKey: string | undefined): boolean {\n\treturn Boolean(propertyKey && parentSchema?.required?.includes(propertyKey));\n}\n\nfunction isScalarSchema(schema: JsonSchemaObject): boolean {\n\treturn getSchemaTypes(schema).some((type) => [\"string\", \"number\", \"integer\", \"boolean\"].includes(type));\n}\n\nfunction isArraySchema(schema: JsonSchemaObject): boolean {\n\treturn getSchemaTypes(schema).includes(\"array\");\n}\n\nfunction isObjectSchema(schema: JsonSchemaObject): boolean {\n\treturn getSchemaTypes(schema).includes(\"object\");\n}\n\nfunction normalizeEnumValue(value: string): string {\n\treturn value.trim().replace(/\\s+/g, \" \").toLowerCase();\n}\n\nfunction enumNormalizeHasMatch(schema: JsonSchemaObject, value: string): boolean {\n\tconst normalized = normalizeEnumValue(value);\n\treturn getEnumValues(schema).filter((candidate) => normalizeEnumValue(candidate) === normalized).length === 1;\n}\n\nfunction isEmptyObject(value: unknown): boolean {\n\treturn isRecord(value) && Object.keys(value).length === 0;\n}\n\nfunction isScalarValue(value: unknown): boolean {\n\treturn [\"string\", \"number\", \"boolean\"].includes(typeof value);\n}\n\nfunction getParentPath(path: readonly string[]): string[] {\n\treturn path.slice(0, -1);\n}\n\nfunction isNumericArrayParentIssue(\n\targs: Record<string, unknown>,\n\trootSchema: JsonSchemaObject,\n\tpath: readonly string[],\n): ToolRepairIssue | undefined {\n\tif (path.length === 0) return undefined;\n\tconst parentPath = getParentPath(path);\n\tconst parentLookup = resolveSchemaAtPath(rootSchema, parentPath);\n\tconst parentSchema = parentLookup.schema;\n\tif (!parentSchema || !isArraySchema(parentSchema) || Array.isArray(parentSchema.items)) return undefined;\n\tif (!isJsonSchemaObject(parentSchema.items)) return undefined;\n\tconst itemTypes = getSchemaTypes(parentSchema.items);\n\tif (!itemTypes.some((type) => type === \"number\" || type === \"integer\")) return undefined;\n\tconst parentValue = getValueAtPath(args, parentPath);\n\tif (!Array.isArray(parentValue) || !parentValue.every((item) => typeof item === \"string\")) return undefined;\n\treturn {\n\t\tpath: parentPath,\n\t\tpathText: formatRepairPath(parentPath),\n\t\tvalue: parentValue,\n\t\tschema: parentSchema,\n\t\tparentSchema: parentLookup.parentSchema,\n\t\tparentValue: getValueAtPath(args, getParentPath(parentPath)),\n\t\tpropertyKey: parentLookup.propertyKey,\n\t\trequired: isRequired(parentLookup.parentSchema, parentLookup.propertyKey),\n\t\tmodes: [\"stringifiedNumberInArray\"],\n\t};\n}\n\nfunction classifyModes(toolName: string, issue: Omit<ToolRepairIssue, \"modes\">): ToolRepairModeName[] {\n\tconst modes: ToolRepairModeName[] = [];\n\tconst expectedTypes = getSchemaTypes(issue.schema);\n\n\tif (toolName === \"bash\" && issue.pathText === \"command\") {\n\t\tif (Array.isArray(issue.value) && issue.value.every((item) => typeof item === \"string\")) {\n\t\t\tmodes.push(\"bashCommandArgvJoin\");\n\t\t}\n\t\tif (isRecord(issue.value)) {\n\t\t\tmodes.push(\"bashCommandUnwrap\");\n\t\t}\n\t}\n\n\tif (typeof issue.value === \"string\" && (isArraySchema(issue.schema) || isObjectSchema(issue.schema))) {\n\t\tmodes.push(\"jsonStringParse\");\n\t\tif (isObjectSchema(issue.schema)) modes.push(\"jsonObjectPropertySalvage\");\n\t}\n\tif (isArraySchema(issue.schema) && isRecord(issue.value)) {\n\t\tmodes.push(\"singleObjectWrap\", \"emptyObjectPlaceholder\");\n\t}\n\tif (isArraySchema(issue.schema) && isScalarValue(issue.value)) {\n\t\tmodes.push(\"bareScalarWrap\");\n\t}\n\tif (typeof issue.value === \"string\" && expectedTypes.some((type) => type === \"number\" || type === \"integer\")) {\n\t\tmodes.push(\"numberFromString\");\n\t}\n\tif (typeof issue.value === \"string\" && expectedTypes.includes(\"boolean\")) {\n\t\tmodes.push(\"boolFromString\");\n\t}\n\tif (typeof issue.value === \"string\" && enumNormalizeHasMatch(issue.schema, issue.value)) {\n\t\tmodes.push(\"enumCaseNormalize\");\n\t}\n\tif (Array.isArray(issue.value) && issue.value.length === 1 && isScalarSchema(issue.schema)) {\n\t\tmodes.push(\"singleElementUnwrap\");\n\t}\n\tif (!issue.required && isEmptyObject(issue.value) && isScalarSchema(issue.schema)) {\n\t\tmodes.push(\"emptyObjectPlaceholder\");\n\t}\n\tif (issue.value === null) {\n\t\tmodes.push(issue.required ? \"nullRequiredBounce\" : \"nullOptionalDrop\");\n\t}\n\n\treturn modes;\n}\n\nfunction comparePaths(a: readonly string[], b: readonly string[]): number {\n\tconst length = Math.min(a.length, b.length);\n\tfor (let index = 0; index < length; index++) {\n\t\tconst left = a[index];\n\t\tconst right = b[index];\n\t\tconst leftNumber = Number(left);\n\t\tconst rightNumber = Number(right);\n\t\tif (Number.isInteger(leftNumber) && Number.isInteger(rightNumber) && leftNumber !== rightNumber) {\n\t\t\treturn leftNumber - rightNumber;\n\t\t}\n\t\tif (left !== right) return left < right ? -1 : 1;\n\t}\n\treturn a.length - b.length;\n}\n\nexport function analyzeToolArgumentErrors(\n\ttoolName: string,\n\tschema: Tool[\"parameters\"],\n\targs: Record<string, unknown>,\n\terrors: readonly ValidationErrorLike[],\n): ToolRepairIssue[] {\n\tconst rootSchema = schema as JsonSchemaObject;\n\tconst issues = new Map<string, ToolRepairIssue>();\n\n\tfor (const error of errors) {\n\t\tif (error.keyword === \"required\") continue;\n\t\tconst path = parseInstancePath(error.instancePath);\n\t\tconst numericArrayIssue = isNumericArrayParentIssue(args, rootSchema, path);\n\t\tif (numericArrayIssue) {\n\t\t\tissues.set(numericArrayIssue.pathText, numericArrayIssue);\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst lookup = resolveSchemaAtPath(rootSchema, path);\n\t\tif (!lookup.schema) continue;\n\t\tconst value = getValueAtPath(args, path);\n\t\tconst issueBase = {\n\t\t\tpath,\n\t\t\tpathText: formatRepairPath(path),\n\t\t\tvalue,\n\t\t\tschema: lookup.schema,\n\t\t\tparentSchema: lookup.parentSchema,\n\t\t\tparentValue: getValueAtPath(args, getParentPath(path)),\n\t\t\tpropertyKey: lookup.propertyKey,\n\t\t\trequired: isRequired(lookup.parentSchema, lookup.propertyKey),\n\t\t};\n\t\tconst modes = classifyModes(toolName, issueBase);\n\t\tif (modes.length > 0) {\n\t\t\tissues.set(issueBase.pathText, { ...issueBase, modes });\n\t\t}\n\t}\n\n\treturn [...issues.values()].sort((left, right) => comparePaths(left.path, right.path));\n}\n"]}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const TOOL_REPAIR_MODE_NAMES: readonly ["nullOptionalDrop", "nullRequiredBounce", "jsonStringParse", "singleObjectWrap", "bareScalarWrap", "emptyObjectPlaceholder", "numberFromString", "boolFromString", "enumCaseNormalize", "singleElementUnwrap", "stringifiedNumberInArray", "bashCommandArgvJoin", "bashCommandUnwrap"];
|
|
1
|
+
export declare const TOOL_REPAIR_MODE_NAMES: readonly ["nullOptionalDrop", "nullRequiredBounce", "jsonStringParse", "jsonObjectPropertySalvage", "singleObjectWrap", "bareScalarWrap", "emptyObjectPlaceholder", "numberFromString", "boolFromString", "enumCaseNormalize", "propertyCaseNormalize", "singleElementUnwrap", "stringifiedNumberInArray", "bashCommandArgvJoin", "bashCommandUnwrap"];
|
|
2
2
|
export type ToolRepairModeName = (typeof TOOL_REPAIR_MODE_NAMES)[number];
|
|
3
3
|
export type ToolRepairFailureModeName = ToolRepairModeName | "other";
|
|
4
4
|
export interface ToolRepairRegistryEntry {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/utils/tool-repair/registry.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../../src/utils/tool-repair/registry.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,sBAAsB,wVAgBzB,CAAC;AAEX,MAAM,MAAM,kBAAkB,GAAG,CAAC,OAAO,sBAAsB,CAAC,CAAC,MAAM,CAAC,CAAC;AACzE,MAAM,MAAM,yBAAyB,GAAG,kBAAkB,GAAG,OAAO,CAAC;AAErE,MAAM,WAAW,uBAAuB;IACvC,IAAI,EAAE,kBAAkB,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;CACrB;AAED,eAAO,MAAM,oBAAoB,EAAE,SAAS,uBAAuB,EAgFzD,CAAC;AAIX,wBAAgB,0BAA0B,CAAC,IAAI,EAAE,kBAAkB,GAAG,uBAAuB,CAI5F;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,kBAAkB,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnF;AAED,wBAAgB,4BAA4B,CAAC,IAAI,EAAE,kBAAkB,GAAG,MAAM,CAE7E;AAED,eAAO,MAAM,8BAA8B;;;;;;;;;;;;;;;;EA6BjC,CAAC;AAEX,MAAM,MAAM,uBAAuB,GAAG,CAAC,OAAO,8BAA8B,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AAE9F,wBAAgB,6BAA6B,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAEtF","sourcesContent":["export const TOOL_REPAIR_MODE_NAMES = [\n\t\"nullOptionalDrop\",\n\t\"nullRequiredBounce\",\n\t\"jsonStringParse\",\n\t\"jsonObjectPropertySalvage\",\n\t\"singleObjectWrap\",\n\t\"bareScalarWrap\",\n\t\"emptyObjectPlaceholder\",\n\t\"numberFromString\",\n\t\"boolFromString\",\n\t\"enumCaseNormalize\",\n\t\"propertyCaseNormalize\",\n\t\"singleElementUnwrap\",\n\t\"stringifiedNumberInArray\",\n\t\"bashCommandArgvJoin\",\n\t\"bashCommandUnwrap\",\n] as const;\n\nexport type ToolRepairModeName = (typeof TOOL_REPAIR_MODE_NAMES)[number];\nexport type ToolRepairFailureModeName = ToolRepairModeName | \"other\";\n\nexport interface ToolRepairRegistryEntry {\n\tname: ToolRepairModeName;\n\tnoteTemplate: string;\n\tstandingRule: string;\n}\n\nexport const TOOL_REPAIR_REGISTRY: readonly ToolRepairRegistryEntry[] = [\n\t{\n\t\tname: \"nullOptionalDrop\",\n\t\tnoteTemplate: \"sent null for optional `{path}` -> omit the field instead\",\n\t\tstandingRule: \"Omit optional fields instead of sending null.\",\n\t},\n\t{\n\t\tname: \"nullRequiredBounce\",\n\t\tnoteTemplate: \"`{path}` is required and cannot be null -> send a real value\",\n\t\tstandingRule: \"Send real values for required fields; never send null for a required field.\",\n\t},\n\t{\n\t\tname: \"jsonStringParse\",\n\t\tnoteTemplate: \"sent `{path}` as a quoted JSON string -> send a raw JSON array/object\",\n\t\tstandingRule:\n\t\t\t\"Send raw JSON arrays/objects where the tool schema expects arrays/objects; do not quote them as JSON strings.\",\n\t},\n\t{\n\t\tname: \"jsonObjectPropertySalvage\",\n\t\tnoteTemplate:\n\t\t\t\"sent `{path}` as malformed JSON with recoverable declared properties -> keep the schema-declared properties\",\n\t\tstandingRule:\n\t\t\t\"When sending JSON objects, use strict JSON syntax with commas between properties and no extra text inside the object.\",\n\t},\n\t{\n\t\tname: \"singleObjectWrap\",\n\t\tnoteTemplate: \"sent one object where `{path}` takes a list -> wrap it in [ ]\",\n\t\tstandingRule: \"Wrap a single object in [ ] when the tool schema expects a list.\",\n\t},\n\t{\n\t\tname: \"bareScalarWrap\",\n\t\tnoteTemplate: \"sent a single value where `{path}` takes a list -> wrap it in [ ]\",\n\t\tstandingRule: \"Wrap a single scalar in [ ] when the tool schema expects a list.\",\n\t},\n\t{\n\t\tname: \"emptyObjectPlaceholder\",\n\t\tnoteTemplate: \"sent `{}` as a placeholder -> omit `{path}`; its default applies\",\n\t\tstandingRule: \"Omit defaulted object fields instead of sending `{}` placeholders.\",\n\t},\n\t{\n\t\tname: \"numberFromString\",\n\t\tnoteTemplate: \"sent `{path}` as a quoted number -> send a bare number\",\n\t\tstandingRule: \"Send bare numbers where the tool schema expects numbers; do not quote them.\",\n\t},\n\t{\n\t\tname: \"boolFromString\",\n\t\tnoteTemplate: \"sent `{path}` as a quoted boolean -> send bare true/false\",\n\t\tstandingRule: \"Send bare true/false where the tool schema expects booleans; do not quote them.\",\n\t},\n\t{\n\t\tname: \"enumCaseNormalize\",\n\t\tnoteTemplate: \"`{path}` matched a declared enum value after case/space normalization\",\n\t\tstandingRule: \"Use enum values exactly as declared, preserving case and spacing.\",\n\t},\n\t{\n\t\tname: \"propertyCaseNormalize\",\n\t\tnoteTemplate: \"sent `{path}` with different property-key casing -> use the schema key casing\",\n\t\tstandingRule: \"Use tool argument property names exactly as declared in the schema, preserving case.\",\n\t},\n\t{\n\t\tname: \"singleElementUnwrap\",\n\t\tnoteTemplate: \"sent `{path}` as a 1-item list where a single value was expected -> send the value\",\n\t\tstandingRule:\n\t\t\t\"Send a single value directly when the tool schema expects a single value; do not wrap it in a one-item list.\",\n\t},\n\t{\n\t\tname: \"stringifiedNumberInArray\",\n\t\tnoteTemplate: \"list `{path}` holds quoted numbers -> send bare numbers\",\n\t\tstandingRule: \"Use bare numbers inside number arrays; do not quote them.\",\n\t},\n\t{\n\t\tname: \"bashCommandArgvJoin\",\n\t\tnoteTemplate: \"bash takes one command string, not an argv list -> joined the argv values\",\n\t\tstandingRule: \"For bash, send one command string rather than an argv array.\",\n\t},\n\t{\n\t\tname: \"bashCommandUnwrap\",\n\t\tnoteTemplate: \"bash `command` is a string -> unwrapped the command object\",\n\t\tstandingRule: \"For bash, send `command` as a string rather than an object wrapper.\",\n\t},\n] as const;\n\nconst registryByName = new Map(TOOL_REPAIR_REGISTRY.map((entry) => [entry.name, entry]));\n\nexport function getToolRepairRegistryEntry(name: ToolRepairModeName): ToolRepairRegistryEntry {\n\tconst entry = registryByName.get(name);\n\tif (!entry) throw new Error(`Unknown tool repair mode: ${name}`);\n\treturn entry;\n}\n\nexport function formatToolRepairNote(name: ToolRepairModeName, path: string): string {\n\treturn getToolRepairRegistryEntry(name).noteTemplate.replaceAll(\"{path}\", path);\n}\n\nexport function formatToolRepairStandingRule(name: ToolRepairModeName): string {\n\treturn getToolRepairRegistryEntry(name).standingRule;\n}\n\nexport const TOOL_EXECUTION_ERROR_CATALOGUE = [\n\t{\n\t\tname: \"commandNotFound\",\n\t\tguidance: \"Command was not found; check the command name or available tools before retrying.\",\n\t\tmatches(message: string): boolean {\n\t\t\treturn /^spawn \\S+ ENOENT\\b/i.test(message) || /(?:^|\\n|:)\\s*command not found\\b/i.test(message);\n\t\t},\n\t},\n\t{\n\t\tname: \"fileNotFound\",\n\t\tguidance: \"Path was not found; list the parent directory or re-read the path before retrying.\",\n\t\tmatches(message: string): boolean {\n\t\t\treturn /\\bENOENT\\b/i.test(message) || /no such file or directory/i.test(message);\n\t\t},\n\t},\n\t{\n\t\tname: \"editOldTextNotFound\",\n\t\tguidance: \"Re-read the target file and use the exact current text before retrying.\",\n\t\tmatches(message: string): boolean {\n\t\t\treturn /(?:oldText|old text|exact text).*(?:not found|no match|failed to match|must match)/is.test(message);\n\t\t},\n\t},\n\t{\n\t\tname: \"pathOutsideCwd\",\n\t\tguidance: \"Choose a path inside the current working directory, or ask before changing scope.\",\n\t\tmatches(message: string): boolean {\n\t\t\treturn /outside (?:the )?(?:current working directory|cwd|workspace|root)/i.test(message);\n\t\t},\n\t},\n] as const;\n\nexport type ToolExecutionErrorClass = (typeof TOOL_EXECUTION_ERROR_CATALOGUE)[number][\"name\"];\n\nexport function getToolExecutionErrorGuidance(errorMessage: string): string | undefined {\n\treturn TOOL_EXECUTION_ERROR_CATALOGUE.find((entry) => entry.matches(errorMessage))?.guidance;\n}\n"]}
|
|
@@ -2,12 +2,14 @@ export const TOOL_REPAIR_MODE_NAMES = [
|
|
|
2
2
|
"nullOptionalDrop",
|
|
3
3
|
"nullRequiredBounce",
|
|
4
4
|
"jsonStringParse",
|
|
5
|
+
"jsonObjectPropertySalvage",
|
|
5
6
|
"singleObjectWrap",
|
|
6
7
|
"bareScalarWrap",
|
|
7
8
|
"emptyObjectPlaceholder",
|
|
8
9
|
"numberFromString",
|
|
9
10
|
"boolFromString",
|
|
10
11
|
"enumCaseNormalize",
|
|
12
|
+
"propertyCaseNormalize",
|
|
11
13
|
"singleElementUnwrap",
|
|
12
14
|
"stringifiedNumberInArray",
|
|
13
15
|
"bashCommandArgvJoin",
|
|
@@ -29,6 +31,11 @@ export const TOOL_REPAIR_REGISTRY = [
|
|
|
29
31
|
noteTemplate: "sent `{path}` as a quoted JSON string -> send a raw JSON array/object",
|
|
30
32
|
standingRule: "Send raw JSON arrays/objects where the tool schema expects arrays/objects; do not quote them as JSON strings.",
|
|
31
33
|
},
|
|
34
|
+
{
|
|
35
|
+
name: "jsonObjectPropertySalvage",
|
|
36
|
+
noteTemplate: "sent `{path}` as malformed JSON with recoverable declared properties -> keep the schema-declared properties",
|
|
37
|
+
standingRule: "When sending JSON objects, use strict JSON syntax with commas between properties and no extra text inside the object.",
|
|
38
|
+
},
|
|
32
39
|
{
|
|
33
40
|
name: "singleObjectWrap",
|
|
34
41
|
noteTemplate: "sent one object where `{path}` takes a list -> wrap it in [ ]",
|
|
@@ -59,6 +66,11 @@ export const TOOL_REPAIR_REGISTRY = [
|
|
|
59
66
|
noteTemplate: "`{path}` matched a declared enum value after case/space normalization",
|
|
60
67
|
standingRule: "Use enum values exactly as declared, preserving case and spacing.",
|
|
61
68
|
},
|
|
69
|
+
{
|
|
70
|
+
name: "propertyCaseNormalize",
|
|
71
|
+
noteTemplate: "sent `{path}` with different property-key casing -> use the schema key casing",
|
|
72
|
+
standingRule: "Use tool argument property names exactly as declared in the schema, preserving case.",
|
|
73
|
+
},
|
|
62
74
|
{
|
|
63
75
|
name: "singleElementUnwrap",
|
|
64
76
|
noteTemplate: "sent `{path}` as a 1-item list where a single value was expected -> send the value",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/utils/tool-repair/registry.ts"],"names":[],"mappings":"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","sourcesContent":["export const TOOL_REPAIR_MODE_NAMES = [\n\t\"nullOptionalDrop\",\n\t\"nullRequiredBounce\",\n\t\"jsonStringParse\",\n\t\"singleObjectWrap\",\n\t\"bareScalarWrap\",\n\t\"emptyObjectPlaceholder\",\n\t\"numberFromString\",\n\t\"boolFromString\",\n\t\"enumCaseNormalize\",\n\t\"singleElementUnwrap\",\n\t\"stringifiedNumberInArray\",\n\t\"bashCommandArgvJoin\",\n\t\"bashCommandUnwrap\",\n] as const;\n\nexport type ToolRepairModeName = (typeof TOOL_REPAIR_MODE_NAMES)[number];\nexport type ToolRepairFailureModeName = ToolRepairModeName | \"other\";\n\nexport interface ToolRepairRegistryEntry {\n\tname: ToolRepairModeName;\n\tnoteTemplate: string;\n\tstandingRule: string;\n}\n\nexport const TOOL_REPAIR_REGISTRY: readonly ToolRepairRegistryEntry[] = [\n\t{\n\t\tname: \"nullOptionalDrop\",\n\t\tnoteTemplate: \"sent null for optional `{path}` -> omit the field instead\",\n\t\tstandingRule: \"Omit optional fields instead of sending null.\",\n\t},\n\t{\n\t\tname: \"nullRequiredBounce\",\n\t\tnoteTemplate: \"`{path}` is required and cannot be null -> send a real value\",\n\t\tstandingRule: \"Send real values for required fields; never send null for a required field.\",\n\t},\n\t{\n\t\tname: \"jsonStringParse\",\n\t\tnoteTemplate: \"sent `{path}` as a quoted JSON string -> send a raw JSON array/object\",\n\t\tstandingRule:\n\t\t\t\"Send raw JSON arrays/objects where the tool schema expects arrays/objects; do not quote them as JSON strings.\",\n\t},\n\t{\n\t\tname: \"singleObjectWrap\",\n\t\tnoteTemplate: \"sent one object where `{path}` takes a list -> wrap it in [ ]\",\n\t\tstandingRule: \"Wrap a single object in [ ] when the tool schema expects a list.\",\n\t},\n\t{\n\t\tname: \"bareScalarWrap\",\n\t\tnoteTemplate: \"sent a single value where `{path}` takes a list -> wrap it in [ ]\",\n\t\tstandingRule: \"Wrap a single scalar in [ ] when the tool schema expects a list.\",\n\t},\n\t{\n\t\tname: \"emptyObjectPlaceholder\",\n\t\tnoteTemplate: \"sent `{}` as a placeholder -> omit `{path}`; its default applies\",\n\t\tstandingRule: \"Omit defaulted object fields instead of sending `{}` placeholders.\",\n\t},\n\t{\n\t\tname: \"numberFromString\",\n\t\tnoteTemplate: \"sent `{path}` as a quoted number -> send a bare number\",\n\t\tstandingRule: \"Send bare numbers where the tool schema expects numbers; do not quote them.\",\n\t},\n\t{\n\t\tname: \"boolFromString\",\n\t\tnoteTemplate: \"sent `{path}` as a quoted boolean -> send bare true/false\",\n\t\tstandingRule: \"Send bare true/false where the tool schema expects booleans; do not quote them.\",\n\t},\n\t{\n\t\tname: \"enumCaseNormalize\",\n\t\tnoteTemplate: \"`{path}` matched a declared enum value after case/space normalization\",\n\t\tstandingRule: \"Use enum values exactly as declared, preserving case and spacing.\",\n\t},\n\t{\n\t\tname: \"singleElementUnwrap\",\n\t\tnoteTemplate: \"sent `{path}` as a 1-item list where a single value was expected -> send the value\",\n\t\tstandingRule:\n\t\t\t\"Send a single value directly when the tool schema expects a single value; do not wrap it in a one-item list.\",\n\t},\n\t{\n\t\tname: \"stringifiedNumberInArray\",\n\t\tnoteTemplate: \"list `{path}` holds quoted numbers -> send bare numbers\",\n\t\tstandingRule: \"Use bare numbers inside number arrays; do not quote them.\",\n\t},\n\t{\n\t\tname: \"bashCommandArgvJoin\",\n\t\tnoteTemplate: \"bash takes one command string, not an argv list -> joined the argv values\",\n\t\tstandingRule: \"For bash, send one command string rather than an argv array.\",\n\t},\n\t{\n\t\tname: \"bashCommandUnwrap\",\n\t\tnoteTemplate: \"bash `command` is a string -> unwrapped the command object\",\n\t\tstandingRule: \"For bash, send `command` as a string rather than an object wrapper.\",\n\t},\n] as const;\n\nconst registryByName = new Map(TOOL_REPAIR_REGISTRY.map((entry) => [entry.name, entry]));\n\nexport function getToolRepairRegistryEntry(name: ToolRepairModeName): ToolRepairRegistryEntry {\n\tconst entry = registryByName.get(name);\n\tif (!entry) throw new Error(`Unknown tool repair mode: ${name}`);\n\treturn entry;\n}\n\nexport function formatToolRepairNote(name: ToolRepairModeName, path: string): string {\n\treturn getToolRepairRegistryEntry(name).noteTemplate.replaceAll(\"{path}\", path);\n}\n\nexport function formatToolRepairStandingRule(name: ToolRepairModeName): string {\n\treturn getToolRepairRegistryEntry(name).standingRule;\n}\n\nexport const TOOL_EXECUTION_ERROR_CATALOGUE = [\n\t{\n\t\tname: \"commandNotFound\",\n\t\tguidance: \"Command was not found; check the command name or available tools before retrying.\",\n\t\tmatches(message: string): boolean {\n\t\t\treturn /^spawn \\S+ ENOENT\\b/i.test(message) || /(?:^|\\n|:)\\s*command not found\\b/i.test(message);\n\t\t},\n\t},\n\t{\n\t\tname: \"fileNotFound\",\n\t\tguidance: \"Path was not found; list the parent directory or re-read the path before retrying.\",\n\t\tmatches(message: string): boolean {\n\t\t\treturn /\\bENOENT\\b/i.test(message) || /no such file or directory/i.test(message);\n\t\t},\n\t},\n\t{\n\t\tname: \"editOldTextNotFound\",\n\t\tguidance: \"Re-read the target file and use the exact current text before retrying.\",\n\t\tmatches(message: string): boolean {\n\t\t\treturn /(?:oldText|old text|exact text).*(?:not found|no match|failed to match|must match)/is.test(message);\n\t\t},\n\t},\n\t{\n\t\tname: \"pathOutsideCwd\",\n\t\tguidance: \"Choose a path inside the current working directory, or ask before changing scope.\",\n\t\tmatches(message: string): boolean {\n\t\t\treturn /outside (?:the )?(?:current working directory|cwd|workspace|root)/i.test(message);\n\t\t},\n\t},\n] as const;\n\nexport type ToolExecutionErrorClass = (typeof TOOL_EXECUTION_ERROR_CATALOGUE)[number][\"name\"];\n\nexport function getToolExecutionErrorGuidance(errorMessage: string): string | undefined {\n\treturn TOOL_EXECUTION_ERROR_CATALOGUE.find((entry) => entry.matches(errorMessage))?.guidance;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"registry.js","sourceRoot":"","sources":["../../../src/utils/tool-repair/registry.ts"],"names":[],"mappings":"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","sourcesContent":["export const TOOL_REPAIR_MODE_NAMES = [\n\t\"nullOptionalDrop\",\n\t\"nullRequiredBounce\",\n\t\"jsonStringParse\",\n\t\"jsonObjectPropertySalvage\",\n\t\"singleObjectWrap\",\n\t\"bareScalarWrap\",\n\t\"emptyObjectPlaceholder\",\n\t\"numberFromString\",\n\t\"boolFromString\",\n\t\"enumCaseNormalize\",\n\t\"propertyCaseNormalize\",\n\t\"singleElementUnwrap\",\n\t\"stringifiedNumberInArray\",\n\t\"bashCommandArgvJoin\",\n\t\"bashCommandUnwrap\",\n] as const;\n\nexport type ToolRepairModeName = (typeof TOOL_REPAIR_MODE_NAMES)[number];\nexport type ToolRepairFailureModeName = ToolRepairModeName | \"other\";\n\nexport interface ToolRepairRegistryEntry {\n\tname: ToolRepairModeName;\n\tnoteTemplate: string;\n\tstandingRule: string;\n}\n\nexport const TOOL_REPAIR_REGISTRY: readonly ToolRepairRegistryEntry[] = [\n\t{\n\t\tname: \"nullOptionalDrop\",\n\t\tnoteTemplate: \"sent null for optional `{path}` -> omit the field instead\",\n\t\tstandingRule: \"Omit optional fields instead of sending null.\",\n\t},\n\t{\n\t\tname: \"nullRequiredBounce\",\n\t\tnoteTemplate: \"`{path}` is required and cannot be null -> send a real value\",\n\t\tstandingRule: \"Send real values for required fields; never send null for a required field.\",\n\t},\n\t{\n\t\tname: \"jsonStringParse\",\n\t\tnoteTemplate: \"sent `{path}` as a quoted JSON string -> send a raw JSON array/object\",\n\t\tstandingRule:\n\t\t\t\"Send raw JSON arrays/objects where the tool schema expects arrays/objects; do not quote them as JSON strings.\",\n\t},\n\t{\n\t\tname: \"jsonObjectPropertySalvage\",\n\t\tnoteTemplate:\n\t\t\t\"sent `{path}` as malformed JSON with recoverable declared properties -> keep the schema-declared properties\",\n\t\tstandingRule:\n\t\t\t\"When sending JSON objects, use strict JSON syntax with commas between properties and no extra text inside the object.\",\n\t},\n\t{\n\t\tname: \"singleObjectWrap\",\n\t\tnoteTemplate: \"sent one object where `{path}` takes a list -> wrap it in [ ]\",\n\t\tstandingRule: \"Wrap a single object in [ ] when the tool schema expects a list.\",\n\t},\n\t{\n\t\tname: \"bareScalarWrap\",\n\t\tnoteTemplate: \"sent a single value where `{path}` takes a list -> wrap it in [ ]\",\n\t\tstandingRule: \"Wrap a single scalar in [ ] when the tool schema expects a list.\",\n\t},\n\t{\n\t\tname: \"emptyObjectPlaceholder\",\n\t\tnoteTemplate: \"sent `{}` as a placeholder -> omit `{path}`; its default applies\",\n\t\tstandingRule: \"Omit defaulted object fields instead of sending `{}` placeholders.\",\n\t},\n\t{\n\t\tname: \"numberFromString\",\n\t\tnoteTemplate: \"sent `{path}` as a quoted number -> send a bare number\",\n\t\tstandingRule: \"Send bare numbers where the tool schema expects numbers; do not quote them.\",\n\t},\n\t{\n\t\tname: \"boolFromString\",\n\t\tnoteTemplate: \"sent `{path}` as a quoted boolean -> send bare true/false\",\n\t\tstandingRule: \"Send bare true/false where the tool schema expects booleans; do not quote them.\",\n\t},\n\t{\n\t\tname: \"enumCaseNormalize\",\n\t\tnoteTemplate: \"`{path}` matched a declared enum value after case/space normalization\",\n\t\tstandingRule: \"Use enum values exactly as declared, preserving case and spacing.\",\n\t},\n\t{\n\t\tname: \"propertyCaseNormalize\",\n\t\tnoteTemplate: \"sent `{path}` with different property-key casing -> use the schema key casing\",\n\t\tstandingRule: \"Use tool argument property names exactly as declared in the schema, preserving case.\",\n\t},\n\t{\n\t\tname: \"singleElementUnwrap\",\n\t\tnoteTemplate: \"sent `{path}` as a 1-item list where a single value was expected -> send the value\",\n\t\tstandingRule:\n\t\t\t\"Send a single value directly when the tool schema expects a single value; do not wrap it in a one-item list.\",\n\t},\n\t{\n\t\tname: \"stringifiedNumberInArray\",\n\t\tnoteTemplate: \"list `{path}` holds quoted numbers -> send bare numbers\",\n\t\tstandingRule: \"Use bare numbers inside number arrays; do not quote them.\",\n\t},\n\t{\n\t\tname: \"bashCommandArgvJoin\",\n\t\tnoteTemplate: \"bash takes one command string, not an argv list -> joined the argv values\",\n\t\tstandingRule: \"For bash, send one command string rather than an argv array.\",\n\t},\n\t{\n\t\tname: \"bashCommandUnwrap\",\n\t\tnoteTemplate: \"bash `command` is a string -> unwrapped the command object\",\n\t\tstandingRule: \"For bash, send `command` as a string rather than an object wrapper.\",\n\t},\n] as const;\n\nconst registryByName = new Map(TOOL_REPAIR_REGISTRY.map((entry) => [entry.name, entry]));\n\nexport function getToolRepairRegistryEntry(name: ToolRepairModeName): ToolRepairRegistryEntry {\n\tconst entry = registryByName.get(name);\n\tif (!entry) throw new Error(`Unknown tool repair mode: ${name}`);\n\treturn entry;\n}\n\nexport function formatToolRepairNote(name: ToolRepairModeName, path: string): string {\n\treturn getToolRepairRegistryEntry(name).noteTemplate.replaceAll(\"{path}\", path);\n}\n\nexport function formatToolRepairStandingRule(name: ToolRepairModeName): string {\n\treturn getToolRepairRegistryEntry(name).standingRule;\n}\n\nexport const TOOL_EXECUTION_ERROR_CATALOGUE = [\n\t{\n\t\tname: \"commandNotFound\",\n\t\tguidance: \"Command was not found; check the command name or available tools before retrying.\",\n\t\tmatches(message: string): boolean {\n\t\t\treturn /^spawn \\S+ ENOENT\\b/i.test(message) || /(?:^|\\n|:)\\s*command not found\\b/i.test(message);\n\t\t},\n\t},\n\t{\n\t\tname: \"fileNotFound\",\n\t\tguidance: \"Path was not found; list the parent directory or re-read the path before retrying.\",\n\t\tmatches(message: string): boolean {\n\t\t\treturn /\\bENOENT\\b/i.test(message) || /no such file or directory/i.test(message);\n\t\t},\n\t},\n\t{\n\t\tname: \"editOldTextNotFound\",\n\t\tguidance: \"Re-read the target file and use the exact current text before retrying.\",\n\t\tmatches(message: string): boolean {\n\t\t\treturn /(?:oldText|old text|exact text).*(?:not found|no match|failed to match|must match)/is.test(message);\n\t\t},\n\t},\n\t{\n\t\tname: \"pathOutsideCwd\",\n\t\tguidance: \"Choose a path inside the current working directory, or ask before changing scope.\",\n\t\tmatches(message: string): boolean {\n\t\t\treturn /outside (?:the )?(?:current working directory|cwd|workspace|root)/i.test(message);\n\t\t},\n\t},\n] as const;\n\nexport type ToolExecutionErrorClass = (typeof TOOL_EXECUTION_ERROR_CATALOGUE)[number][\"name\"];\n\nexport function getToolExecutionErrorGuidance(errorMessage: string): string | undefined {\n\treturn TOOL_EXECUTION_ERROR_CATALOGUE.find((entry) => entry.matches(errorMessage))?.guidance;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repairer.d.ts","sourceRoot":"","sources":["../../../src/utils/tool-repair/repairer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAUN,KAAK,mBAAmB,EACxB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,kBAAkB,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;CACb;AAKD,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,cAAc,EAAE,kBAAkB,EAAE,CAAC;IACrC,OAAO,EAAE,iBAAiB,EAAE,CAAC;CAC7B;AAkND,wBAAgB,mBAAmB,CAClC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,EAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,EAAE,SAAS,mBAAmB,EAAE,EACtC,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,GAC7D,gBAAgB,GAAG,SAAS,CA0B9B;AAED,wBAAgB,mBAAmB,CAAC,cAAc,EAAE,SAAS,kBAAkB,EAAE,GAAG,MAAM,CAEzF;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAEjE","sourcesContent":["import { Compile } from \"typebox/compile\";\nimport type { Tool } from \"../../types.ts\";\nimport {\n\tanalyzeToolArgumentErrors,\n\tformatRepairPath,\n\tgetEnumValues,\n\tgetSchemaTypes,\n\tgetValueAtPath,\n\tisJsonSchemaObject,\n\tisRecord,\n\ttype JsonSchemaObject,\n\ttype ToolRepairIssue,\n\ttype ValidationErrorLike,\n} from \"./analyzer.ts\";\nimport type { ToolRepairModeName } from \"./registry.ts\";\n\nexport interface AppliedToolRepair {\n\tname: ToolRepairModeName;\n\tpath: string;\n}\n\nconst schemaValidatorCache = new WeakMap<object, ReturnType<typeof Compile>>();\nconst bashCommandWrapperKeys = new Set([\"cmd\", \"command\", \"script\"]);\n\nexport interface ToolRepairResult {\n\targs: Record<string, unknown>;\n\trepairsApplied: ToolRepairModeName[];\n\trepairs: AppliedToolRepair[];\n}\n\nfunction getSchemaValidator(schema: JsonSchemaObject): ReturnType<typeof Compile> | undefined {\n\ttry {\n\t\tconst key = schema as object;\n\t\tconst cached = schemaValidatorCache.get(key);\n\t\tif (cached) return cached;\n\t\tconst validator = Compile(schema as Tool[\"parameters\"]);\n\t\tschemaValidatorCache.set(key, validator);\n\t\treturn validator;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction schemaChecks(schema: JsonSchemaObject, value: unknown): boolean {\n\treturn getSchemaValidator(schema)?.Check(value) === true;\n}\n\nfunction setValueAtPath(target: Record<string, unknown>, path: readonly string[], value: unknown): boolean {\n\tif (path.length === 0) return false;\n\tlet cursor: unknown = target;\n\tfor (let index = 0; index < path.length - 1; index++) {\n\t\tconst segment = path[index];\n\t\tif (Array.isArray(cursor)) {\n\t\t\tconst arrayIndex = Number(segment);\n\t\t\tif (!Number.isInteger(arrayIndex)) return false;\n\t\t\tcursor = cursor[arrayIndex];\n\t\t} else if (isRecord(cursor)) {\n\t\t\tcursor = cursor[segment];\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tconst finalSegment = path[path.length - 1];\n\tif (Array.isArray(cursor)) {\n\t\tconst arrayIndex = Number(finalSegment);\n\t\tif (!Number.isInteger(arrayIndex)) return false;\n\t\tcursor[arrayIndex] = value;\n\t\treturn true;\n\t}\n\tif (isRecord(cursor)) {\n\t\tcursor[finalSegment] = value;\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nfunction deleteValueAtPath(target: Record<string, unknown>, path: readonly string[]): boolean {\n\tif (path.length === 0) return false;\n\tlet cursor: unknown = target;\n\tfor (let index = 0; index < path.length - 1; index++) {\n\t\tconst segment = path[index];\n\t\tif (Array.isArray(cursor)) {\n\t\t\tconst arrayIndex = Number(segment);\n\t\t\tif (!Number.isInteger(arrayIndex)) return false;\n\t\t\tcursor = cursor[arrayIndex];\n\t\t} else if (isRecord(cursor)) {\n\t\t\tcursor = cursor[segment];\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tconst finalSegment = path[path.length - 1];\n\tif (Array.isArray(cursor)) {\n\t\tconst arrayIndex = Number(finalSegment);\n\t\tif (!Number.isInteger(arrayIndex)) return false;\n\t\tcursor.splice(arrayIndex, 1);\n\t\treturn true;\n\t}\n\tif (isRecord(cursor)) {\n\t\tdelete cursor[finalSegment];\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nfunction normalizeEnumValue(value: string): string {\n\treturn value.trim().replace(/\\s+/g, \" \").toLowerCase();\n}\n\nfunction findNormalizedEnumValue(schema: JsonSchemaObject, value: string): string | undefined {\n\tconst normalized = normalizeEnumValue(value);\n\tconst matches = getEnumValues(schema).filter((candidate) => normalizeEnumValue(candidate) === normalized);\n\treturn matches.length === 1 ? matches[0] : undefined;\n}\n\nfunction parseJsonContainer(value: string, schema: JsonSchemaObject): unknown | undefined {\n\tconst trimmed = value.trim();\n\tif (!trimmed.startsWith(\"[\") && !trimmed.startsWith(\"{\")) return undefined;\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(trimmed);\n\t\tconst expectedTypes = getSchemaTypes(schema);\n\t\tif (expectedTypes.includes(\"array\") && !Array.isArray(parsed)) return undefined;\n\t\tif (expectedTypes.includes(\"object\") && (!isRecord(parsed) || Array.isArray(parsed))) return undefined;\n\t\treturn parsed;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction parseNumber(value: string, schema: JsonSchemaObject): number | undefined {\n\tif (value.trim() === \"\") return undefined;\n\tconst numberValue = Number(value);\n\tif (!Number.isFinite(numberValue)) return undefined;\n\treturn getSchemaTypes(schema).includes(\"integer\") && !Number.isInteger(numberValue) ? undefined : numberValue;\n}\n\nfunction coerceStringifiedNumberArray(value: unknown, schema: JsonSchemaObject): unknown[] | undefined {\n\tif (!Array.isArray(value) || !isJsonSchemaObject(schema.items)) return undefined;\n\tconst itemTypes = getSchemaTypes(schema.items);\n\tif (!itemTypes.some((type) => type === \"number\" || type === \"integer\")) return undefined;\n\tconst numbers: number[] = [];\n\tfor (const item of value) {\n\t\tif (typeof item !== \"string\") return undefined;\n\t\tconst parsed = parseNumber(item, schema.items);\n\t\tif (parsed === undefined) return undefined;\n\t\tnumbers.push(parsed);\n\t}\n\treturn numbers;\n}\n\nfunction unwrapBashCommand(value: unknown): string | undefined {\n\tif (!isRecord(value) || Object.keys(value).length !== 1) return undefined;\n\tconst [key] = Object.keys(value);\n\tif (!bashCommandWrapperKeys.has(key)) return undefined;\n\tconst command = value[key];\n\treturn typeof command === \"string\" ? command : undefined;\n}\n\nfunction transformValue(\n\tissue: ToolRepairIssue,\n\tmode: ToolRepairModeName,\n): { type: \"set\"; value: unknown } | { type: \"delete\" } | undefined {\n\tswitch (mode) {\n\t\tcase \"jsonStringParse\": {\n\t\t\treturn typeof issue.value === \"string\"\n\t\t\t\t? { type: \"set\", value: parseJsonContainer(issue.value, issue.schema) }\n\t\t\t\t: undefined;\n\t\t}\n\t\tcase \"singleObjectWrap\":\n\t\t\treturn isRecord(issue.value) ? { type: \"set\", value: [issue.value] } : undefined;\n\t\tcase \"bareScalarWrap\":\n\t\t\treturn [\"string\", \"number\", \"boolean\"].includes(typeof issue.value)\n\t\t\t\t? { type: \"set\", value: [issue.value] }\n\t\t\t\t: undefined;\n\t\tcase \"emptyObjectPlaceholder\":\n\t\t\treturn !issue.required && isRecord(issue.value) && Object.keys(issue.value).length === 0\n\t\t\t\t? { type: \"delete\" }\n\t\t\t\t: undefined;\n\t\tcase \"numberFromString\": {\n\t\t\tconst parsed = typeof issue.value === \"string\" ? parseNumber(issue.value, issue.schema) : undefined;\n\t\t\treturn parsed === undefined ? undefined : { type: \"set\", value: parsed };\n\t\t}\n\t\tcase \"boolFromString\":\n\t\t\tif (issue.value === \"true\") return { type: \"set\", value: true };\n\t\t\tif (issue.value === \"false\") return { type: \"set\", value: false };\n\t\t\treturn undefined;\n\t\tcase \"enumCaseNormalize\": {\n\t\t\tconst enumValue =\n\t\t\t\ttypeof issue.value === \"string\" ? findNormalizedEnumValue(issue.schema, issue.value) : undefined;\n\t\t\treturn enumValue === undefined ? undefined : { type: \"set\", value: enumValue };\n\t\t}\n\t\tcase \"singleElementUnwrap\":\n\t\t\treturn Array.isArray(issue.value) && issue.value.length === 1\n\t\t\t\t? { type: \"set\", value: issue.value[0] }\n\t\t\t\t: undefined;\n\t\tcase \"stringifiedNumberInArray\": {\n\t\t\tconst coerced = coerceStringifiedNumberArray(issue.value, issue.schema);\n\t\t\treturn coerced === undefined ? undefined : { type: \"set\", value: coerced };\n\t\t}\n\t\tcase \"nullOptionalDrop\":\n\t\t\treturn !issue.required && issue.value === null ? { type: \"delete\" } : undefined;\n\t\tcase \"nullRequiredBounce\":\n\t\t\treturn undefined;\n\t\tcase \"bashCommandArgvJoin\":\n\t\t\treturn Array.isArray(issue.value) && issue.value.every((item) => typeof item === \"string\")\n\t\t\t\t? { type: \"set\", value: issue.value.join(\" \") }\n\t\t\t\t: undefined;\n\t\tcase \"bashCommandUnwrap\": {\n\t\t\tconst command = unwrapBashCommand(issue.value);\n\t\t\treturn command === undefined ? undefined : { type: \"set\", value: command };\n\t\t}\n\t}\n}\n\nfunction applyTransform(\n\tcandidate: Record<string, unknown>,\n\tissue: ToolRepairIssue,\n\tmode: ToolRepairModeName,\n): Record<string, unknown> | undefined {\n\tconst transform = transformValue(issue, mode);\n\tif (!transform) return undefined;\n\tif (transform.type === \"delete\") {\n\t\treturn deleteValueAtPath(candidate, issue.path) ? candidate : undefined;\n\t}\n\tif (transform.value === undefined) return undefined;\n\tif (!schemaChecks(issue.schema, transform.value)) return undefined;\n\tif (issue.path.length === 0) {\n\t\treturn isRecord(transform.value) ? transform.value : undefined;\n\t}\n\treturn setValueAtPath(candidate, issue.path, transform.value) ? candidate : undefined;\n}\n\nfunction refreshIssueValue(candidate: Record<string, unknown>, issue: ToolRepairIssue): ToolRepairIssue {\n\treturn { ...issue, value: getValueAtPath(candidate, issue.path) };\n}\n\nexport function repairToolArguments(\n\ttoolName: string,\n\tschema: Tool[\"parameters\"],\n\targs: Record<string, unknown>,\n\terrors: readonly ValidationErrorLike[],\n\tcheckWholeArgs: (candidate: Record<string, unknown>) => boolean,\n): ToolRepairResult | undefined {\n\tconst issues = analyzeToolArgumentErrors(toolName, schema, args, errors);\n\tif (issues.length === 0) return undefined;\n\n\tlet candidate = structuredClone(args);\n\tconst repairsApplied: ToolRepairModeName[] = [];\n\tconst repairs: AppliedToolRepair[] = [];\n\n\tfor (const issue of issues) {\n\t\tif (issue.modes.includes(\"nullRequiredBounce\")) continue;\n\t\tconst currentIssue = refreshIssueValue(candidate, issue);\n\t\tfor (const mode of currentIssue.modes) {\n\t\t\tif (mode === \"nullRequiredBounce\") continue;\n\t\t\tconst nextCandidate = applyTransform(candidate, currentIssue, mode);\n\t\t\tif (nextCandidate) {\n\t\t\t\tcandidate = nextCandidate;\n\t\t\t\trepairsApplied.push(mode);\n\t\t\t\trepairs.push({ name: mode, path: formatRepairPath(currentIssue.path) });\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (repairsApplied.length === 0) return undefined;\n\tif (!checkWholeArgs(candidate)) return undefined;\n\treturn { args: candidate, repairsApplied, repairs };\n}\n\nexport function formatRepairSummary(repairsApplied: readonly ToolRepairModeName[]): string {\n\treturn repairsApplied.length === 0 ? \"none\" : repairsApplied.join(\", \");\n}\n\nexport function getRepairPathText(path: readonly string[]): string {\n\treturn formatRepairPath(path);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"repairer.d.ts","sourceRoot":"","sources":["../../../src/utils/tool-repair/repairer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,gBAAgB,CAAC;AAC3C,OAAO,EAUN,KAAK,mBAAmB,EACxB,MAAM,eAAe,CAAC;AACvB,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAExD,MAAM,WAAW,iBAAiB;IACjC,IAAI,EAAE,kBAAkB,CAAC;IACzB,IAAI,EAAE,MAAM,CAAC;CACb;AAKD,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAC9B,cAAc,EAAE,kBAAkB,EAAE,CAAC;IACrC,OAAO,EAAE,iBAAiB,EAAE,CAAC;CAC7B;AAgSD,wBAAgB,mBAAmB,CAClC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,IAAI,CAAC,YAAY,CAAC,EAC1B,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC7B,MAAM,EAAE,SAAS,mBAAmB,EAAE,EACtC,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,OAAO,GAC7D,gBAAgB,GAAG,SAAS,CAmC9B;AAED,wBAAgB,mBAAmB,CAAC,cAAc,EAAE,SAAS,kBAAkB,EAAE,GAAG,MAAM,CAEzF;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,CAEjE","sourcesContent":["import { Compile } from \"typebox/compile\";\nimport type { Tool } from \"../../types.ts\";\nimport {\n\tanalyzeToolArgumentErrors,\n\tformatRepairPath,\n\tgetEnumValues,\n\tgetSchemaTypes,\n\tgetValueAtPath,\n\tisJsonSchemaObject,\n\tisRecord,\n\ttype JsonSchemaObject,\n\ttype ToolRepairIssue,\n\ttype ValidationErrorLike,\n} from \"./analyzer.ts\";\nimport type { ToolRepairModeName } from \"./registry.ts\";\n\nexport interface AppliedToolRepair {\n\tname: ToolRepairModeName;\n\tpath: string;\n}\n\nconst schemaValidatorCache = new WeakMap<object, ReturnType<typeof Compile>>();\nconst bashCommandWrapperKeys = new Set([\"cmd\", \"command\", \"script\"]);\n\nexport interface ToolRepairResult {\n\targs: Record<string, unknown>;\n\trepairsApplied: ToolRepairModeName[];\n\trepairs: AppliedToolRepair[];\n}\n\nfunction getSchemaValidator(schema: JsonSchemaObject): ReturnType<typeof Compile> | undefined {\n\ttry {\n\t\tconst key = schema as object;\n\t\tconst cached = schemaValidatorCache.get(key);\n\t\tif (cached) return cached;\n\t\tconst validator = Compile(schema as Tool[\"parameters\"]);\n\t\tschemaValidatorCache.set(key, validator);\n\t\treturn validator;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction schemaChecks(schema: JsonSchemaObject, value: unknown): boolean {\n\treturn getSchemaValidator(schema)?.Check(value) === true;\n}\n\nfunction setValueAtPath(target: Record<string, unknown>, path: readonly string[], value: unknown): boolean {\n\tif (path.length === 0) return false;\n\tlet cursor: unknown = target;\n\tfor (let index = 0; index < path.length - 1; index++) {\n\t\tconst segment = path[index];\n\t\tif (Array.isArray(cursor)) {\n\t\t\tconst arrayIndex = Number(segment);\n\t\t\tif (!Number.isInteger(arrayIndex)) return false;\n\t\t\tcursor = cursor[arrayIndex];\n\t\t} else if (isRecord(cursor)) {\n\t\t\tcursor = cursor[segment];\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tconst finalSegment = path[path.length - 1];\n\tif (Array.isArray(cursor)) {\n\t\tconst arrayIndex = Number(finalSegment);\n\t\tif (!Number.isInteger(arrayIndex)) return false;\n\t\tcursor[arrayIndex] = value;\n\t\treturn true;\n\t}\n\tif (isRecord(cursor)) {\n\t\tcursor[finalSegment] = value;\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nfunction deleteValueAtPath(target: Record<string, unknown>, path: readonly string[]): boolean {\n\tif (path.length === 0) return false;\n\tlet cursor: unknown = target;\n\tfor (let index = 0; index < path.length - 1; index++) {\n\t\tconst segment = path[index];\n\t\tif (Array.isArray(cursor)) {\n\t\t\tconst arrayIndex = Number(segment);\n\t\t\tif (!Number.isInteger(arrayIndex)) return false;\n\t\t\tcursor = cursor[arrayIndex];\n\t\t} else if (isRecord(cursor)) {\n\t\t\tcursor = cursor[segment];\n\t\t} else {\n\t\t\treturn false;\n\t\t}\n\t}\n\n\tconst finalSegment = path[path.length - 1];\n\tif (Array.isArray(cursor)) {\n\t\tconst arrayIndex = Number(finalSegment);\n\t\tif (!Number.isInteger(arrayIndex)) return false;\n\t\tcursor.splice(arrayIndex, 1);\n\t\treturn true;\n\t}\n\tif (isRecord(cursor)) {\n\t\tdelete cursor[finalSegment];\n\t\treturn true;\n\t}\n\treturn false;\n}\n\nfunction normalizeEnumValue(value: string): string {\n\treturn value.trim().replace(/\\s+/g, \" \").toLowerCase();\n}\n\nfunction findNormalizedEnumValue(schema: JsonSchemaObject, value: string): string | undefined {\n\tconst normalized = normalizeEnumValue(value);\n\tconst matches = getEnumValues(schema).filter((candidate) => normalizeEnumValue(candidate) === normalized);\n\treturn matches.length === 1 ? matches[0] : undefined;\n}\n\nfunction parsedContainerMatchesSchemaType(parsed: unknown, schema: JsonSchemaObject): boolean {\n\tconst expectedTypes = getSchemaTypes(schema);\n\tif (expectedTypes.includes(\"array\") && !Array.isArray(parsed)) return false;\n\tif (expectedTypes.includes(\"object\") && (!isRecord(parsed) || Array.isArray(parsed))) return false;\n\treturn true;\n}\n\nfunction normalizeJsonQuoteDrift(value: string): string | undefined {\n\tif (!/[“”]/.test(value)) return undefined;\n\tconst normalizedQuotes = value.replaceAll(\"“\", '\"').replaceAll(\"”\", '\"');\n\treturn normalizedQuotes.replace(/\"([A-Za-z_][A-Za-z0-9_-]*)\\s*:\\s*\"/g, '\"$1\":\"');\n}\n\nfunction escapeRegExp(value: string): string {\n\treturn value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nfunction parseJsonLiteralToken(token: string): unknown | undefined {\n\ttry {\n\t\treturn JSON.parse(token) as unknown;\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction salvageDeclaredObjectProperties(value: string, schema: JsonSchemaObject): Record<string, unknown> | undefined {\n\tconst properties = schema.properties;\n\tif (!properties) return undefined;\n\tconst trimmed = value.trim();\n\tif (!trimmed.startsWith(\"{\") || !trimmed.endsWith(\"}\")) return undefined;\n\tconst normalized = normalizeJsonQuoteDrift(trimmed) ?? trimmed;\n\tconst salvaged: Record<string, unknown> = {};\n\tfor (const key of Object.keys(properties)) {\n\t\tconst pattern = new RegExp(\n\t\t\t`\"${escapeRegExp(key)}\"\\\\s*:\\\\s*(\"(?:\\\\\\\\.|[^\"\\\\\\\\])*\"|-?\\\\d+(?:\\\\.\\\\d+)?(?:[eE][+-]?\\\\d+)?|true|false|null)`,\n\t\t\t\"g\",\n\t\t);\n\t\tconst matches = [...normalized.matchAll(pattern)];\n\t\tif (matches.length > 1) return undefined;\n\t\tconst token = matches[0]?.[1];\n\t\tif (token === undefined) continue;\n\t\tconst parsed = parseJsonLiteralToken(token);\n\t\tif (parsed === undefined && token !== \"null\") return undefined;\n\t\tsalvaged[key] = parsed;\n\t}\n\treturn Object.keys(salvaged).length > 0 ? salvaged : undefined;\n}\n\nfunction parseJsonContainer(value: string, schema: JsonSchemaObject): unknown | undefined {\n\tconst trimmed = value.trim();\n\tif (!trimmed.startsWith(\"[\") && !trimmed.startsWith(\"{\")) return undefined;\n\tfor (const candidate of [trimmed, normalizeJsonQuoteDrift(trimmed)]) {\n\t\tif (candidate === undefined) continue;\n\t\ttry {\n\t\t\tconst parsed: unknown = JSON.parse(candidate);\n\t\t\tif (!parsedContainerMatchesSchemaType(parsed, schema)) continue;\n\t\t\treturn parsed;\n\t\t} catch {}\n\t}\n\treturn undefined;\n}\n\nfunction parseNumber(value: string, schema: JsonSchemaObject): number | undefined {\n\tif (value.trim() === \"\") return undefined;\n\tconst numberValue = Number(value);\n\tif (!Number.isFinite(numberValue)) return undefined;\n\treturn getSchemaTypes(schema).includes(\"integer\") && !Number.isInteger(numberValue) ? undefined : numberValue;\n}\n\nfunction coerceStringifiedNumberArray(value: unknown, schema: JsonSchemaObject): unknown[] | undefined {\n\tif (!Array.isArray(value) || !isJsonSchemaObject(schema.items)) return undefined;\n\tconst itemTypes = getSchemaTypes(schema.items);\n\tif (!itemTypes.some((type) => type === \"number\" || type === \"integer\")) return undefined;\n\tconst numbers: number[] = [];\n\tfor (const item of value) {\n\t\tif (typeof item !== \"string\") return undefined;\n\t\tconst parsed = parseNumber(item, schema.items);\n\t\tif (parsed === undefined) return undefined;\n\t\tnumbers.push(parsed);\n\t}\n\treturn numbers;\n}\n\nfunction unwrapBashCommand(value: unknown): string | undefined {\n\tif (!isRecord(value) || Object.keys(value).length !== 1) return undefined;\n\tconst [key] = Object.keys(value);\n\tif (!bashCommandWrapperKeys.has(key)) return undefined;\n\tconst command = value[key];\n\treturn typeof command === \"string\" ? command : undefined;\n}\n\nfunction transformValue(\n\tissue: ToolRepairIssue,\n\tmode: ToolRepairModeName,\n): { type: \"set\"; value: unknown } | { type: \"delete\" } | undefined {\n\tswitch (mode) {\n\t\tcase \"jsonStringParse\": {\n\t\t\treturn typeof issue.value === \"string\"\n\t\t\t\t? { type: \"set\", value: parseJsonContainer(issue.value, issue.schema) }\n\t\t\t\t: undefined;\n\t\t}\n\t\tcase \"jsonObjectPropertySalvage\":\n\t\t\treturn typeof issue.value === \"string\"\n\t\t\t\t? { type: \"set\", value: salvageDeclaredObjectProperties(issue.value, issue.schema) }\n\t\t\t\t: undefined;\n\t\tcase \"singleObjectWrap\":\n\t\t\treturn isRecord(issue.value) ? { type: \"set\", value: [issue.value] } : undefined;\n\t\tcase \"bareScalarWrap\":\n\t\t\treturn [\"string\", \"number\", \"boolean\"].includes(typeof issue.value)\n\t\t\t\t? { type: \"set\", value: [issue.value] }\n\t\t\t\t: undefined;\n\t\tcase \"emptyObjectPlaceholder\":\n\t\t\treturn !issue.required && isRecord(issue.value) && Object.keys(issue.value).length === 0\n\t\t\t\t? { type: \"delete\" }\n\t\t\t\t: undefined;\n\t\tcase \"numberFromString\": {\n\t\t\tconst parsed = typeof issue.value === \"string\" ? parseNumber(issue.value, issue.schema) : undefined;\n\t\t\treturn parsed === undefined ? undefined : { type: \"set\", value: parsed };\n\t\t}\n\t\tcase \"boolFromString\":\n\t\t\tif (issue.value === \"true\") return { type: \"set\", value: true };\n\t\t\tif (issue.value === \"false\") return { type: \"set\", value: false };\n\t\t\treturn undefined;\n\t\tcase \"enumCaseNormalize\": {\n\t\t\tconst enumValue =\n\t\t\t\ttypeof issue.value === \"string\" ? findNormalizedEnumValue(issue.schema, issue.value) : undefined;\n\t\t\treturn enumValue === undefined ? undefined : { type: \"set\", value: enumValue };\n\t\t}\n\t\tcase \"singleElementUnwrap\":\n\t\t\treturn Array.isArray(issue.value) && issue.value.length === 1\n\t\t\t\t? { type: \"set\", value: issue.value[0] }\n\t\t\t\t: undefined;\n\t\tcase \"stringifiedNumberInArray\": {\n\t\t\tconst coerced = coerceStringifiedNumberArray(issue.value, issue.schema);\n\t\t\treturn coerced === undefined ? undefined : { type: \"set\", value: coerced };\n\t\t}\n\t\tcase \"nullOptionalDrop\":\n\t\t\treturn !issue.required && issue.value === null ? { type: \"delete\" } : undefined;\n\t\tcase \"nullRequiredBounce\":\n\t\t\treturn undefined;\n\t\tcase \"bashCommandArgvJoin\":\n\t\t\treturn Array.isArray(issue.value) && issue.value.every((item) => typeof item === \"string\")\n\t\t\t\t? { type: \"set\", value: issue.value.join(\" \") }\n\t\t\t\t: undefined;\n\t\tcase \"bashCommandUnwrap\": {\n\t\t\tconst command = unwrapBashCommand(issue.value);\n\t\t\treturn command === undefined ? undefined : { type: \"set\", value: command };\n\t\t}\n\t}\n}\n\nfunction applyTransform(\n\tcandidate: Record<string, unknown>,\n\tissue: ToolRepairIssue,\n\tmode: ToolRepairModeName,\n): Record<string, unknown> | undefined {\n\tconst transform = transformValue(issue, mode);\n\tif (!transform) return undefined;\n\tif (transform.type === \"delete\") {\n\t\treturn deleteValueAtPath(candidate, issue.path) ? candidate : undefined;\n\t}\n\tif (transform.value === undefined) return undefined;\n\tif (!schemaChecks(issue.schema, transform.value)) return undefined;\n\tif (issue.path.length === 0) {\n\t\treturn isRecord(transform.value) ? transform.value : undefined;\n\t}\n\treturn setValueAtPath(candidate, issue.path, transform.value) ? candidate : undefined;\n}\n\nfunction refreshIssueValue(candidate: Record<string, unknown>, issue: ToolRepairIssue): ToolRepairIssue {\n\treturn { ...issue, value: getValueAtPath(candidate, issue.path) };\n}\n\nfunction normalizeRootPropertyCase(\n\targs: Record<string, unknown>,\n\tschema: Tool[\"parameters\"],\n): { args: Record<string, unknown>; repairs: AppliedToolRepair[] } | undefined {\n\tif (!isRecord(args)) return undefined;\n\tconst schemaRecord = isJsonSchemaObject(schema) ? schema : undefined;\n\tconst properties = schemaRecord?.properties;\n\tif (!properties) return undefined;\n\tconst canonicalByLower = new Map<string, string[]>();\n\tfor (const key of Object.keys(properties)) {\n\t\tconst lower = key.toLowerCase();\n\t\tcanonicalByLower.set(lower, [...(canonicalByLower.get(lower) ?? []), key]);\n\t}\n\tconst next = { ...args };\n\tconst repairs: AppliedToolRepair[] = [];\n\tfor (const key of Object.keys(args)) {\n\t\tconst matches = canonicalByLower.get(key.toLowerCase()) ?? [];\n\t\tconst canonical = matches.length === 1 ? matches[0] : undefined;\n\t\tif (!canonical || canonical === key || canonical in next) continue;\n\t\tnext[canonical] = next[key];\n\t\tdelete next[key];\n\t\trepairs.push({ name: \"propertyCaseNormalize\", path: canonical });\n\t}\n\treturn repairs.length > 0 ? { args: next, repairs } : undefined;\n}\n\nexport function repairToolArguments(\n\ttoolName: string,\n\tschema: Tool[\"parameters\"],\n\targs: Record<string, unknown>,\n\terrors: readonly ValidationErrorLike[],\n\tcheckWholeArgs: (candidate: Record<string, unknown>) => boolean,\n): ToolRepairResult | undefined {\n\tlet candidate = structuredClone(args);\n\tconst repairsApplied: ToolRepairModeName[] = [];\n\tconst repairs: AppliedToolRepair[] = [];\n\tconst caseNormalized = normalizeRootPropertyCase(candidate, schema);\n\tif (caseNormalized) {\n\t\tcandidate = caseNormalized.args;\n\t\trepairsApplied.push(...caseNormalized.repairs.map((repair) => repair.name));\n\t\trepairs.push(...caseNormalized.repairs);\n\t}\n\tconst issues = analyzeToolArgumentErrors(toolName, schema, args, errors);\n\tif (issues.length === 0) {\n\t\treturn repairsApplied.length > 0 && checkWholeArgs(candidate)\n\t\t\t? { args: candidate, repairsApplied, repairs }\n\t\t\t: undefined;\n\t}\n\n\tfor (const issue of issues) {\n\t\tif (issue.modes.includes(\"nullRequiredBounce\")) continue;\n\t\tconst currentIssue = refreshIssueValue(candidate, issue);\n\t\tfor (const mode of currentIssue.modes) {\n\t\t\tif (mode === \"nullRequiredBounce\") continue;\n\t\t\tconst nextCandidate = applyTransform(candidate, currentIssue, mode);\n\t\t\tif (nextCandidate) {\n\t\t\t\tcandidate = nextCandidate;\n\t\t\t\trepairsApplied.push(mode);\n\t\t\t\trepairs.push({ name: mode, path: formatRepairPath(currentIssue.path) });\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\n\tif (repairsApplied.length === 0) return undefined;\n\tif (!checkWholeArgs(candidate)) return undefined;\n\treturn { args: candidate, repairsApplied, repairs };\n}\n\nexport function formatRepairSummary(repairsApplied: readonly ToolRepairModeName[]): string {\n\treturn repairsApplied.length === 0 ? \"none\" : repairsApplied.join(\", \");\n}\n\nexport function getRepairPathText(path: readonly string[]): string {\n\treturn formatRepairPath(path);\n}\n"]}
|
|
@@ -93,22 +93,71 @@ function findNormalizedEnumValue(schema, value) {
|
|
|
93
93
|
const matches = getEnumValues(schema).filter((candidate) => normalizeEnumValue(candidate) === normalized);
|
|
94
94
|
return matches.length === 1 ? matches[0] : undefined;
|
|
95
95
|
}
|
|
96
|
-
function
|
|
97
|
-
const
|
|
98
|
-
if (
|
|
96
|
+
function parsedContainerMatchesSchemaType(parsed, schema) {
|
|
97
|
+
const expectedTypes = getSchemaTypes(schema);
|
|
98
|
+
if (expectedTypes.includes("array") && !Array.isArray(parsed))
|
|
99
|
+
return false;
|
|
100
|
+
if (expectedTypes.includes("object") && (!isRecord(parsed) || Array.isArray(parsed)))
|
|
101
|
+
return false;
|
|
102
|
+
return true;
|
|
103
|
+
}
|
|
104
|
+
function normalizeJsonQuoteDrift(value) {
|
|
105
|
+
if (!/[“”]/.test(value))
|
|
99
106
|
return undefined;
|
|
107
|
+
const normalizedQuotes = value.replaceAll("“", '"').replaceAll("”", '"');
|
|
108
|
+
return normalizedQuotes.replace(/"([A-Za-z_][A-Za-z0-9_-]*)\s*:\s*"/g, '"$1":"');
|
|
109
|
+
}
|
|
110
|
+
function escapeRegExp(value) {
|
|
111
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
112
|
+
}
|
|
113
|
+
function parseJsonLiteralToken(token) {
|
|
100
114
|
try {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
115
|
+
return JSON.parse(token);
|
|
116
|
+
}
|
|
117
|
+
catch {
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
function salvageDeclaredObjectProperties(value, schema) {
|
|
122
|
+
const properties = schema.properties;
|
|
123
|
+
if (!properties)
|
|
124
|
+
return undefined;
|
|
125
|
+
const trimmed = value.trim();
|
|
126
|
+
if (!trimmed.startsWith("{") || !trimmed.endsWith("}"))
|
|
127
|
+
return undefined;
|
|
128
|
+
const normalized = normalizeJsonQuoteDrift(trimmed) ?? trimmed;
|
|
129
|
+
const salvaged = {};
|
|
130
|
+
for (const key of Object.keys(properties)) {
|
|
131
|
+
const pattern = new RegExp(`"${escapeRegExp(key)}"\\s*:\\s*("(?:\\\\.|[^"\\\\])*"|-?\\d+(?:\\.\\d+)?(?:[eE][+-]?\\d+)?|true|false|null)`, "g");
|
|
132
|
+
const matches = [...normalized.matchAll(pattern)];
|
|
133
|
+
if (matches.length > 1)
|
|
104
134
|
return undefined;
|
|
105
|
-
|
|
135
|
+
const token = matches[0]?.[1];
|
|
136
|
+
if (token === undefined)
|
|
137
|
+
continue;
|
|
138
|
+
const parsed = parseJsonLiteralToken(token);
|
|
139
|
+
if (parsed === undefined && token !== "null")
|
|
106
140
|
return undefined;
|
|
107
|
-
|
|
141
|
+
salvaged[key] = parsed;
|
|
108
142
|
}
|
|
109
|
-
|
|
143
|
+
return Object.keys(salvaged).length > 0 ? salvaged : undefined;
|
|
144
|
+
}
|
|
145
|
+
function parseJsonContainer(value, schema) {
|
|
146
|
+
const trimmed = value.trim();
|
|
147
|
+
if (!trimmed.startsWith("[") && !trimmed.startsWith("{"))
|
|
110
148
|
return undefined;
|
|
149
|
+
for (const candidate of [trimmed, normalizeJsonQuoteDrift(trimmed)]) {
|
|
150
|
+
if (candidate === undefined)
|
|
151
|
+
continue;
|
|
152
|
+
try {
|
|
153
|
+
const parsed = JSON.parse(candidate);
|
|
154
|
+
if (!parsedContainerMatchesSchemaType(parsed, schema))
|
|
155
|
+
continue;
|
|
156
|
+
return parsed;
|
|
157
|
+
}
|
|
158
|
+
catch { }
|
|
111
159
|
}
|
|
160
|
+
return undefined;
|
|
112
161
|
}
|
|
113
162
|
function parseNumber(value, schema) {
|
|
114
163
|
if (value.trim() === "")
|
|
@@ -151,6 +200,10 @@ function transformValue(issue, mode) {
|
|
|
151
200
|
? { type: "set", value: parseJsonContainer(issue.value, issue.schema) }
|
|
152
201
|
: undefined;
|
|
153
202
|
}
|
|
203
|
+
case "jsonObjectPropertySalvage":
|
|
204
|
+
return typeof issue.value === "string"
|
|
205
|
+
? { type: "set", value: salvageDeclaredObjectProperties(issue.value, issue.schema) }
|
|
206
|
+
: undefined;
|
|
154
207
|
case "singleObjectWrap":
|
|
155
208
|
return isRecord(issue.value) ? { type: "set", value: [issue.value] } : undefined;
|
|
156
209
|
case "bareScalarWrap":
|
|
@@ -216,13 +269,47 @@ function applyTransform(candidate, issue, mode) {
|
|
|
216
269
|
function refreshIssueValue(candidate, issue) {
|
|
217
270
|
return { ...issue, value: getValueAtPath(candidate, issue.path) };
|
|
218
271
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
272
|
+
function normalizeRootPropertyCase(args, schema) {
|
|
273
|
+
if (!isRecord(args))
|
|
274
|
+
return undefined;
|
|
275
|
+
const schemaRecord = isJsonSchemaObject(schema) ? schema : undefined;
|
|
276
|
+
const properties = schemaRecord?.properties;
|
|
277
|
+
if (!properties)
|
|
222
278
|
return undefined;
|
|
279
|
+
const canonicalByLower = new Map();
|
|
280
|
+
for (const key of Object.keys(properties)) {
|
|
281
|
+
const lower = key.toLowerCase();
|
|
282
|
+
canonicalByLower.set(lower, [...(canonicalByLower.get(lower) ?? []), key]);
|
|
283
|
+
}
|
|
284
|
+
const next = { ...args };
|
|
285
|
+
const repairs = [];
|
|
286
|
+
for (const key of Object.keys(args)) {
|
|
287
|
+
const matches = canonicalByLower.get(key.toLowerCase()) ?? [];
|
|
288
|
+
const canonical = matches.length === 1 ? matches[0] : undefined;
|
|
289
|
+
if (!canonical || canonical === key || canonical in next)
|
|
290
|
+
continue;
|
|
291
|
+
next[canonical] = next[key];
|
|
292
|
+
delete next[key];
|
|
293
|
+
repairs.push({ name: "propertyCaseNormalize", path: canonical });
|
|
294
|
+
}
|
|
295
|
+
return repairs.length > 0 ? { args: next, repairs } : undefined;
|
|
296
|
+
}
|
|
297
|
+
export function repairToolArguments(toolName, schema, args, errors, checkWholeArgs) {
|
|
223
298
|
let candidate = structuredClone(args);
|
|
224
299
|
const repairsApplied = [];
|
|
225
300
|
const repairs = [];
|
|
301
|
+
const caseNormalized = normalizeRootPropertyCase(candidate, schema);
|
|
302
|
+
if (caseNormalized) {
|
|
303
|
+
candidate = caseNormalized.args;
|
|
304
|
+
repairsApplied.push(...caseNormalized.repairs.map((repair) => repair.name));
|
|
305
|
+
repairs.push(...caseNormalized.repairs);
|
|
306
|
+
}
|
|
307
|
+
const issues = analyzeToolArgumentErrors(toolName, schema, args, errors);
|
|
308
|
+
if (issues.length === 0) {
|
|
309
|
+
return repairsApplied.length > 0 && checkWholeArgs(candidate)
|
|
310
|
+
? { args: candidate, repairsApplied, repairs }
|
|
311
|
+
: undefined;
|
|
312
|
+
}
|
|
226
313
|
for (const issue of issues) {
|
|
227
314
|
if (issue.modes.includes("nullRequiredBounce"))
|
|
228
315
|
continue;
|