( tool: Tool<AnyObject, Output>, toolUseResult: Output, )
| 4723 | } |
| 4724 | |
| 4725 | function createToolResultMessage<Output>( |
| 4726 | tool: Tool<AnyObject, Output>, |
| 4727 | toolUseResult: Output, |
| 4728 | ): UserMessage { |
| 4729 | try { |
| 4730 | const result = tool.mapToolResultToToolResultBlockParam(toolUseResult, '1') |
| 4731 | |
| 4732 | // If the result contains image content blocks, preserve them as is |
| 4733 | if ( |
| 4734 | Array.isArray(result.content) && |
| 4735 | result.content.some(block => block.type === 'image') |
| 4736 | ) { |
| 4737 | return createUserMessage({ |
| 4738 | content: result.content as ContentBlockParam[], |
| 4739 | isMeta: true, |
| 4740 | }) |
| 4741 | } |
| 4742 | |
| 4743 | // For string content, use raw string — jsonStringify would escape \n→\\n, |
| 4744 | // wasting ~1 token per newline (a 2000-line @-file = ~1000 wasted tokens). |
| 4745 | // Keep jsonStringify for array/object content where structure matters. |
| 4746 | const contentStr = |
| 4747 | typeof result.content === 'string' |
| 4748 | ? result.content |
| 4749 | : jsonStringify(result.content) |
| 4750 | return createUserMessage({ |
| 4751 | content: `Result of calling the ${tool.name} tool:\n${contentStr}`, |
| 4752 | isMeta: true, |
| 4753 | }) |
| 4754 | } catch { |
| 4755 | return createUserMessage({ |
| 4756 | content: `Result of calling the ${tool.name} tool: Error`, |
| 4757 | isMeta: true, |
| 4758 | }) |
| 4759 | } |
| 4760 | } |
| 4761 | |
| 4762 | function createToolUseMessage( |
| 4763 | toolName: string, |
no test coverage detected