* For external users, make REPL invisible in the persisted transcript: strip * REPL tool_use/tool_result pairs and promote isVirtual messages to real. On * --resume the model then sees a coherent native-tool-call history (assistant * called Bash, got result, called Read, got result) without the R
( messages: Transcript, replIds: Set<string>, )
| 4395 | * and leave an orphaned tool_result on disk. |
| 4396 | */ |
| 4397 | function transformMessagesForExternalTranscript( |
| 4398 | messages: Transcript, |
| 4399 | replIds: Set<string>, |
| 4400 | ): Transcript { |
| 4401 | return messages.flatMap(m => { |
| 4402 | if (m.type === 'assistant' && Array.isArray(m.message.content)) { |
| 4403 | const content = m.message.content |
| 4404 | const hasRepl = content.some( |
| 4405 | b => b.type === 'tool_use' && b.name === REPL_TOOL_NAME, |
| 4406 | ) |
| 4407 | const filtered = hasRepl |
| 4408 | ? content.filter( |
| 4409 | b => !(b.type === 'tool_use' && b.name === REPL_TOOL_NAME), |
| 4410 | ) |
| 4411 | : content |
| 4412 | if (filtered.length === 0) return [] |
| 4413 | if (m.isVirtual) { |
| 4414 | const { isVirtual: _omit, ...rest } = m |
| 4415 | return [{ ...rest, message: { ...m.message, content: filtered } }] |
| 4416 | } |
| 4417 | if (filtered !== content) { |
| 4418 | return [{ ...m, message: { ...m.message, content: filtered } }] |
| 4419 | } |
| 4420 | return [m] |
| 4421 | } |
| 4422 | if (m.type === 'user' && Array.isArray(m.message.content)) { |
| 4423 | const content = m.message.content |
| 4424 | const hasRepl = content.some( |
| 4425 | b => b.type === 'tool_result' && replIds.has(b.tool_use_id), |
| 4426 | ) |
| 4427 | const filtered = hasRepl |
| 4428 | ? content.filter( |
| 4429 | b => !(b.type === 'tool_result' && replIds.has(b.tool_use_id)), |
| 4430 | ) |
| 4431 | : content |
| 4432 | if (filtered.length === 0) return [] |
| 4433 | if (m.isVirtual) { |
| 4434 | const { isVirtual: _omit, ...rest } = m |
| 4435 | return [{ ...rest, message: { ...m.message, content: filtered } }] |
| 4436 | } |
| 4437 | if (filtered !== content) { |
| 4438 | return [{ ...m, message: { ...m.message, content: filtered } }] |
| 4439 | } |
| 4440 | return [m] |
| 4441 | } |
| 4442 | // string-content user, system, attachment |
| 4443 | if ('isVirtual' in m && m.isVirtual) { |
| 4444 | const { isVirtual: _omit, ...rest } = m |
| 4445 | return [rest] |
| 4446 | } |
| 4447 | return [m] |
| 4448 | }) as Transcript |
| 4449 | } |
| 4450 | |
| 4451 | export function cleanMessagesForLogging( |
| 4452 | messages: Message[], |
no test coverage detected