Catalog PyPI
Back to packageRELEASE DETAILS

0.4.0

PyPI

agent-registry-router

Registry-driven LLM routing: build classifier prompts from agent descriptions, validate decisions, and dispatch.

Published3 Mar 2026
Direct dependencies14
Transitive dependenciesNot calculated

README

Version 0.4.0 documentation

agent-registry-router

CI PyPI Python License

Registry-driven LLM routing: build classifier prompts, validate decisions, and dispatch to the right agent.

Why

When you have multiple AI agents, something needs to decide which one handles each user message. Most teams hardcode if/else chains or build bespoke classifiers. This library gives you a clean, framework-agnostic way to:

  • Build classifier prompts from a registry of agent descriptions
  • Validate routing decisions with typed errors or optional graceful fallback
  • Dispatch to the selected agent with observability hooks
  • Benchmark classifier accuracy across LLMs and embedding models

How It Works

graph LR
    A[User Message] --> B{Classifier}
    B -->|LLM| C[Build Prompt from Registry]
    B -->|FAISS| D[Embed & Similarity Search]
    C --> E[RouteDecision]
    D --> E
    E --> F[Validate Against Registry]
    F --> G[Dispatch to Agent]
    G --> H[Response]

Install

pip install agent-registry-router

With a framework adapter:

pip install "agent-registry-router[pydanticai]"    # PydanticAI
pip install "agent-registry-router[openai-agents]"  # OpenAI Agents SDK
pip install "agent-registry-router[google-adk]"     # Google ADK
pip install "agent-registry-router[faiss]"          # FAISS classifier

Quick Start

from agent_registry_router import (
    AgentRegistry,
    AgentRegistration,
    RouteDecision,
    build_classifier_system_prompt,
    validate_route_decision,
)

# Register your agents
registry = AgentRegistry()
registry.register(AgentRegistration(name="billing", description="Handles billing and payments."))
registry.register(AgentRegistration(name="technical", description="Handles technical support."))
registry.register(AgentRegistration(name="general", description="Handles general inquiries."))

# Build a classifier prompt from the registry
prompt = build_classifier_system_prompt(registry, default_agent="general")

# Validate a routing decision
decision = RouteDecision(agent="billing", confidence=0.9, reasoning="Payment question.")
validated = validate_route_decision(decision, registry=registry, default_agent="general")

Adapters

Framework-specific dispatchers that handle classify → validate → dispatch. Each is opt-in — the core has no framework dependencies.

AdapterInstall ExtraDispatcher Class
PydanticAIpydanticaiPydanticAIDispatcher
OpenAI Agents SDKopenai-agentsOpenAIAgentsDispatcher
Google ADKgoogle-adkGoogleADKDispatcher

All adapters are duck-typed (no runtime imports of the framework). Any object matching the protocol works. All support:

  • route_and_run() — classify, validate, dispatch
  • route_and_stream() — same flow, streaming output
  • Pinned agent bypass (skip classifier, dispatch directly)
  • on_event observability hooks
from agent_registry_router.adapters.pydantic_ai import PydanticAIDispatcher
from agent_registry_router.adapters.openai_agents import OpenAIAgentsDispatcher
from agent_registry_router.adapters.google_adk import GoogleADKDispatcher

FAISS Classifier

An alternative to LLM-based classification: embed agent descriptions, find the nearest match by cosine similarity. Near-zero latency, near-zero cost.

from agent_registry_router import FaissClassifier

classifier = FaissClassifier(
    registry=registry,
    embed_fn=your_embedding_function,  # any callable: list[str] -> list[list[float]]
)
decision = classifier.classify("I was charged twice")

Structured Logging

Built-in JSON logging for routing events. One line to set up.

from agent_registry_router import StructuredLogger

dispatcher = PydanticAIDispatcher(
    ...,
    on_event=StructuredLogger(),
)
# Produces: {"ts": "...", "event": "classifier_run_success", "agent": "billing", "confidence": 0.92}

Eval Suite

Benchmarks the classifier prompts this library generates across LLMs and FAISS. Includes fixtures, a runner, and a report generator.

make install-eval
cp .env.example .env  # add your API keys
make eval

