Query Router
AgentOS includes a QueryRouter that turns one user question into a three-stage pipeline:
- classify the query into tier
0through3 - retrieve the right amount of context
- generate a grounded answer from that context
What Is Live Today
- Tier classification uses an LLM prompt with corpus topics, recent conversation history, and optional tool names.
- The router embeds local markdown docs into an in-memory vector store when an embedding provider is available.
- If embeddings are unavailable or vector search fails, the router falls back to keyword search automatically.
- Result metadata includes
tiersUsedandfallbacksUsed. - Lifecycle events cover classification, retrieval, research, generation, and route completion.
Current Limitations
The QueryRouter scaffold is ahead of the wired runtime in a few places:
graphExpand()is now a built-in corpus-neighborhood heuristic, not yet a true GraphRAG engine.rerank()is now a built-in lexical heuristic reranker, not yet a cross-encoder service.deepResearch()is now a built-in local-corpus heuristic synthesis pass, not yet a web-backed research runtime.- The router is useful today for query classification, vector retrieval, keyword fallback, heuristic graph expansion, heuristic reranking, heuristic local research synthesis, and grounded answer generation, but it is not yet a full GraphRAG or web-research runtime.
Host-Injected Runtime Hooks
You can replace the built-in heuristic branches without forking QueryRouter
by passing host-provided callbacks in the constructor:
graphExpand(seedChunks)for GraphRAG or relationship expansionrerank(query, chunks, topN)for provider-backed rerankingdeepResearch(query, sources)for real multi-source research
When these hooks are supplied, router.getCorpusStats() will report the
corresponding runtime mode as active instead of the built-in heuristic
mode.
Example
Runnable source: packages/agentos/examples/query-router.mjs
import { QueryRouter } from '@framers/agentos';
const router = new QueryRouter({
knowledgeCorpus: ['./docs', './packages/agentos/docs'],
availableTools: ['web_search', 'deep_research'],
});
await router.init();
console.log(router.getCorpusStats());
const result = await router.route('How does memory retrieval work?');
console.log(result.answer);
console.log(result.classification.tier);
console.log(result.tiersUsed);
console.log(result.fallbacksUsed);
console.log(result.sources);
await router.close();
Host-Injected Runtime Example
Runnable source: packages/agentos/examples/query-router-host-hooks.mjs
const router = new QueryRouter({
knowledgeCorpus: ['./docs', './packages/agentos/docs'],
graphEnabled: true,
deepResearchEnabled: true,
graphExpand: async (seedChunks) => [...seedChunks, extraGraphChunk],
rerank: async (_query, chunks, topN) => chunks.slice(0, topN),
deepResearch: async (query, sources) => ({
synthesis: `Host-provided research for ${query}`,
sources: externalResearchChunks,
}),
});
await router.init();
console.log(router.getCorpusStats()); // graph/deepResearch/rerank runtime modes become active
Config Notes
knowledgeCorpusis required.init()throws ifknowledgeCorpusresolves to zero readable.md/.mdxsections.availableToolsis optional and is only used to help the classifier reason about what the runtime can do.apiKey/baseUrlconfigure classifier and generator LLM calls. When omitted, QueryRouter prefersOPENAI_API_KEYand falls back toOPENROUTER_API_KEYwith the OpenRouter compatibility base URL.embeddingApiKey/embeddingBaseUrloverride only the embedding path when vector retrieval should use a different provider or credential. When omitted, embeddings fall back throughapiKey, thenOPENAI_API_KEY, thenOPENROUTER_API_KEY.githubReposoptionally enables non-blocking GitHub corpus indexing afterinit(). Newly indexed repo chunks are merged back into the live corpus, keyword fallback, classifier topics, and the vector index when embeddings are active.deepResearchEnabledcontrols whether the tier-3 research branch is attempted; the default core implementation is a local-corpus heuristic, and hosts can still inject a real web-backed implementation.onClassificationandonRetrievalare hooks for consumers that want lightweight runtime integration without reading the full event stream.router.getCorpusStats()returns aQueryRouterCorpusStatssnapshot with configured path count, loaded chunk/topic/source counts, whether retrieval is running invector+keyword-fallbackorkeyword-onlymode, the embedding health fieldembeddingStatus, and the runtime-truth fieldsgraphRuntimeMode,rerankRuntimeMode, anddeepResearchRuntimeMode.embeddingStatus: 'active'means the vector index initialized successfully,'disabled-no-key'means init stayed keyword-only because no embedding credential was available, and'failed-init'means embedding bootstrap was attempted but failed and the router fell back to keyword-only mode.graphRuntimeMode: 'heuristic'means the built-in same-document / heading-overlap expansion is active;'active'is reserved for a future wired graph expansion service or a host-injected hook.rerankRuntimeMode: 'heuristic'means the built-in lexical reranker is active;'active'is reserved for a future wired reranker service.deepResearchRuntimeMode: 'heuristic'means the built-in local-corpus synthesis pass is active;'active'is reserved for a host-injected or future provider-backed research runtime.
Result Metadata
QueryResult includes:
classification: the final classification resultsources: citations built from retrieved chunkstiersUsed: the tiers actually exercised after fallbacksfallbacksUsed: retrieval/classification fallback strategy names such askeyword-fallbackorresearch-skipdurationMs: total end-to-end wall-clock time for classification, retrieval, and generation
Events
The router records typed events for:
classify:startclassify:completeclassify:errorretrieve:*research:*generate:*route:complete
These events are intended for observability, audit trails, and future workbench/runtime inspection surfaces.