route66 Python SDK
Project description
route66
Intelligent Tool Router for LLM Agents — a catalog-in library that, given a query and a large tool catalog, returns only the relevant tools, deduplicated, in an ordered execution plan, with policy-aware defaults.
Built against the router-testkit hackathon grading contract
(single-tool routing, ordered multi-tool plans, near-duplicate
resolution, capability-based fallback widening, deprecation policy,
out-of-scope refusal, and clarify-on-vague-destructive).
Layout
route66/
├── tool_router/ # The POC library (facade + retrievers + dedup)
├── testkit_adapter.py # Bridges tool_router to the harness contract
├── demo.py # Toy 60-tool catalog demo of the POC
├── metrics.py # Recall/precision/token-savings eval on the toy set
├── router-testkit/ # Hackathon input kit — DO NOT MODIFY
│ ├── catalog/ # 64 mock tools · 13 clusters · dup/version metadata
│ ├── test_cases/ # 29 scored cases across 11 categories
│ ├── registry_guardrail/# Intake validator fixtures
│ └── harness/ # run_benchmark.py (scorer) + baseline_router.py
├── bench/ # Additional benchmarks (baseline, mutations, guardrail)
├── specs/ # Spec-driven-development plan (SPEC-001..011)
├── docs/ # PRDs and the hackathon problem statement
└── tests/ # Unit tests (populated as specs are executed)
Baseline
| Router | Cases passed | Token savings |
|---|---|---|
Testkit reference baseline_router |
7 / 29 (24%) | 94% |
tool_router (this repo, current) |
5 / 29 (17%) | 90% |
The gap is deliberate and mapped in specs/. See
specs/README.md for the priority-ordered plan
(P0 → P1 → P2) with acceptance criteria pinned to specific TC-*
cases. Target after P0: ≥ 20/29. After P1: ≥ 24/29.
Quick start
# Install (uv-managed)
uv sync
# Score the reference baseline
cd router-testkit/harness
python run_benchmark.py --verbose
# Score this project's router
python run_benchmark.py --router testkit_adapter:MyRouter --verbose
The harness has no third-party dependencies; standard-library only.
The router itself can run on HashingEmbedder (zero deps) or opt-in
SentenceTransformerEmbedder via uv sync --extra semantic.
Pluggable embedding store (Chroma DB, optional)
The dense-retrieval leg of the pipeline stores tool embeddings behind a
VectorStore abstraction. The default is a zero-dependency in-memory
exact-cosine store; you can opt into Chroma DB without changing any
other code.
from route66 import Tool, ToolRouter, ChromaVectorStore
tools = [Tool(id="fin.get_revenue", name="get_revenue_report",
description="Retrieve booked revenue for a period"), ...]
# Default: in-memory store, zero extra deps.
router = ToolRouter(tools)
# Opt in to Chroma DB — same catalog, same results, external store.
router = ToolRouter(tools, vector_store=ChromaVectorStore())
Or select it by environment variable (no code change):
export TR_VECTOR_STORE=chroma # 'memory' (default) | 'chroma'
Install the optional dependency with uv sync --extra chroma. When
chromadb is not installed, the registry logs a warning and falls back
to the in-memory store, so nothing breaks.
Live tool sync from MCP servers (optional)
MCPToolSync connects to an agent's MCP server(s) with the official
mcp SDK, calls list_tools(), transforms the schemas into route66
Tools, and updates the embedding store — adding embeddings for new
tools and purging embeddings for any tool whose server was removed.
It works with either vector store above.
from route66 import ToolRouter, MCPServerSpec, MCPToolSync, ChromaVectorStore
router = ToolRouter(seed_tools, vector_store=ChromaVectorStore())
sync = MCPToolSync(router, servers=[
MCPServerSpec("slack", command="npx", args=("-y", "@modelcontextprotocol/server-slack")),
MCPServerSpec("github", url="https://mcp.example.com/sse"),
])
sync.sync() # connect → transform → embed (returns a CatalogDelta)
sync.servers.pop() # detach the github server
sync.sync() # its tool embeddings are purged from the store
sync() is a manual, pull-based call (no threads, no file watching): run
it at start-up and whenever you attach/detach a server. It is a no-op
when nothing changed. Install the optional client with
uv sync --extra mcp.
How to test and set these up locally: see
docs/chroma-and-mcp-sync.md.
Where to read next
docs/architecture/query-flow.md— sequence diagram of a singleroute()call end-to-end. Every arrow points at a function you cangrepfor. Read this before touching the pipeline.docs/architecture/components.md— module dependency graph, per-module code-map, and extension-point cheat-sheet. Read this when picking up the codebase cold.specs/README.md— the executable plan. Every spec is pickable independently and has acceptance criteria tied to testkit case IDs.router-testkit/README.md— the grading contract (authoritative).docs/hackathon-definition.md— the problem statement.docs/PRD.md— the initial PRD.
Toolchain
- Python ≥ 3.14 (pinned in
.python-version, managed by uv) - Ruff for lint + format
- Pytest for unit tests (see
pyproject.toml's[dev]extra)
Dev
uv run ruff check .
uv run ruff format .
uv run pytest
Release
Releases are published to PyPI via a GitLab CI child pipeline. To trigger a release:
- Go to CI/CD → Pipelines → Run pipeline on the
masterbranch. - The
trigger:releasejob starts automatically and spawns the release child pipeline. - Set any of the following pipeline variables before running:
| Variable | Default | Meaning |
|---|---|---|
BUMP |
patch |
patch / minor / major — controls auto-increment. |
VERSION |
empty | Explicit x.y.z — overrides BUMP when set. |
RELEASE_NOTES |
empty | Free-form notes shown on the PyPI page, git tag, and GitLab Release. |
The pipeline will:
- Bump
src/route66/_version.pyand rebuild the package - Inject release notes into the PyPI long description (visible on pypi.org)
- Publish the wheel + sdist via twine
- Commit the version bump and push an annotated git tag
vX.Y.Z - Create a GitLab Release under Deployments → Releases
- Update
release/CHANGELOG.mdandrelease/versions/pypi.json
See release/README.md for full pipeline and
variable documentation.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file route66-2.0.2.tar.gz.
File metadata
- Download URL: route66-2.0.2.tar.gz
- Upload date:
- Size: 62.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c4c8fc47d17bfd3930664a13e7a827f741f0e7c1398021d7bdeed3178d58603c
|
|
| MD5 |
aa9af2a0c5b3a2a818960735dc362840
|
|
| BLAKE2b-256 |
79ec07f08bf3cfc5e48cad222c6cee34ac0e842d3d91a8e7127a885fb2555e52
|
File details
Details for the file route66-2.0.2-py3-none-any.whl.
File metadata
- Download URL: route66-2.0.2-py3-none-any.whl
- Upload date:
- Size: 80.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
23abca5aa91d505f6237fe06b3ee42924f51d606789bc9538959ad76da5e880f
|
|
| MD5 |
125c8eb92f1f0ef3312eba92c7519e3a
|
|
| BLAKE2b-256 |
0a2b414079d8ef0772f0f74fe1badfe6ebb05b527eeeb1d5af193d997c568205
|