@caupulican/pi-ai 0.81.13 → 0.81.15

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.
@@ -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 parseJsonContainer(value, schema) {
97
- const trimmed = value.trim();
98
- if (!trimmed.startsWith("[") && !trimmed.startsWith("{"))
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
- const parsed = JSON.parse(trimmed);
102
- const expectedTypes = getSchemaTypes(schema);
103
- if (expectedTypes.includes("array") && !Array.isArray(parsed))
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
- if (expectedTypes.includes("object") && (!isRecord(parsed) || Array.isArray(parsed)))
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
- return parsed;
141
+ salvaged[key] = parsed;
108
142
  }
109
- catch {
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
- export function repairToolArguments(toolName, schema, args, errors, checkWholeArgs) {
220
- const issues = analyzeToolArgumentErrors(toolName, schema, args, errors);
221
- if (issues.length === 0)
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;
@@ -1 +1 @@
1
- {"version":3,"file":"repairer.js","sourceRoot":"","sources":["../../../src/utils/tool-repair/repairer.ts"],"names":[],"mappings":"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","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.js","sourceRoot":"","sources":["../../../src/utils/tool-repair/repairer.ts"],"names":[],"mappings":"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","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"]}
@@ -1,5 +1,5 @@
1
1
  import type { Tool, ToolCall } from "../../types.ts";
2
- export type TextToolProtocolParseFailure = "overlap" | "mixed-prose" | "unrecognized";
2
+ export type TextToolProtocolParseFailure = "overlap" | "mixed-prose" | "unrecognized" | "unknown-tool" | "validation-failed";
3
3
  export interface ParsedTextToolCalls {
4
4
  calls: ToolCall[];
5
5
  text: string;
@@ -1 +1 @@
1
- {"version":3,"file":"text-protocol.d.ts","sourceRoot":"","sources":["../../../src/utils/tool-repair/text-protocol.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAErD,MAAM,MAAM,4BAA4B,GAAG,SAAS,GAAG,aAAa,GAAG,cAAc,CAAC;AAEtF,MAAM,WAAW,mBAAmB;IACnC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,4BAA4B,CAAC;CACvC;AAED,MAAM,MAAM,uBAAuB,GAAG,UAAU,GAAG,WAAW,GAAG,aAAa,CAAC;AAE/E,MAAM,WAAW,uBAAuB;IACvC,OAAO,CAAC,EAAE,uBAAuB,CAAC;CAClC;AAgLD,wBAAgB,gCAAgC,CAC/C,MAAM,EAAE,OAAO,GAAG,uBAAuB,GAAG,SAAS,GACnD,uBAAuB,GAAG,SAAS,CAIrC;AAQD,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,EAAE,OAAO,CAAC,EAAE,uBAAuB,GAAG,MAAM,CAehH;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,IAAI,EAAE,GAAG,mBAAmB,CAajG","sourcesContent":["import type { Tool, ToolCall } from \"../../types.ts\";\n\nexport type TextToolProtocolParseFailure = \"overlap\" | \"mixed-prose\" | \"unrecognized\";\n\nexport interface ParsedTextToolCalls {\n\tcalls: ToolCall[];\n\ttext: string;\n\tattempted: boolean;\n\tfailure?: TextToolProtocolParseFailure;\n}\n\nexport type TextToolProtocolVariant = \"tool-tag\" | \"tool-call\" | \"fenced-json\";\n\nexport interface TextToolProtocolOptions {\n\tvariant?: TextToolProtocolVariant;\n}\n\ntype EnvelopeKind = \"pi_call\" | \"tool_call\" | \"fenced_json\";\n\ninterface EnvelopeMatch {\n\tkind: EnvelopeKind;\n\tstart: number;\n\tend: number;\n\tname?: string;\n\tbody: string;\n}\n\nconst MAX_SCHEMA_CHARS = 600;\nconst DEFAULT_TEXT_TOOL_PROTOCOL_VARIANT: TextToolProtocolVariant = \"tool-tag\";\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction compactJson(value: unknown, maxChars = MAX_SCHEMA_CHARS): string {\n\tconst json = JSON.stringify(value);\n\tif (json.length <= maxChars) return json;\n\treturn `${json.slice(0, maxChars - 1)}…`;\n}\n\nfunction escapeAttribute(value: string): string {\n\treturn value.replace(/&/g, \"&amp;\").replace(/\"/g, \"&quot;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n}\n\nfunction unescapeAttribute(value: string): string {\n\treturn value\n\t\t.replace(/&quot;/g, '\"')\n\t\t.replace(/&lt;/g, \"<\")\n\t\t.replace(/&gt;/g, \">\")\n\t\t.replace(/&amp;/g, \"&\");\n}\n\nfunction knownToolNames(tools: readonly Tool[]): Set<string> {\n\treturn new Set(tools.map((tool) => tool.name));\n}\n\nfunction findToolEnvelopes(text: string): EnvelopeMatch[] {\n\tconst matches: EnvelopeMatch[] = [];\n\tconst piCallEnvelope = /<pi:call\\s+name=\"([^\"]+)\"\\s*>([\\s\\S]*?)<\\/pi:call>/g;\n\tfor (const match of text.matchAll(piCallEnvelope)) {\n\t\tmatches.push({\n\t\t\tkind: \"pi_call\",\n\t\t\tstart: match.index,\n\t\t\tend: match.index + match[0].length,\n\t\t\tname: unescapeAttribute(match[1] ?? \"\"),\n\t\t\tbody: match[2] ?? \"\",\n\t\t});\n\t}\n\n\tconst toolCallEnvelope = /<tool_call>([\\s\\S]*?)<\\/tool_call>/g;\n\tfor (const match of text.matchAll(toolCallEnvelope)) {\n\t\tmatches.push({\n\t\t\tkind: \"tool_call\",\n\t\t\tstart: match.index,\n\t\t\tend: match.index + match[0].length,\n\t\t\tbody: match[1] ?? \"\",\n\t\t});\n\t}\n\n\tconst fence = /```(?:tool|tool_call)\\s*\\n([\\s\\S]*?)\\n?```/gi;\n\tfor (const match of text.matchAll(fence)) {\n\t\tmatches.push({\n\t\t\tkind: \"fenced_json\",\n\t\t\tstart: match.index,\n\t\t\tend: match.index + match[0].length,\n\t\t\tbody: match[1] ?? \"\",\n\t\t});\n\t}\n\n\treturn matches.sort((a, b) => a.start - b.start);\n}\n\nfunction hasOverlap(matches: readonly EnvelopeMatch[]): boolean {\n\tlet previousEnd = -1;\n\tfor (const match of matches) {\n\t\tif (match.start < previousEnd) return true;\n\t\tpreviousEnd = match.end;\n\t}\n\treturn false;\n}\n\nfunction remainingText(text: string, matches: readonly EnvelopeMatch[]): string {\n\tlet cursor = 0;\n\tconst pieces: string[] = [];\n\tfor (const match of matches) {\n\t\tpieces.push(text.slice(cursor, match.start));\n\t\tcursor = match.end;\n\t}\n\tpieces.push(text.slice(cursor));\n\treturn pieces.join(\"\");\n}\n\nfunction coerceArguments(value: unknown): {\n\targuments: Record<string, unknown>;\n\trawArguments?: Record<string, unknown>;\n} {\n\tif (isRecord(value)) return { arguments: value };\n\treturn { arguments: value as Record<string, unknown>, rawArguments: { value } };\n}\n\nfunction parseJsonValue(raw: string): { ok: true; value: unknown } | { ok: false } {\n\ttry {\n\t\treturn { ok: true, value: JSON.parse(raw) as unknown };\n\t} catch {\n\t\treturn { ok: false };\n\t}\n}\n\nfunction parseJsonObject(raw: string): Record<string, unknown> | undefined {\n\tconst parsed = parseJsonValue(raw);\n\treturn parsed.ok && isRecord(parsed.value) ? parsed.value : undefined;\n}\n\nfunction textToolErrorMessage(name: string, names: readonly string[]): string | undefined {\n\tif (names.includes(name)) return undefined;\n\treturn `Unknown tool \"${name}\". Valid tools: ${names.join(\", \")}.`;\n}\n\nfunction extractNameFromMalformedJson(raw: string): string | undefined {\n\tconst match = /\"(?:name|tool)\"\\s*:\\s*\"([^\"]+)\"/.exec(raw);\n\treturn match?.[1];\n}\n\nfunction parsePiCallEnvelope(match: EnvelopeMatch, names: readonly string[], index: number): ToolCall | undefined {\n\tif (!match.name) return undefined;\n\tconst parsed = parseJsonValue(match.body);\n\tconst args = parsed.ok ? coerceArguments(parsed.value) : coerceArguments(match.body.trim());\n\treturn {\n\t\ttype: \"toolCall\",\n\t\tid: `text-tool-${index}`,\n\t\tname: match.name,\n\t\targuments: args.arguments,\n\t\trawArguments: parsed.ok ? args.rawArguments : { text: match.body.trim() },\n\t\tsource: \"text-protocol\",\n\t\terrorMessage: textToolErrorMessage(match.name, names),\n\t};\n}\n\nfunction parseEnvelope(match: EnvelopeMatch, names: readonly string[], index: number): ToolCall | undefined {\n\tif (match.kind === \"pi_call\") return parsePiCallEnvelope(match, names, index);\n\n\tconst parsed = parseJsonObject(match.body);\n\tif (!parsed) {\n\t\tconst name = extractNameFromMalformedJson(match.body);\n\t\tif (!name) return undefined;\n\t\treturn {\n\t\t\ttype: \"toolCall\",\n\t\t\tid: `text-tool-${index}`,\n\t\t\tname,\n\t\t\targuments: match.body.trim() as unknown as Record<string, unknown>,\n\t\t\trawArguments: { text: match.body.trim() },\n\t\t\tsource: \"text-protocol\",\n\t\t\terrorMessage: textToolErrorMessage(name, names),\n\t\t};\n\t}\n\n\tconst nameValue = parsed.name ?? parsed.tool;\n\tif (typeof nameValue !== \"string\") return undefined;\n\tconst argsValue = parsed.arguments ?? parsed.args ?? {};\n\tconst args = coerceArguments(argsValue);\n\treturn {\n\t\ttype: \"toolCall\",\n\t\tid: `text-tool-${index}`,\n\t\tname: nameValue,\n\t\targuments: args.arguments,\n\t\trawArguments: args.rawArguments,\n\t\tsource: \"text-protocol\",\n\t\terrorMessage: textToolErrorMessage(nameValue, names),\n\t};\n}\n\nexport function normalizeTextToolProtocolOptions(\n\toption: boolean | TextToolProtocolOptions | undefined,\n): TextToolProtocolOptions | undefined {\n\tif (!option) return undefined;\n\tif (option === true) return { variant: DEFAULT_TEXT_TOOL_PROTOCOL_VARIANT };\n\treturn { variant: option.variant ?? DEFAULT_TEXT_TOOL_PROTOCOL_VARIANT };\n}\n\nfunction formatVariantEnvelope(variant: TextToolProtocolVariant, toolName: string, argsJson: string): string {\n\tif (variant === \"tool-call\") return `<tool_call>{\"name\":\"${toolName}\",\"arguments\":${argsJson}}</tool_call>`;\n\tif (variant === \"fenced-json\") return `\\`\\`\\`tool_call\\n{\"name\":\"${toolName}\",\"arguments\":${argsJson}}\\n\\`\\`\\``;\n\treturn `<pi:call name=\"${escapeAttribute(toolName)}\">${argsJson}</pi:call>`;\n}\n\nexport function generateTextToolProtocolPrimer(tools: readonly Tool[], options?: TextToolProtocolOptions): string {\n\tif (tools.length === 0) return \"\";\n\tconst variant = options?.variant ?? DEFAULT_TEXT_TOOL_PROTOCOL_VARIANT;\n\tconst lines = [\n\t\t\"Text tool-call protocol is enabled.\",\n\t\t\"When calling tools, output only one or more envelopes and no prose:\",\n\t\tformatVariantEnvelope(variant, \"TOOL_NAME\", '{\"argument\":\"value\"}'),\n\t\t\"Available tools:\",\n\t];\n\tfor (const tool of tools) {\n\t\tlines.push(`- ${escapeAttribute(tool.name)}: ${tool.description}; args schema ${compactJson(tool.parameters)}`);\n\t}\n\tconst exampleTool = tools[0];\n\tlines.push(\"Examples:\", formatVariantEnvelope(variant, exampleTool.name, \"{}\"));\n\treturn lines.join(\"\\n\");\n}\n\nexport function parseTextToolCalls(text: string, knownTools: readonly Tool[]): ParsedTextToolCalls {\n\tif (knownTools.length === 0) return { calls: [], text, attempted: false };\n\tconst matches = findToolEnvelopes(text);\n\tif (matches.length === 0) return { calls: [], text, attempted: false };\n\tif (hasOverlap(matches)) return { calls: [], text, attempted: true, failure: \"overlap\" };\n\tconst remainder = remainingText(text, matches);\n\tconst names = [...knownToolNames(knownTools)];\n\tconst calls = matches\n\t\t.map((match, index) => parseEnvelope(match, names, index + 1))\n\t\t.filter((call): call is ToolCall => call !== undefined);\n\treturn calls.length > 0\n\t\t? { calls, text: remainder.trim(), attempted: true }\n\t\t: { calls: [], text, attempted: true, failure: \"unrecognized\" };\n}\n"]}
1
+ {"version":3,"file":"text-protocol.d.ts","sourceRoot":"","sources":["../../../src/utils/tool-repair/text-protocol.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAErD,MAAM,MAAM,4BAA4B,GACrC,SAAS,GACT,aAAa,GACb,cAAc,GACd,cAAc,GACd,mBAAmB,CAAC;AAEvB,MAAM,WAAW,mBAAmB;IACnC,KAAK,EAAE,QAAQ,EAAE,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,4BAA4B,CAAC;CACvC;AAED,MAAM,MAAM,uBAAuB,GAAG,UAAU,GAAG,WAAW,GAAG,aAAa,CAAC;AAE/E,MAAM,WAAW,uBAAuB;IACvC,OAAO,CAAC,EAAE,uBAAuB,CAAC;CAClC;AA+QD,wBAAgB,gCAAgC,CAC/C,MAAM,EAAE,OAAO,GAAG,uBAAuB,GAAG,SAAS,GACnD,uBAAuB,GAAG,SAAS,CAIrC;AAuJD,wBAAgB,8BAA8B,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,EAAE,OAAO,CAAC,EAAE,uBAAuB,GAAG,MAAM,CAchH;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,IAAI,EAAE,GAAG,mBAAmB,CAajG","sourcesContent":["import type { Tool, ToolCall } from \"../../types.ts\";\n\nexport type TextToolProtocolParseFailure =\n\t| \"overlap\"\n\t| \"mixed-prose\"\n\t| \"unrecognized\"\n\t| \"unknown-tool\"\n\t| \"validation-failed\";\n\nexport interface ParsedTextToolCalls {\n\tcalls: ToolCall[];\n\ttext: string;\n\tattempted: boolean;\n\tfailure?: TextToolProtocolParseFailure;\n}\n\nexport type TextToolProtocolVariant = \"tool-tag\" | \"tool-call\" | \"fenced-json\";\n\nexport interface TextToolProtocolOptions {\n\tvariant?: TextToolProtocolVariant;\n}\n\ntype EnvelopeKind = \"pi_call\" | \"tool_call\" | \"fenced_json\";\n\ninterface EnvelopeMatch {\n\tkind: EnvelopeKind;\n\tstart: number;\n\tend: number;\n\tname?: string;\n\tbody: string;\n}\n\nconst DEFAULT_TEXT_TOOL_PROTOCOL_VARIANT: TextToolProtocolVariant = \"tool-tag\";\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n\treturn typeof value === \"object\" && value !== null && !Array.isArray(value);\n}\n\nfunction escapeAttribute(value: string): string {\n\treturn value.replace(/&/g, \"&amp;\").replace(/\"/g, \"&quot;\").replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n}\n\nfunction unescapeAttribute(value: string): string {\n\treturn value\n\t\t.replace(/&quot;/g, '\"')\n\t\t.replace(/&lt;/g, \"<\")\n\t\t.replace(/&gt;/g, \">\")\n\t\t.replace(/&amp;/g, \"&\");\n}\n\nfunction knownToolNames(tools: readonly Tool[]): Set<string> {\n\treturn new Set(tools.map((tool) => tool.name));\n}\n\nfunction findJsonObjectEnd(text: string, start: number): number | undefined {\n\tlet index = start;\n\twhile (/\\s/.test(text[index] ?? \"\")) index++;\n\tif (text[index] !== \"{\") return undefined;\n\tlet depth = 0;\n\tlet inString = false;\n\tlet escaped = false;\n\tfor (; index < text.length; index++) {\n\t\tconst char = text[index];\n\t\tif (inString) {\n\t\t\tif (escaped) {\n\t\t\t\tescaped = false;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (char === \"\\\\\") {\n\t\t\t\tescaped = true;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (char === '\"') inString = false;\n\t\t\tcontinue;\n\t\t}\n\t\tif (char === '\"') {\n\t\t\tinString = true;\n\t\t\tcontinue;\n\t\t}\n\t\tif (char === \"{\") depth++;\n\t\tif (char === \"}\") {\n\t\t\tdepth--;\n\t\t\tif (depth === 0) return index + 1;\n\t\t}\n\t}\n\treturn undefined;\n}\n\nfunction isInsideMatch(index: number, matches: readonly EnvelopeMatch[]): boolean {\n\treturn matches.some((match) => index >= match.start && index < match.end);\n}\n\nfunction findToolEnvelopes(text: string): EnvelopeMatch[] {\n\tconst matches: EnvelopeMatch[] = [];\n\tconst piCallEnvelope = /<pi:call\\s+name=([\"'])(.*?)\\1\\s*>([\\s\\S]*?)<\\/pi:call\\s*>/g;\n\tfor (const match of text.matchAll(piCallEnvelope)) {\n\t\tmatches.push({\n\t\t\tkind: \"pi_call\",\n\t\t\tstart: match.index,\n\t\t\tend: match.index + match[0].length,\n\t\t\tname: unescapeAttribute(match[2] ?? \"\"),\n\t\t\tbody: match[3] ?? \"\",\n\t\t});\n\t}\n\n\tconst openPiCallEnvelope = /<pi:call\\s+name=([\"'])(.*?)\\1\\s*>/g;\n\tfor (const match of text.matchAll(openPiCallEnvelope)) {\n\t\tif (isInsideMatch(match.index, matches)) continue;\n\t\tconst bodyStart = match.index + match[0].length;\n\t\tconst bodyEnd = findJsonObjectEnd(text, bodyStart);\n\t\tif (bodyEnd === undefined) continue;\n\t\tmatches.push({\n\t\t\tkind: \"pi_call\",\n\t\t\tstart: match.index,\n\t\t\tend: bodyEnd,\n\t\t\tname: unescapeAttribute(match[2] ?? \"\"),\n\t\t\tbody: text.slice(bodyStart, bodyEnd),\n\t\t});\n\t}\n\n\tconst toolCallEnvelope = /<tool_call>([\\s\\S]*?)<\\/tool_call>/g;\n\tfor (const match of text.matchAll(toolCallEnvelope)) {\n\t\tmatches.push({\n\t\t\tkind: \"tool_call\",\n\t\t\tstart: match.index,\n\t\t\tend: match.index + match[0].length,\n\t\t\tbody: match[1] ?? \"\",\n\t\t});\n\t}\n\n\tconst fence = /```(?:tool|tool_call|json)\\s*\\n([\\s\\S]*?)\\n?```/gi;\n\tfor (const match of text.matchAll(fence)) {\n\t\tmatches.push({\n\t\t\tkind: \"fenced_json\",\n\t\t\tstart: match.index,\n\t\t\tend: match.index + match[0].length,\n\t\t\tbody: match[1] ?? \"\",\n\t\t});\n\t}\n\n\treturn matches.sort((a, b) => a.start - b.start);\n}\n\nfunction hasOverlap(matches: readonly EnvelopeMatch[]): boolean {\n\tlet previousEnd = -1;\n\tfor (const match of matches) {\n\t\tif (match.start < previousEnd) return true;\n\t\tpreviousEnd = match.end;\n\t}\n\treturn false;\n}\n\nfunction remainingText(text: string, matches: readonly EnvelopeMatch[]): string {\n\tlet cursor = 0;\n\tconst pieces: string[] = [];\n\tfor (const match of matches) {\n\t\tpieces.push(text.slice(cursor, match.start));\n\t\tcursor = match.end;\n\t}\n\tpieces.push(text.slice(cursor));\n\treturn pieces.join(\"\");\n}\n\nfunction coerceArguments(value: unknown): {\n\targuments: Record<string, unknown>;\n\trawArguments?: Record<string, unknown>;\n} {\n\tif (isRecord(value)) return { arguments: value };\n\treturn { arguments: value as Record<string, unknown>, rawArguments: { value } };\n}\n\nfunction normalizeSingleQuotedJson(raw: string): string | undefined {\n\tconst trimmed = raw.trim();\n\tif (!/^\\{[\\s\\S]*\\}$/.test(trimmed)) return undefined;\n\tif (!/'[^'\\\\]*(?:\\\\.[^'\\\\]*)*'/.test(trimmed)) return undefined;\n\treturn trimmed.replace(/'([^'\\\\]*(?:\\\\.[^'\\\\]*)*)'/g, (_match, inner: string) => {\n\t\treturn JSON.stringify(inner.replace(/\\\\'/g, \"'\"));\n\t});\n}\n\nfunction normalizeBareJsonObject(raw: string): string | undefined {\n\tconst trimmed = raw.trim();\n\tif (!/^\\{[\\s\\S]*\\}$/.test(trimmed)) return undefined;\n\tlet changed = false;\n\tlet normalized = trimmed.replace(\n\t\t/([{,]\\s*)([A-Za-z_][A-Za-z0-9_-]*)(\\s*:)/g,\n\t\t(_match, prefix: string, key: string, suffix: string) => {\n\t\t\tchanged = true;\n\t\t\treturn `${prefix}${JSON.stringify(key)}${suffix}`;\n\t\t},\n\t);\n\tnormalized = normalized.replace(/:\\s*([A-Za-z_./-][A-Za-z0-9_./:-]*)(?=\\s*[,}])/g, (_match, value: string) => {\n\t\tif ([\"true\", \"false\", \"null\"].includes(value)) return `:${value}`;\n\t\tchanged = true;\n\t\treturn `:${JSON.stringify(value)}`;\n\t});\n\treturn changed ? normalized : undefined;\n}\n\nfunction normalizedJsonCandidates(raw: string): string[] {\n\tconst candidates: string[] = [];\n\tconst objectEnd = findJsonObjectEnd(raw, 0);\n\tif (objectEnd !== undefined && raw.slice(objectEnd).trim()) candidates.push(raw.slice(0, objectEnd));\n\tconst singleQuoted = normalizeSingleQuotedJson(raw);\n\tif (singleQuoted) candidates.push(singleQuoted);\n\tconst bare = normalizeBareJsonObject(raw);\n\tif (bare) candidates.push(bare);\n\tconst singleQuotedBare = singleQuoted ? normalizeBareJsonObject(singleQuoted) : undefined;\n\tif (singleQuotedBare) candidates.push(singleQuotedBare);\n\treturn candidates;\n}\n\nfunction parseJsonValue(raw: string): { ok: true; value: unknown } | { ok: false } {\n\ttry {\n\t\treturn { ok: true, value: JSON.parse(raw) as unknown };\n\t} catch {\n\t\tfor (const normalized of normalizedJsonCandidates(raw)) {\n\t\t\ttry {\n\t\t\t\treturn { ok: true, value: JSON.parse(normalized) as unknown };\n\t\t\t} catch {\n\t\t\t\t// Try the next bounded normalization candidate.\n\t\t\t}\n\t\t}\n\t\treturn { ok: false };\n\t}\n}\n\nfunction parseJsonObject(raw: string): Record<string, unknown> | undefined {\n\tconst parsed = parseJsonValue(raw);\n\treturn parsed.ok && isRecord(parsed.value) ? parsed.value : undefined;\n}\n\nfunction textToolErrorMessage(name: string, names: readonly string[]): string | undefined {\n\tif (names.includes(name)) return undefined;\n\treturn `Unknown tool \"${name}\". Valid tools: ${names.join(\", \")}.`;\n}\n\nfunction extractNameFromMalformedJson(raw: string): string | undefined {\n\tconst match = /\"(?:name|tool)\"\\s*:\\s*\"([^\"]+)\"/.exec(raw);\n\treturn match?.[1];\n}\n\nfunction parsePiCallEnvelope(match: EnvelopeMatch, names: readonly string[], index: number): ToolCall | undefined {\n\tif (!match.name) return undefined;\n\tconst parsed = parseJsonValue(match.body);\n\tconst args = parsed.ok ? coerceArguments(parsed.value) : coerceArguments(match.body.trim());\n\treturn {\n\t\ttype: \"toolCall\",\n\t\tid: `text-tool-${index}`,\n\t\tname: match.name,\n\t\targuments: args.arguments,\n\t\trawArguments: parsed.ok ? args.rawArguments : { text: match.body.trim() },\n\t\tsource: \"text-protocol\",\n\t\terrorMessage: textToolErrorMessage(match.name, names),\n\t};\n}\n\nfunction parseEnvelope(match: EnvelopeMatch, names: readonly string[], index: number): ToolCall | undefined {\n\tif (match.kind === \"pi_call\") return parsePiCallEnvelope(match, names, index);\n\n\tconst parsed = parseJsonObject(match.body);\n\tif (!parsed) {\n\t\tconst name = extractNameFromMalformedJson(match.body);\n\t\tif (!name) return undefined;\n\t\treturn {\n\t\t\ttype: \"toolCall\",\n\t\t\tid: `text-tool-${index}`,\n\t\t\tname,\n\t\t\targuments: match.body.trim() as unknown as Record<string, unknown>,\n\t\t\trawArguments: { text: match.body.trim() },\n\t\t\tsource: \"text-protocol\",\n\t\t\terrorMessage: textToolErrorMessage(name, names),\n\t\t};\n\t}\n\n\tconst wrappedTool = isRecord(parsed.tool) ? parsed.tool : undefined;\n\tconst nameValue = parsed.name ?? (typeof parsed.tool === \"string\" ? parsed.tool : undefined) ?? wrappedTool?.name;\n\tif (typeof nameValue !== \"string\") return undefined;\n\tconst argsValue = parsed.arguments ?? parsed.args ?? wrappedTool?.arguments ?? wrappedTool?.args ?? {};\n\tconst args = coerceArguments(argsValue);\n\treturn {\n\t\ttype: \"toolCall\",\n\t\tid: `text-tool-${index}`,\n\t\tname: nameValue,\n\t\targuments: args.arguments,\n\t\trawArguments: args.rawArguments,\n\t\tsource: \"text-protocol\",\n\t\terrorMessage: textToolErrorMessage(nameValue, names),\n\t};\n}\n\nexport function normalizeTextToolProtocolOptions(\n\toption: boolean | TextToolProtocolOptions | undefined,\n): TextToolProtocolOptions | undefined {\n\tif (!option) return undefined;\n\tif (option === true) return { variant: DEFAULT_TEXT_TOOL_PROTOCOL_VARIANT };\n\treturn { variant: option.variant ?? DEFAULT_TEXT_TOOL_PROTOCOL_VARIANT };\n}\n\nfunction formatVariantEnvelope(variant: TextToolProtocolVariant, toolName: string, argsJson: string): string {\n\tif (variant === \"tool-call\") return `<tool_call>{\"name\":\"${toolName}\",\"arguments\":${argsJson}}</tool_call>`;\n\tif (variant === \"fenced-json\") return `\\`\\`\\`tool_call\\n{\"name\":\"${toolName}\",\"arguments\":${argsJson}}\\n\\`\\`\\``;\n\treturn `<pi:call name=\"${escapeAttribute(toolName)}\">${argsJson}</pi:call>`;\n}\n\nfunction schemaRecord(value: unknown): Record<string, unknown> | undefined {\n\treturn isRecord(value) ? value : undefined;\n}\n\nfunction firstString(value: unknown): string | undefined {\n\treturn typeof value === \"string\" ? value : undefined;\n}\n\nfunction schemaType(schema: Record<string, unknown>): string | undefined {\n\tconst type = schema.type;\n\tif (typeof type === \"string\") return type;\n\tif (!Array.isArray(type)) return undefined;\n\treturn type.filter(firstString).find((entry) => entry !== \"null\");\n}\n\nfunction stringExampleForProperty(propertyName: string | undefined): string {\n\tif (propertyName === \"path\") return \"src/index.ts\";\n\tif (propertyName === \"command\") return \"echo ok\";\n\tif (propertyName === \"oldText\") return \"foo\";\n\tif (propertyName === \"newText\") return \"bar\";\n\tif (propertyName === \"content\") return \"text\";\n\treturn \"value\";\n}\n\nfunction exampleValueForSchema(schemaValue: unknown, propertyName?: string): unknown {\n\tconst schema = schemaRecord(schemaValue);\n\tif (!schema) return stringExampleForProperty(propertyName);\n\tconst constValue = schema.const;\n\tif (constValue !== undefined) return constValue;\n\tconst enumValues = Array.isArray(schema.enum) ? schema.enum : [];\n\tif (enumValues.length > 0) return enumValues[0];\n\tconst defaultValue = schema.default;\n\tif (defaultValue !== undefined) return defaultValue;\n\tconst type = schemaType(schema);\n\tif (type === \"number\" || type === \"integer\") return 1;\n\tif (type === \"boolean\") return true;\n\tif (type === \"array\") return [exampleValueForSchema(schema.items, propertyName)];\n\tif (type === \"object\") return exampleArgumentsForParameters(schema);\n\treturn stringExampleForProperty(propertyName);\n}\n\nfunction requiredPropertyNames(parameters: Record<string, unknown> | undefined): string[] {\n\treturn Array.isArray(parameters?.required) ? parameters.required.filter(firstString) : [];\n}\n\nfunction exampleArgumentsForParameters(parametersValue: unknown): Record<string, unknown> {\n\tconst parameters = schemaRecord(parametersValue);\n\tconst properties = schemaRecord(parameters?.properties);\n\tif (!properties) return {};\n\tconst args: Record<string, unknown> = {};\n\tfor (const name of requiredPropertyNames(parameters)) {\n\t\targs[name] = exampleValueForSchema(properties[name], name);\n\t}\n\treturn args;\n}\n\nfunction typeLabel(schemaValue: unknown): string {\n\tconst schema = schemaRecord(schemaValue);\n\tif (!schema) return \"string\";\n\tconst enumValues = Array.isArray(schema.enum) ? schema.enum : [];\n\tif (enumValues.length > 0 && enumValues.every((entry) => [\"string\", \"number\", \"boolean\"].includes(typeof entry))) {\n\t\treturn enumValues.map(String).join(\"|\");\n\t}\n\tconst type = schemaType(schema);\n\tif (type === \"integer\" || type === \"number\") return \"number\";\n\tif (type === \"boolean\") return \"bool\";\n\tif (type === \"array\") return `${typeLabel(schema.items)}[]`;\n\tif (type === \"object\") {\n\t\tconst properties = schemaRecord(schema.properties);\n\t\tif (!properties) return \"{}\";\n\t\tconst entries = Object.entries(properties)\n\t\t\t.slice(0, 4)\n\t\t\t.map(([name, value]) => `${name}:${typeLabel(value)}`);\n\t\tconst suffix = Object.keys(properties).length > entries.length ? \",...\" : \"\";\n\t\treturn `{${entries.join(\",\")}${suffix}}`;\n\t}\n\treturn \"string\";\n}\n\nfunction orderedPropertyNames(properties: Record<string, unknown>, required: readonly string[]): string[] {\n\tconst requiredSet = new Set(required);\n\treturn [\n\t\t...required.filter((name) => name in properties),\n\t\t...Object.keys(properties).filter((name) => !requiredSet.has(name)),\n\t];\n}\n\nfunction formatDefault(value: unknown): string {\n\tconst json = JSON.stringify(value);\n\treturn json ? `=${json}` : \"\";\n}\n\nfunction formatToolProjection(tool: Tool): string {\n\tconst parameters = schemaRecord(tool.parameters);\n\tconst properties = schemaRecord(parameters?.properties);\n\tconst required = requiredPropertyNames(parameters);\n\tconst requiredSet = new Set(required);\n\tconst args = properties\n\t\t? orderedPropertyNames(properties, required)\n\t\t\t\t.map((name) => {\n\t\t\t\t\tconst schema = schemaRecord(properties[name]);\n\t\t\t\t\tconst optional = requiredSet.has(name) ? \"\" : \"?\";\n\t\t\t\t\tconst defaultText = schema && \"default\" in schema ? formatDefault(schema.default) : \"\";\n\t\t\t\t\treturn `${name}:${typeLabel(schema)}${optional}${defaultText}`;\n\t\t\t\t})\n\t\t\t\t.join(\", \")\n\t\t: \"\";\n\tconst description = tool.description.replace(/\\s+/g, \" \").trim();\n\treturn `${tool.name}(${args}) - ${description}`;\n}\n\nfunction toolHasArrayParameter(tool: Tool): boolean {\n\tconst parameters = schemaRecord(tool.parameters);\n\tconst properties = schemaRecord(parameters?.properties);\n\tif (!properties) return false;\n\treturn Object.values(properties).some((schemaValue) => schemaType(schemaRecord(schemaValue) ?? {}) === \"array\");\n}\n\nfunction exampleTools(tools: readonly Tool[]): Tool[] {\n\tconst examples: Tool[] = [];\n\tconst readTool = tools.find((tool) => tool.name === \"read\");\n\tif (readTool) examples.push(readTool);\n\tif (examples.length === 0) examples.push(tools[0]);\n\tconst editTool = tools.find((tool) => tool.name === \"edit\" && !examples.includes(tool));\n\tconst arrayTool = editTool ?? tools.find((tool) => !examples.includes(tool) && toolHasArrayParameter(tool));\n\tif (arrayTool) examples.push(arrayTool);\n\treturn examples;\n}\n\nfunction protocolHeader(variant: TextToolProtocolVariant): string[] {\n\treturn [\n\t\t\"Text tool-call protocol is enabled.\",\n\t\t\"When calling tools, output only one or more envelopes and no prose:\",\n\t\tformatVariantEnvelope(variant, \"TOOL\", '{\"arg\":\"value\"}'),\n\t\t\"Arguments must be valid JSON objects. Use double quotes for JSON keys and string values. Arrays are JSON arrays [ ], never quoted strings. Omit optional args you do not need - do not send null.\",\n\t\t\"User requests about files, directories, searches, edits, writes, or shell commands require a tool envelope first; do not describe results yourself.\",\n\t\t'If the user asks to read /tmp/example.txt, output exactly: <pi:call name=\"read\">{\"path\":\"/tmp/example.txt\"}</pi:call>',\n\t\t'For any request to read a file path, call read with {\"path\":\"THE_PATH\"}; never output {\"file_path\":..., \"content\":...} or invented file contents.',\n\t\t\"Never write raw shell commands such as read -t PATH, cat PATH, or ls PATH; use a tool-call envelope instead.\",\n\t\t\"Never output markdown code blocks, raw shell commands, file paths, or invented tool results instead of a tool call; use the envelope and wait for the real result.\",\n\t];\n}\n\nexport function generateTextToolProtocolPrimer(tools: readonly Tool[], options?: TextToolProtocolOptions): string {\n\tif (tools.length === 0) return \"\";\n\tconst variant = options?.variant ?? DEFAULT_TEXT_TOOL_PROTOCOL_VARIANT;\n\tconst lines = [...protocolHeader(variant), \"Examples:\"];\n\tfor (const tool of exampleTools(tools)) {\n\t\tlines.push(\n\t\t\tformatVariantEnvelope(variant, tool.name, JSON.stringify(exampleArgumentsForParameters(tool.parameters))),\n\t\t);\n\t}\n\tlines.push(\"Available tools:\");\n\tfor (const tool of tools) {\n\t\tlines.push(formatToolProjection(tool));\n\t}\n\treturn lines.join(\"\\n\");\n}\n\nexport function parseTextToolCalls(text: string, knownTools: readonly Tool[]): ParsedTextToolCalls {\n\tif (knownTools.length === 0) return { calls: [], text, attempted: false };\n\tconst matches = findToolEnvelopes(text);\n\tif (matches.length === 0) return { calls: [], text, attempted: false };\n\tif (hasOverlap(matches)) return { calls: [], text, attempted: true, failure: \"overlap\" };\n\tconst remainder = remainingText(text, matches);\n\tconst names = [...knownToolNames(knownTools)];\n\tconst calls = matches\n\t\t.map((match, index) => parseEnvelope(match, names, index + 1))\n\t\t.filter((call): call is ToolCall => call !== undefined);\n\treturn calls.length > 0\n\t\t? { calls, text: remainder.trim(), attempted: true }\n\t\t: { calls: [], text, attempted: true, failure: \"unrecognized\" };\n}\n"]}