( msg: SDKMessage, opts?: ConvertOptions, )
| 167 | * Convert an SDKMessage to REPL message format |
| 168 | */ |
| 169 | export function convertSDKMessage( |
| 170 | msg: SDKMessage, |
| 171 | opts?: ConvertOptions, |
| 172 | ): ConvertedMessage { |
| 173 | switch (msg.type) { |
| 174 | case 'assistant': |
| 175 | return { |
| 176 | type: 'message', |
| 177 | message: convertAssistantMessage(msg as SDKAssistantMessage), |
| 178 | } |
| 179 | |
| 180 | case 'user': { |
| 181 | const userMsg = msg as SDKUserMessage |
| 182 | const content = userMsg.message?.content |
| 183 | // Tool result messages from the remote server need to be converted so |
| 184 | // they render and collapse like local tool results. Detect via content |
| 185 | // shape (tool_result blocks) — parent_tool_use_id is NOT reliable: the |
| 186 | // agent-side normalizeMessage() hardcodes it to null for top-level |
| 187 | // tool results, so it can't distinguish tool results from prompt echoes. |
| 188 | const isToolResult = |
| 189 | Array.isArray(content) && content.some(b => b.type === 'tool_result') |
| 190 | if (opts?.convertToolResults && isToolResult) { |
| 191 | return { |
| 192 | type: 'message', |
| 193 | message: createUserMessage({ |
| 194 | content, |
| 195 | toolUseResult: userMsg.tool_use_result, |
| 196 | uuid: userMsg.uuid, |
| 197 | timestamp: userMsg.timestamp, |
| 198 | }), |
| 199 | } |
| 200 | } |
| 201 | // When converting historical events, user-typed messages need to be |
| 202 | // rendered (they weren't added locally by the REPL). Skip tool_results |
| 203 | // here — already handled above. |
| 204 | if (opts?.convertUserTextMessages && !isToolResult) { |
| 205 | if (typeof content === 'string' || Array.isArray(content)) { |
| 206 | return { |
| 207 | type: 'message', |
| 208 | message: createUserMessage({ |
| 209 | content, |
| 210 | toolUseResult: userMsg.tool_use_result, |
| 211 | uuid: userMsg.uuid, |
| 212 | timestamp: userMsg.timestamp, |
| 213 | }), |
| 214 | } |
| 215 | } |
| 216 | } |
| 217 | // User-typed messages (string content) are already added locally by REPL. |
| 218 | // In CCR mode, all user messages are ignored (tool results handled differently). |
| 219 | return { type: 'ignored' } |
| 220 | } |
| 221 | |
| 222 | case 'stream_event': |
| 223 | return { |
| 224 | type: 'stream_event', |
| 225 | event: convertStreamEvent(msg as SDKPartialAssistantMessage), |
| 226 | } |
no test coverage detected