Skip to content

Registry

Steven Enamakel edited this page Oct 22, 2026 · 8 revisions

Registry

The registry (crates/tinyagents-registry/) is the named capability catalog. Models, tools, agents, and host-provided capability descriptors are registered under names so a host can inspect and select them without relying on hidden process globals.

The registry is explicit, not a hidden global — you own one per application, test, tenant, or workspace. It does not execute tools 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).
  • router — ModelRouter, 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 host-provided graph descriptor no
    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_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_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), and agent(name) resolve a name (or one alias hop) to a live handle. has(kind, name) answers presence, names(kind) lists canonical names, and names_including_aliases(kind) lists canonical names and aliases. 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).

CapabilityRegistry<State> also implements tinyagents_registry::AgentRegistry for resolving registered agents 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"));

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 power a discovery UI over available models/tools/agents, to resolve agents by name, 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

  • Architecture — how the crates fit together.
  • Harness — the agent loop that consumes registered models and tools.

TinyAgents

Provider-neutral agent harness and tools for Rust.

Getting started

Concepts

Modules

Providers

Contributing


Clone this wiki locally