(context: TaskContext)
| 16 | * - Code blocks only for key symbols |
| 17 | */ |
| 18 | export function formatContextAsMarkdown(context: TaskContext): string { |
| 19 | const lines: string[] = []; |
| 20 | |
| 21 | // Header with query |
| 22 | lines.push('## Code Context\n'); |
| 23 | lines.push(`**Query:** ${context.query}\n`); |
| 24 | |
| 25 | // Entry points - compact format. Re-sort so generated files (.pb.go, |
| 26 | // .pulsar.go, mocks, …) rank LAST — a flow query should lead with the |
| 27 | // hand-written implementation, not protobuf scaffolding. |
| 28 | const orderedEntries = [...context.entryPoints].sort((a, b) => { |
| 29 | const aGen = isGeneratedFile(a.filePath) ? 1 : 0; |
| 30 | const bGen = isGeneratedFile(b.filePath) ? 1 : 0; |
| 31 | return aGen - bGen; |
| 32 | }); |
| 33 | if (orderedEntries.length > 0) { |
| 34 | lines.push('### Entry Points\n'); |
| 35 | for (const node of orderedEntries) { |
| 36 | const location = node.startLine ? `:${node.startLine}` : ''; |
| 37 | lines.push(`- **${node.name}** (${node.kind}) - ${node.filePath}${location}`); |
| 38 | if (node.signature) { |
| 39 | lines.push(` \`${node.signature}\``); |
| 40 | } |
| 41 | } |
| 42 | lines.push(''); |
| 43 | } |
| 44 | |
| 45 | // Related symbols - compact list (skip verbose structure tree). Drop nodes |
| 46 | // in generated source files (`.pb.go` / `.pulsar.go` / mocks / …) — agents |
| 47 | // chasing a flow never want to land on protobuf scaffolding (cosmos-Q3 used |
| 48 | // to list `gov.pulsar.go::GetExpeditedThreshold` and `1.pulsar.go::Get` in |
| 49 | // Related Symbols, pure noise that displaced real-flow entries). |
| 50 | const otherSymbols = Array.from(context.subgraph.nodes.values()) |
| 51 | .filter(n => !context.entryPoints.some(e => e.id === n.id)) |
| 52 | .filter(n => !isGeneratedFile(n.filePath)) |
| 53 | .slice(0, 10); // Limit to 10 related symbols |
| 54 | |
| 55 | if (otherSymbols.length > 0) { |
| 56 | lines.push('### Related Symbols\n'); |
| 57 | const byFile = new Map<string, Node[]>(); |
| 58 | for (const node of otherSymbols) { |
| 59 | const existing = byFile.get(node.filePath) || []; |
| 60 | existing.push(node); |
| 61 | byFile.set(node.filePath, existing); |
| 62 | } |
| 63 | |
| 64 | for (const [file, nodes] of byFile) { |
| 65 | const nodeList = nodes.map(n => `${n.name}:${n.startLine}`).join(', '); |
| 66 | lines.push(`- ${file}: ${nodeList}`); |
| 67 | } |
| 68 | lines.push(''); |
| 69 | } |
| 70 | |
| 71 | // Code blocks - only for key entry points. Re-sort so non-generated blocks |
| 72 | // show first (consistent with Entry Points reordering above). |
| 73 | if (context.codeBlocks.length > 0) { |
| 74 | const orderedBlocks = [...context.codeBlocks].sort((a, b) => { |
| 75 | const aGen = isGeneratedFile(a.filePath) ? 1 : 0; |
no test coverage detected