Build the trailing message pair for a fork child. Mirrors ``buildForkedMessages()`` from ``forkSubagent.ts:107-169``. For prompt-cache sharing, every fork child must produce a byte-identical API request prefix. This function: 1. Clones the parent assistant message (preserving ever
(
directive: str,
parent_assistant: AssistantMessage | None,
)
| 181 | |
| 182 | |
| 183 | def build_forked_messages( |
| 184 | directive: str, |
| 185 | parent_assistant: AssistantMessage | None, |
| 186 | ) -> list[Message]: |
| 187 | """Build the trailing message pair for a fork child. |
| 188 | |
| 189 | Mirrors ``buildForkedMessages()`` from ``forkSubagent.ts:107-169``. |
| 190 | |
| 191 | For prompt-cache sharing, every fork child must produce a byte-identical |
| 192 | API request prefix. This function: |
| 193 | |
| 194 | 1. Clones the parent assistant message (preserving every ``tool_use`` |
| 195 | block and its ID). |
| 196 | 2. For each ``tool_use`` block, emits a ``tool_result`` with the |
| 197 | constant ``FORK_PLACEHOLDER_RESULT`` text. |
| 198 | 3. Appends a single user message containing all those placeholder |
| 199 | ``tool_result`` blocks followed by the boilerplate-wrapped |
| 200 | directive. |
| 201 | |
| 202 | Result: ``[cloned_assistant, user_message]``. Only the final text block |
| 203 | differs per child, maximizing cache hits. |
| 204 | |
| 205 | If the parent assistant has no ``tool_use`` blocks (or no parent at |
| 206 | all), we fall back to a single user message carrying the directive. |
| 207 | """ |
| 208 | if parent_assistant is None: |
| 209 | return [ |
| 210 | create_user_message(content=[TextBlock(text=build_child_message(directive))]) |
| 211 | ] |
| 212 | |
| 213 | tool_use_blocks = _collect_tool_use_blocks(parent_assistant.content) |
| 214 | |
| 215 | if not tool_use_blocks: |
| 216 | return [ |
| 217 | create_user_message(content=[TextBlock(text=build_child_message(directive))]) |
| 218 | ] |
| 219 | |
| 220 | # Clone the assistant message — new uuid, deep-copied content list — so |
| 221 | # we never mutate the parent's message in place. |
| 222 | cloned_content: list[Any] = [] |
| 223 | for block in parent_assistant.content if isinstance(parent_assistant.content, list) else []: |
| 224 | cloned_content.append(copy.deepcopy(block)) |
| 225 | cloned_assistant = AssistantMessage( |
| 226 | content=cloned_content, |
| 227 | uuid=str(uuid4()), |
| 228 | timestamp=parent_assistant.timestamp, |
| 229 | stop_reason=parent_assistant.stop_reason, |
| 230 | model=parent_assistant.model, |
| 231 | usage=parent_assistant.usage, |
| 232 | requestId=parent_assistant.requestId, |
| 233 | ) |
| 234 | |
| 235 | # Build placeholder tool_result blocks for every parent tool_use block. |
| 236 | tool_result_blocks: list[ToolResultBlock] = [] |
| 237 | for block in tool_use_blocks: |
| 238 | tool_use_id = _get_attr(block, "id", "") or "" |
| 239 | tool_result_blocks.append( |
| 240 | ToolResultBlock( |