( directive: string, assistantMessage: AssistantMessage, )
| 105 | * Only the final text block differs per child, maximizing cache hits. |
| 106 | */ |
| 107 | export function buildForkedMessages( |
| 108 | directive: string, |
| 109 | assistantMessage: AssistantMessage, |
| 110 | ): MessageType[] { |
| 111 | // Clone the assistant message to avoid mutating the original, keeping all |
| 112 | // content blocks (thinking, text, and every tool_use) |
| 113 | const fullAssistantMessage: AssistantMessage = { |
| 114 | ...assistantMessage, |
| 115 | uuid: randomUUID(), |
| 116 | message: { |
| 117 | ...assistantMessage.message, |
| 118 | content: [...assistantMessage.message.content], |
| 119 | }, |
| 120 | } |
| 121 | |
| 122 | // Collect all tool_use blocks from the assistant message |
| 123 | const toolUseBlocks = assistantMessage.message.content.filter( |
| 124 | (block): block is BetaToolUseBlock => block.type === 'tool_use', |
| 125 | ) |
| 126 | |
| 127 | if (toolUseBlocks.length === 0) { |
| 128 | logForDebugging( |
| 129 | `No tool_use blocks found in assistant message for fork directive: ${directive.slice(0, 50)}...`, |
| 130 | { level: 'error' }, |
| 131 | ) |
| 132 | return [ |
| 133 | createUserMessage({ |
| 134 | content: [ |
| 135 | { type: 'text' as const, text: buildChildMessage(directive) }, |
| 136 | ], |
| 137 | }), |
| 138 | ] |
| 139 | } |
| 140 | |
| 141 | // Build tool_result blocks for every tool_use, all with identical placeholder text |
| 142 | const toolResultBlocks = toolUseBlocks.map(block => ({ |
| 143 | type: 'tool_result' as const, |
| 144 | tool_use_id: block.id, |
| 145 | content: [ |
| 146 | { |
| 147 | type: 'text' as const, |
| 148 | text: FORK_PLACEHOLDER_RESULT, |
| 149 | }, |
| 150 | ], |
| 151 | })) |
| 152 | |
| 153 | // Build a single user message: all placeholder tool_results + the per-child directive |
| 154 | // TODO(smoosh): this text sibling creates a [tool_result, text] pattern on the wire |
| 155 | // (renders as </function_results>\n\nHuman:<text>). One-off per-child construction, |
| 156 | // not a repeated teacher, so low-priority. If we ever care, use smooshIntoToolResult |
| 157 | // from src/utils/messages.ts to fold the directive into the last tool_result.content. |
| 158 | const toolResultMessage = createUserMessage({ |
| 159 | content: [ |
| 160 | ...toolResultBlocks, |
| 161 | { |
| 162 | type: 'text' as const, |
| 163 | text: buildChildMessage(directive), |
| 164 | }, |
no test coverage detected