Skip to content

Registry

Steven Enamakel edited this page Aug 31, 2026 · 4 revisions

Registry

The registry (crates/tinyagents-registry/) is the named capability catalog: every model, tool, graph, agent, router, and reducer is registered under a name, and .rag source binds to those names rather than to Rust types. It is what a .rag blueprint's model/tool/subgraph references resolve against.

The registry is explicit, not a hidden global — you own one per application, test, tenant, or workspace. It does not execute graph nodes or call providers; it answers "which capabilities exist, under what names, and is this name allowed?"

Cargo feature: tracing only (no default features).

What the registry holds

Three submodules:

  • component — identity and discovery types.
  • capability — the name-addressable CapabilityRegistry.
  • catalog — the offline model catalog (prices, context windows, capabilities).
  • routerModelRouter, a workload-alias layer over named models.

Component identity (component)

  • ComponentId(String) — a stable identifier, a newtype over the registered name (e.g. "gpt-4o", "lookup_user"), not a Rust type path.

  • ComponentKind — partitions the namespace: lookups, duplicate detection, aliasing, and discovery are all scoped by kind, so (Model, "x") and (Tool, "x") are independent entries. Variants:

    Kind Stores Executable?
    Model Arc<dyn ChatModel<State>> yes
    Tool Arc<dyn Tool<State>> yes
    Graph Blueprint (a compiled .rag graph) serializable value
    Agent Arc<dyn HarnessAgent> yes
    Router name-only descriptor no
    Reducer name-only descriptor no
    Store name-only descriptor no
    Script name-only descriptor for a host-provided scripted node no
    Middleware name-only descriptor no
    Checkpointer name-only descriptor no
    TaskStore name-only descriptor no
    Listener name-only descriptor no
  • ComponentMetadata { id, kind, description, tags, aliases } — discovery metadata. Every registration records one, even the name-only kinds (where description and tags start empty); it is the source of truth for presence.

The capability registry (capability)

CapabilityRegistry<State = ()> is the name-addressable catalog, generic over the application State because models and tools are generic over it. Registered agents are state-decoupled — a HarnessAgent receives a mapped prompt, not the registry's State — so the agent map does not depend on the State generic.

It is distinct from the harness's per-run ModelRegistry and ToolRegistry (executable stores for a single harness). CapabilityRegistry is the catalog that declarative source is validated against; to_model_registry() / to_tool_registry() build a harness registry out of it.

let mut reg = CapabilityRegistry::<()>::new();
reg.register_model("gpt-4o", model)?;      // duplicate name -> error
reg.register_tool(tool)?;                   // keyed by Tool::name()
reg.register_graph_blueprint("triage", blueprint)?;
reg.register_agent(agent)?;                 // keyed by HarnessAgent::name()
reg.register_router("route_by_intent")?;    // name-only descriptor
reg.register_reducer("append_messages")?;   // name-only descriptor
reg.alias(ComponentKind::Model, "fast", "gpt-4o")?;
  • register_* fails with a duplicate-component error if the (kind, name) pair already exists; replace_model / replace_tool / replace_graph_blueprint / replace_agent overwrite while preserving any richer metadata already attached.
  • register_descriptor(kind, name) backs the name-only kinds.
  • alias(kind, alias, target) declares an alternate name; it validates the target exists and the alias is free.

Looking things up: model(name), tool(name), graph_blueprint(name), and agent(name) resolve a name (or one alias hop) to a live handle or blueprint. has(kind, name) answers presence, names(kind) lists canonical names, and names_including_aliases(kind) lists canonical names and aliases — the set a .rag source may reference. metadata(kind, name) returns the ComponentMetadata.

Handing off to the runtime: to_model_registry() builds a harness ModelRegistry from the registered models, binding alias names to the same handle. to_tool_registry() builds a harness ToolRegistry (tools are keyed by their own Tool::name(), so tool-level aliases are not propagated — a tool is always invoked under its canonical name). capability_resolver() builds the language layer's CapabilityResolver, the bridge to .rag.

