| 68 | // --------------------------------------------------------------------------- |
| 69 | |
| 70 | export function getTaskContext(index: GraphIndex | null, taskDescription: string) { |
| 71 | if (!index) return NO_GRAPH; |
| 72 | |
| 73 | const keywords = extractKeywords(taskDescription); |
| 74 | if (keywords.length === 0) { |
| 75 | return { error: "no_keywords", message: "Could not extract keywords from task description." }; |
| 76 | } |
| 77 | |
| 78 | const { graph } = index; |
| 79 | |
| 80 | // Score a string against the extracted keywords |
| 81 | function score(text: string): number { |
| 82 | const t = text.toLowerCase(); |
| 83 | let s = 0; |
| 84 | for (const kw of keywords) { |
| 85 | if (t === kw) s += 10; |
| 86 | else if (t.includes(kw)) s += 3; |
| 87 | } |
| 88 | return s; |
| 89 | } |
| 90 | |
| 91 | // Score every file by aggregating node scores within it |
| 92 | const fileScores = new Map<string, number>(); |
| 93 | const fileNodes = new Map<string, WorkflowNode[]>(); |
| 94 | for (const [file, nodes] of index.fileToNodes) { |
| 95 | let s = score(file) * 2; // file path match is strong signal |
| 96 | for (const n of nodes) { |
| 97 | s += score(n.label); |
| 98 | s += score(n.source?.function ?? ""); |
| 99 | s += score(n.description ?? "") * 0.5; |
| 100 | } |
| 101 | if (s > 0) { |
| 102 | fileScores.set(file, s); |
| 103 | fileNodes.set(file, nodes); |
| 104 | } |
| 105 | } |
| 106 | |
| 107 | // Top 10 files by score |
| 108 | const topFiles = [...fileScores.entries()] |
| 109 | .sort((a, b) => b[1] - a[1]) |
| 110 | .slice(0, 10); |
| 111 | |
| 112 | // Build response per file |
| 113 | const relevantFiles: Array<{ |
| 114 | file: string; |
| 115 | why: string; |
| 116 | key_functions: string[]; |
| 117 | workflows: string[]; |
| 118 | }> = []; |
| 119 | |
| 120 | for (const [file] of topFiles) { |
| 121 | const nodes = fileNodes.get(file) ?? []; |
| 122 | const wfNames = new Set<string>(); |
| 123 | const functions: string[] = []; |
| 124 | const labels: string[] = []; |
| 125 | |
| 126 | for (const n of nodes) { |
| 127 | const wf = index.nodeToWorkflow.get(n.id); |