( httpExchanges: readonly CapturedExchange[], workDir: string, toolResultNormalizers: ToolResultNormalizer[], )
| 749 | |
| 750 | // Takes raw HTTP traffic and turns it into the normalized form that we store on disk |
| 751 | async function transformHttpExchanges( |
| 752 | httpExchanges: readonly CapturedExchange[], |
| 753 | workDir: string, |
| 754 | toolResultNormalizers: ToolResultNormalizer[], |
| 755 | ): Promise<NormalizedData> { |
| 756 | const chatCompletionExchanges = httpExchanges |
| 757 | .filter((e) => e.request.url === chatCompletionEndpoint) |
| 758 | .filter(excludeFailedResponses); |
| 759 | const allTurns = await Promise.all( |
| 760 | chatCompletionExchanges.map((e) => |
| 761 | transformHttpExchange(e.request.body, e.response?.body), |
| 762 | ), |
| 763 | ); |
| 764 | const dedupedExchanges = removePrefixConversations( |
| 765 | allTurns.map((t) => t.conversation), |
| 766 | ); |
| 767 | const dedupedModels = new Set( |
| 768 | allTurns.map((t) => t.model ?? "").filter((m) => !!m), |
| 769 | ); |
| 770 | |
| 771 | normalizeToolCalls(dedupedExchanges, toolResultNormalizers); |
| 772 | normalizeToolResultOrder(dedupedExchanges); |
| 773 | normalizeFilenames(dedupedExchanges, workDir); |
| 774 | return { models: Array.from(dedupedModels), conversations: dedupedExchanges }; |
| 775 | } |
| 776 | |
| 777 | function normalizeFilenames( |
| 778 | conversations: NormalizedConversation[], |
no test coverage detected
searching dependent graphs…