Skip to content

Commit 2f50784

Browse files
committed
feat(query-router): extend RetrievalPlan to ExecutionPlan with skill/tool/extension recommendations
Add ExecutionPlan interface extending RetrievalPlan with capability activation recommendations. The classifier now evaluates Tier 0 summaries from the CapabilityDiscoveryEngine to recommend which skills, tools, and extensions should be activated alongside the retrieval plan. - Add ExecutionPlan, SkillRecommendation, ToolRecommendation, ExtensionRecommendation types to rag/unified/types.ts - Add buildDefaultExecutionPlan() factory - Add getTier0Summaries() and getTier0SummariesByKind() to CapabilityDiscoveryEngine for prompt injection - Enhance QueryClassifier.classifyWithPlan() to return ExecutionPlan with capability recommendations from LLM - Add setCapabilityDiscoveryEngine() to wire discovery into classifier - Add heuristicCapabilitySelect() keyword-based fallback (14 patterns) - Update PLAN_SYSTEM_PROMPT_TEMPLATE with 10-step chain-of-thought covering capability selection dimensions - Add CapabilitiesActivateEvent to QueryRouterEventUnion - Wire capabilities:activate event emission into QueryRouter.route() - Add setCapabilityDiscoveryEngine() to QueryRouter public API - 26 new tests covering ExecutionPlan defaults, heuristic selection, classifier output, capability filtering, and discovery integration
1 parent 5f4bc2d commit 2f50784

6 files changed

Lines changed: 1492 additions & 30 deletions

File tree

src/discovery/CapabilityDiscoveryEngine.ts

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,59 @@ export class CapabilityDiscoveryEngine implements ICapabilityDiscoveryEngine {
295295
return this.initialized;
296296
}
297297

298+
/**
299+
* Get Tier 0 category summaries for all indexed capabilities.
300+
*
301+
* Returns a compact (~150 tokens) overview of available capability
302+
* categories, suitable for injection into LLM classification prompts.
303+
* This allows the classifier to reason about what capabilities exist
304+
* without loading full schemas.
305+
*
306+
* Returns an empty string when the engine is not initialized.
307+
*
308+
* @returns Tier 0 summary text, or empty string if uninitialized.
309+
*
310+
* @example
311+
* ```typescript
312+
* const summaries = engine.getTier0Summaries();
313+
* // "Available capability categories:\n- Information: web-search, deep-research (+2 more) (4)\n..."
314+
* ```
315+
*/
316+
getTier0Summaries(): string {
317+
if (!this.initialized) {
318+
return '';
319+
}
320+
return this.assembler.buildTier0(this.index.getAllCapabilities(), this.indexVersion);
321+
}
322+
323+
/**
324+
* Get Tier 0 category summaries filtered by capability kind.
325+
*
326+
* Produces separate summaries for skills, tools, and extensions so the
327+
* classifier can reason about each category independently.
328+
*
329+
* @returns Object with `skills`, `tools`, and `extensions` summary strings.
330+
*/
331+
getTier0SummariesByKind(): { skills: string; tools: string; extensions: string } {
332+
if (!this.initialized) {
333+
return { skills: '', tools: '', extensions: '' };
334+
}
335+
336+
const allCapabilities = this.index.getAllCapabilities();
337+
338+
const filterByKind = (kinds: string[]): CapabilityDescriptor[] =>
339+
allCapabilities.filter((c) => kinds.includes(c.kind));
340+
341+
// Build separate summaries using a fresh assembler to avoid polluting the cache
342+
const tempAssembler = new CapabilityContextAssembler(this.assembler['strategy']);
343+
344+
return {
345+
skills: tempAssembler.buildTier0(filterByKind(['skill']), -1),
346+
tools: tempAssembler.buildTier0(filterByKind(['tool', 'emergent-tool']), -2),
347+
extensions: tempAssembler.buildTier0(filterByKind(['extension', 'channel', 'voice', 'productivity']), -3),
348+
};
349+
}
350+
298351
listCapabilityIds(): string[] {
299352
return this.index.listIds();
300353
}

0 commit comments

Comments
 (0)