MCPcopy Create free account
hub / github.com/colbymchenry/codegraph / handleExplore

Method handleExplore

src/mcp/tools.ts:4064–7558  ·  view source on GitHub ↗

* Handle codegraph_explore — deep exploration in a single call * * Strategy: find relevant symbols via graph traversal, group by file, * then read contiguous file sections covering all symbols per file. * This replaces multiple codegraph_node + Read calls. * * Output size is adapti

(args: Record<string, unknown>)

Source from the content-addressed store, hash-verified

4062 * tax on small projects while earning its keep on large ones.
4063 */
4064 private async handleExplore(args: Record<string, unknown>): Promise<ToolResult> {
4065 const rawQuery = this.validateString(args.query, 'query');
4066 if (typeof rawQuery !== 'string') return rawQuery;
4067 // One normalization point so the flow-builder, relevance search, and
4068 // ranking all see the same canonical spelling (Erlang `mod:fn/arity`).
4069 const query = normalizeQuerySpelling(rawQuery);
4070
4071 const cg = this.getCodeGraph(args.projectPath as string | undefined);
4072 const projectRoot = cg.getProjectRoot();
4073
4074 // Resolve adaptive output budget from project size. Falls back to the
4075 // largest-tier defaults if stats aren't available, which preserves
4076 // pre-#185 behavior for callers that hit the rare stats failure.
4077 let budget: ExploreOutputBudget;
4078 let indexedFileCount = -1;
4079 let indexedNodeCount = -1;
4080 try {
4081 const stats = cg.getStats();
4082 indexedFileCount = stats.fileCount;
4083 indexedNodeCount = stats.nodeCount;
4084 budget = getExploreOutputBudget(indexedFileCount);
4085 } catch {
4086 budget = getExploreOutputBudget(Infinity);
4087 }
4088 const maxFiles = clamp((args.maxFiles as number) || budget.defaultMaxFiles, 1, 20);
4089
4090 // File paths named in the query become PINNED files: guaranteed admission,
4091 // top of the rank order, funded first — and their span is REMOVED from the
4092 // matching query. Runs on the RAW query (normalizeQuerySpelling strips
4093 // `/digits` tails, which would mangle numeric path segments). Without this,
4094 // a SvelteKit path like `runs/[runId]/+page.svelte` was shredded by the
4095 // seeding tokenizer (splits on brackets → `runId` seeded as a "named
4096 // symbol") and by FTS (`page`/`runs` fragments admitted every sibling
4097 // `+page.svelte`), starving the very files the agent asked for.
4098 let pinnedFiles: string[] = [];
4099 let unresolvedPathSpans: string[] = [];
4100 let lineAnchors: QueryLineAnchor[] = [];
4101 let setAsideMatches: QuerySetAsideMatch[] = [];
4102 let matchQuery = query;
4103 if (queryMightContainPaths(rawQuery)) {
4104 try {
4105 const extraction = extractQueryPaths(
4106 rawQuery,
4107 cg.getFiles().map((f) => f.path),
4108 {
4109 maxPins: maxFiles,
4110 existsOnDisk: (rel) => pathIsProjectFile(projectRoot, rel),
4111 symbolFiles: (symbol) => filesDefiningSymbol(cg, symbol),
4112 },
4113 );
4114 if (extraction.pinnedFiles.length > 0 || extraction.unresolvedPathSpans.length > 0) {
4115 pinnedFiles = extraction.pinnedFiles;
4116 unresolvedPathSpans = extraction.unresolvedPathSpans;
4117 lineAnchors = extraction.lineAnchors;
4118 setAsideMatches = extraction.setAsideMatches;
4119 matchQuery = normalizeQuerySpelling(extraction.strippedQuery);
4120 }
4121 } catch { /* path pinning must never fail an explore call */ }

Callers 1

dispatchToolMethod · 0.95

Calls 15

validateStringMethod · 0.95
getCodeGraphMethod · 0.95
textResultMethod · 0.95
findAllSymbolsMethod · 0.95
computeGraphRelevanceMethod · 0.95
isFileStaleOnDiskMethod · 0.95
answerResultMethod · 0.95
clampFunction · 0.90
queryMightContainPathsFunction · 0.90
extractQueryPathsFunction · 0.90

Tested by

no test coverage detected