See evals/README.md for details. Bring your own fixtures to benchmark your own agent registries.

Error Handling

Fail-fast by default with typed exceptions:

  • InvalidRouteDecision — classifier picked a non-routable agent
  • InvalidFallback — default agent isn't routable or registry is empty
  • AgentNotFound — validated agent can't be resolved for dispatch
  • RegistryError — invalid names, descriptions, or empty registry

Graceful Fallback

Opt in to graceful degradation instead of hard failures:

validated = validate_route_decision(
    decision,
    registry=registry,
    default_agent="general",
    allow_fallback=True,       # swap to default instead of raising on invalid agent
    confidence_threshold=0.5,  # swap to default when confidence is below threshold
)
if validated.did_fallback:
    print(f"Fell back: {validated.fallback_reason}")

Design Principles

  • Framework-agnostic core: routing logic has no opinion on your agent framework
  • Duck-typed adapters: protocols, not imports — any compatible object works
  • Fail-fast validation: typed errors, never silent wrong-agent routing
  • Deterministic prompts: registration order preserved, routable-only, size-bounded
  • Observable: on_event hooks + StructuredLogger for production monitoring

Development

make install       # install dev dependencies
make lint          # ruff + mypy
make test          # pytest with 85% coverage gate
make format        # auto-format
make eval          # run classifier benchmarks (requires API keys)

License

Apache-2.0

Downloads & popularity

Awaiting observations

No metric observations yet

Download counts and popularity will appear here as the collector receives them.

Declared dependencies 14

Native requirements
14 direct targetsNot calculated transitive count
Package / targetRequirementRelationship
pydantic
Environment
{
  "extras": "",
  "marker": null,
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
pydantic<3.0,>=2.0.0runtime
anyio
Environment
{
  "extras": "trio",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
anyio[trio]; extra == "dev"runtime
mypy
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
mypy>=1.11.0; extra == "dev"runtime
pytest-cov
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
pytest-cov>=4.1.0; extra == "dev"runtime
pytest
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
pytest>=8.0.0; extra == "dev"runtime
ruff
Environment
{
  "extras": "",
  "marker": "extra == \"dev\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
ruff>=0.7.0; extra == "dev"runtime
anthropic
Environment
{
  "extras": "",
  "marker": "extra == \"eval\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
anthropic; extra == "eval"runtime
google-genai
Environment
{
  "extras": "",
  "marker": "extra == \"eval\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
google-genai; extra == "eval"runtime
openai
Environment
{
  "extras": "",
  "marker": "extra == \"eval\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
openai; extra == "eval"runtime
faiss-cpu
Environment
{
  "extras": "",
  "marker": "extra == \"faiss\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
faiss-cpu; extra == "faiss"runtime
numpy
Environment
{
  "extras": "",
  "marker": "extra == \"faiss\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
numpy; extra == "faiss"runtime
google-adk
Environment
{
  "extras": "",
  "marker": "extra == \"google-adk\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
google-adk; extra == "google-adk"runtime
openai-agents
Environment
{
  "extras": "",
  "marker": "extra == \"openai-agents\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
openai-agents; extra == "openai-agents"runtime
pydantic-ai
Environment
{
  "extras": "",
  "marker": "extra == \"pydanticai\"",
  "requires_python": ">=3.10",
  "evaluation": "NOT_EVALUATED"
}
pydantic-ai; extra == "pydanticai"runtime

Distribution files

2 collected
agent_registry_router-0.4.0-py3-none-any.whl

bdist_wheel · 33.45 KB · Python py3

Source file
agent_registry_router-0.4.0.tar.gz

sdist · 20.76 KB · Python source

Source file

Repository

PENDING
agibson22/agent-registry-router

Shared repository data · GitHub

License detected in repository
Not collected

Metadata history

Meaningful changes
Current collected state Current

Observed since 20 Oct, 23:11 UTC

No superseded metadata states collected. Unchanged observations do not create new revisions.

Record identity

package_version:175c18daa6b72e6cef5f256b1671d56105ca9c2f69e04344ba968b103cfe3a0b

Other collected versions

View all collected versions →