(
batch: { path: string; content: string; }[],
batchIndex: number,
totalBatches: number,
allMetadata: any[],
graphs: any[],
costTracker: CostAggregator,
condensedStructureParam?: string,
httpConnectionsContextParam?: string
)
| 721 | |
| 722 | // Inner function to analyze a single batch |
| 723 | async function analyzeBatch( |
| 724 | batch: { path: string; content: string; }[], |
| 725 | batchIndex: number, |
| 726 | totalBatches: number, |
| 727 | allMetadata: any[], |
| 728 | graphs: any[], |
| 729 | costTracker: CostAggregator, |
| 730 | condensedStructureParam?: string, |
| 731 | httpConnectionsContextParam?: string |
| 732 | ): Promise<WorkflowGraph | null> { |
| 733 | const batchPaths = batch.map(f => f.path); |
| 734 | const batchMetadata = allMetadata.filter(m => batchPaths.includes(vscode.workspace.asRelativePath(m.file, false))); |
| 735 | |
| 736 | // Detect framework for THIS batch (use first detected in batch) |
| 737 | let batchFramework: string | null = null; |
| 738 | for (const file of batch) { |
| 739 | batchFramework = WorkflowDetector.detectFramework(file.content); |
| 740 | if (batchFramework) break; |
| 741 | } |
| 742 | |
| 743 | // Combine batch files for analysis in XML format |
| 744 | const combinedBatchCode = combineFilesXML(batch, batchMetadata); |
| 745 | const batchTokens = estimateTokens(combinedBatchCode); |
| 746 | |
| 747 | log(`\nAnalyzing batch ${batchIndex + 1}/${totalBatches} (${batch.length} files, ~${Math.round(batchTokens / 1000)}k tokens)...`); |
| 748 | log(`Files in batch:`); |
| 749 | batch.forEach(f => { |
| 750 | const relativePath = vscode.workspace.asRelativePath(f.path); |
| 751 | const sizeKb = Math.round(f.content.length / 1024); |
| 752 | log(` - ${relativePath} (${sizeKb} KB)`); |
| 753 | }); |
| 754 | |
| 755 | try { |
| 756 | |
| 757 | log(`Sending POST /analyze: ${batch.length} file(s), ~${Math.round(batchTokens / 1000)}k tokens, framework: ${batchFramework || 'none'}${condensedStructureParam ? ', with cross-batch context' : ''}${httpConnectionsContextParam ? ', with HTTP connections' : ''}`); |
| 758 | const batchResult = await api.analyzeWorkflow( |
| 759 | combinedBatchCode, |
| 760 | batchPaths, |
| 761 | batchFramework || undefined, |
| 762 | batchMetadata, |
| 763 | condensedStructureParam, |
| 764 | httpConnectionsContextParam |
| 765 | ); |
| 766 | |
| 767 | // Check if session was invalidated (cache cleared) during request |
| 768 | if (getAnalysisSession() !== sessionAtStart) { |
| 769 | log(`Batch ${batchIndex + 1} result discarded (session invalidated)`); |
| 770 | return null; |
| 771 | } |
| 772 | |
| 773 | const batchGraph = batchResult.graph; |
| 774 | |
| 775 | |
| 776 | // Track actual cost from API |
| 777 | costTracker.add('analyze', batch.length, batchResult.usage, batchResult.cost, batchIndex); |
| 778 | |
| 779 | // Track tokens for legacy logging (accumulate in outer scope) |
| 780 | totalInputTokens += batchTokens; |
no test coverage detected