( messages: ReadonlyArray<Message>, lastUserMessage: Message, )
| 2463 | * resolve after. |
| 2464 | */ |
| 2465 | export function collectRecentSuccessfulTools( |
| 2466 | messages: ReadonlyArray<Message>, |
| 2467 | lastUserMessage: Message, |
| 2468 | ): readonly string[] { |
| 2469 | const useIdToName = new Map<string, string>() |
| 2470 | const resultByUseId = new Map<string, boolean>() |
| 2471 | for (let i = messages.length - 1; i >= 0; i--) { |
| 2472 | const m = messages[i] |
| 2473 | if (!m) continue |
| 2474 | if (isHumanTurn(m) && m !== lastUserMessage) break |
| 2475 | if (m.type === 'assistant' && typeof m.message.content !== 'string') { |
| 2476 | for (const block of m.message.content) { |
| 2477 | if (block.type === 'tool_use') useIdToName.set(block.id, block.name) |
| 2478 | } |
| 2479 | } else if ( |
| 2480 | m.type === 'user' && |
| 2481 | 'message' in m && |
| 2482 | Array.isArray(m.message.content) |
| 2483 | ) { |
| 2484 | for (const block of m.message.content) { |
| 2485 | if (isToolResultBlock(block)) { |
| 2486 | resultByUseId.set(block.tool_use_id, block.is_error === true) |
| 2487 | } |
| 2488 | } |
| 2489 | } |
| 2490 | } |
| 2491 | const failed = new Set<string>() |
| 2492 | const succeeded = new Set<string>() |
| 2493 | for (const [id, name] of useIdToName) { |
| 2494 | const errored = resultByUseId.get(id) |
| 2495 | if (errored === undefined) continue |
| 2496 | if (errored) { |
| 2497 | failed.add(name) |
| 2498 | } else { |
| 2499 | succeeded.add(name) |
| 2500 | } |
| 2501 | } |
| 2502 | return [...succeeded].filter(t => !failed.has(t)) |
| 2503 | } |
| 2504 | |
| 2505 | |
| 2506 | /** |
no test coverage detected