Convert a parsed JSON object into a ToolCall iff its shape and tool name are recognized.
(obj: any, knownToolNames: ReadonlySet<string>)
| 386 | |
| 387 | /** Convert a parsed JSON object into a ToolCall iff its shape and tool name are recognized. */ |
| 388 | function parsedObjectToToolCall(obj: any, knownToolNames: ReadonlySet<string>): ToolCall | null { |
| 389 | if (!obj || typeof obj !== 'object') return null; |
| 390 | |
| 391 | // Shape 1: { name, arguments | parameters | input } |
| 392 | if (typeof obj.name === 'string' && knownToolNames.has(obj.name)) { |
| 393 | const args = obj.arguments ?? obj.parameters ?? obj.input ?? {}; |
| 394 | return { |
| 395 | id: typeof obj.id === 'string' ? obj.id : `recovered_${Date.now()}_${Math.floor(Math.random() * 1000)}`, |
| 396 | type: 'function', |
| 397 | function: { |
| 398 | name: obj.name, |
| 399 | arguments: typeof args === 'string' ? args : JSON.stringify(args), |
| 400 | }, |
| 401 | }; |
| 402 | } |
| 403 | |
| 404 | // Shape 2: { function: { name, arguments } } (OpenAI legacy) |
| 405 | if (obj.function && typeof obj.function.name === 'string' && knownToolNames.has(obj.function.name)) { |
| 406 | const args = obj.function.arguments ?? {}; |
| 407 | return { |
| 408 | id: typeof obj.id === 'string' ? obj.id : `recovered_${Date.now()}_${Math.floor(Math.random() * 1000)}`, |
| 409 | type: 'function', |
| 410 | function: { |
| 411 | name: obj.function.name, |
| 412 | arguments: typeof args === 'string' ? args : JSON.stringify(args), |
| 413 | }, |
| 414 | }; |
| 415 | } |
| 416 | |
| 417 | // Shape 3: { tool, args } (Claude-style) |
| 418 | if (typeof obj.tool === 'string' && knownToolNames.has(obj.tool)) { |
| 419 | const args = obj.args ?? obj.arguments ?? obj.parameters ?? {}; |
| 420 | return { |
| 421 | id: typeof obj.id === 'string' ? obj.id : `recovered_${Date.now()}_${Math.floor(Math.random() * 1000)}`, |
| 422 | type: 'function', |
| 423 | function: { |
| 424 | name: obj.tool, |
| 425 | arguments: typeof args === 'string' ? args : JSON.stringify(args), |
| 426 | }, |
| 427 | }; |
| 428 | } |
| 429 | |
| 430 | return null; |
| 431 | } |
| 432 | |
| 433 | /** Find the first balanced JSON object in a string (depth-counting on braces, respecting strings). */ |
| 434 | function findFirstJsonObject(text: string): string | null { |
no test coverage detected