( tool: T, input: z.infer<T['inputSchema']>, )
| 683 | // Strips fields that were added by normalizeToolInput before sending to API |
| 684 | // (e.g., plan field from ExitPlanModeV2 which has an empty input schema) |
| 685 | export function normalizeToolInputForAPI<T extends Tool>( |
| 686 | tool: T, |
| 687 | input: z.infer<T['inputSchema']>, |
| 688 | ): z.infer<T['inputSchema']> { |
| 689 | switch (tool.name) { |
| 690 | case EXIT_PLAN_MODE_V2_TOOL_NAME: { |
| 691 | // Strip injected fields before sending to API (schema expects empty object) |
| 692 | if ( |
| 693 | input && |
| 694 | typeof input === 'object' && |
| 695 | ('plan' in input || 'planFilePath' in input) |
| 696 | ) { |
| 697 | const { plan, planFilePath, ...rest } = input as Record<string, unknown> |
| 698 | return rest as z.infer<T['inputSchema']> |
| 699 | } |
| 700 | return input |
| 701 | } |
| 702 | case FileEditTool.name: { |
| 703 | // Strip synthetic old_string/new_string/replace_all from OLD sessions |
| 704 | // that were resumed from transcripts written before PR #20357, where |
| 705 | // normalizeToolInput used to synthesize these. Needed so old --resume'd |
| 706 | // transcripts don't send whole-file copies to the API. New sessions |
| 707 | // don't need this (synthesis moved to emission time). |
| 708 | if (input && typeof input === 'object' && 'edits' in input) { |
| 709 | const { old_string, new_string, replace_all, ...rest } = |
| 710 | input as Record<string, unknown> |
| 711 | return rest as z.infer<T['inputSchema']> |
| 712 | } |
| 713 | return input |
| 714 | } |
| 715 | default: |
| 716 | return input |
| 717 | } |
| 718 | } |
no outgoing calls
no test coverage detected