CapabilityRegistry<State> also implements tinyagents_language::capability_resolver::CapabilitySource and tinyagents_graph::subagent_node::AgentRegistry, which is what lets a .rag blueprint resolve capability names and lets a SubAgentNode resolve a registered Agent by name.

Introspection and diagnostics

snapshot() returns a serializable RegistrySnapshot, sorted by (kind, name). It enumerates both components and every alias as AliasBinding { kind, alias, canonical }.

let mut reg = CapabilityRegistry::<()>::new();
reg.register_model("gpt-4o", model)?;
reg.alias(ComponentKind::Model, "default", "gpt-4o")?;

let snapshot = reg.snapshot();
assert_eq!(snapshot.aliases[0].alias, "default");
assert_eq!(snapshot.aliases[0].canonical, "gpt-4o");
assert_eq!(snapshot.aliases[0].kind, ComponentKind::Model);

diagnostics() returns RegistryDiagnostics the registration-time duplicate check cannot catch alone: an alias that shadows a registered component's name, a dangling alias pointing at an unregistered name, and a name reused across different kinds (legal, since kinds partition the namespace, but flagged for audits — the diagnostic message names the offending kinds).

let mut reg = CapabilityRegistry::<()>::new();
reg.register_model("shared", model)?;
reg.register_router("shared")?; // legal: a different kind

let diags = reg.diagnostics();
assert_eq!(diags[0].name, "shared");
assert!(diags[0].message.contains("multiple kinds"));

Binding .rag capabilities by name

CapabilityResolver::from_registry(reg) snapshots names_including_aliases for every kind into allow-lists (models, tools, subgraphs, routers, reducers). When a .rag blueprint names a model, tool, subgraph, router, or reducer, the compiler checks it against these allow-lists — an unknown reference is a compile error before anything runs. Because graphs are registered as Graph components, a blueprint can reference another blueprint by name as a subgraph.

flowchart LR
    Rust[Rust: register_* by name] --> Reg[CapabilityRegistry]
    Reg -->|names_including_aliases| Res[CapabilityResolver]
    Rag[".rag source"] -->|references names| Res
    Res -->|validated| Graph[Graph + Harness runtime]
Loading

See Expressive Language (.rag).

Model routing (router)

ModelRouter maps a workload alias (chat-v1, vision-v1, ...) onto a WorkloadRoute { alias, model, requires: CapabilitySet, fallbacks }. It is a declarative layer above the named model registry: route(alias) / target_model(alias) resolve an alias to a concrete registered model name, required_capabilities(alias) returns the capability gate, and fallback_policy(alias) returns an ordered same-family fallback chain. A host uses this to let application code ask for "the model for this workload" while keeping the concrete model swap in one place.

The model catalog (catalog)

The model catalog is an offline snapshot of provider model metadata, not a live source of truth. It gives deterministic behavior for cost estimates, context-window checks, and capability gating without a network call. A checked-in snapshot (crates/tinyagents-registry/model-catalog.snapshot.json) is compiled into the crate.

  • ModelCatalog::seed() loads the bundled snapshot; from_json / from_snapshot load a custom one. get(provider, model_id) and get_by_model_id(model_id) resolve an entry by id or alias; snapshot() exposes the raw ModelCatalogSnapshot and models() the full entry slice.
  • ModelCatalogSnapshot carries schema_version, snapshot_id, provenance, and the models list.
  • ModelCatalogEntry describes one model: provider, model_id, aliases, token limits, pricing, and capabilities.
  • ModelPricing gives per-token input/output prices plus cache-read, cache-creation, audio, and reasoning rates.
  • ModelCapabilities is the feature matrix: streaming, tool_calling, parallel_tool_calling, json_schema, system_messages, vision, audio_input/audio_output, pdf_input, prompt_caching, reasoning.

When to use the registry

Use a CapabilityRegistry to compile and validate .rag blueprints, to let one agent or graph reference another by name instead of hardcoding it, to power a discovery UI over available models/tools/graphs, or to hand a curated, allow-listed set of models and tools to a harness. Use the model catalog for offline cost or capability facts about a model.

See also

TinyAgents

Provider-neutral agent harness and durable state-graph runtime for Rust.

Getting started

Concepts

Modules

Providers

Contributing


Clone this wiki locally