Registry - tinyhumansai/tinyagents GitHub Wiki

Registry

The registry (crates/tinyagents-registry/) is the named capability catalog: every model, tool, agent, capability bundle, router, and reducer is registered under a name, so a host refers to capabilities by name rather than by Rust type. Only names that were explicitly registered resolve.

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

Submodules:

  • component — identity and discovery types.
  • capability — the name-addressable CapabilityRegistry.
  • catalog — the offline model catalog (prices, context windows, capabilities).
  • router — WorkloadRouter, a workload-alias layer over named models (ModelRouter is a deprecated alias of it).
  • diagnostics — RegistrySnapshot and RegistryDiagnostic.

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 tinytools::Tool> yes
    Agent tinyagents_definition::AgentDefinition (a declarative definition, not a live agent) yes (a stored definition)
    Capability a tinyagents_harness::capability::Capability<State, Ctx> bundle, stored type-erased yes
    Graph name-only descriptor no
    Router name-only descriptor no
    Reducer name-only descriptor no
    Store name-only descriptor 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. Agent definitions and capability bundles do not use State for their own storage: an AgentDefinition is plain data, and a Capability is stored type-erased and downcast back by naming its Ctx type again.

It is distinct from the harness's per-run ModelRegistry and ToolRegistry (executable stores for a single harness). CapabilityRegistry is the catalog that hosts resolve names against; to_model_registry() / to_tool_registry() build a harness registry out of it. It also implements tinyagents_definition::DefinitionRegistry, so the agent definitions registered here can serve as a host's definition registry.

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_definition)?;      // keyed by AgentDefinition::id
reg.register_capability(capability)?;       // keyed by Capability::name
reg.register_descriptor(ComponentKind::Graph, "triage")?; // name-only
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 / replace_capability overwrite while preserving any richer metadata already attached.
  • register_descriptor(kind, name) backs the name-only kinds.
  • set_metadata(kind, name, metadata) replaces the recorded ComponentMetadata of a registered component, and remove(kind, name) unregisters one (leaving any aliases dangling, which diagnostics() then reports).
  • 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), agent(name) and capability::<Ctx>(name) resolve a name (or one alias hop) to a live handle or definition. has(kind, name) answers presence, names(kind) lists canonical names, and names_including_aliases(kind) lists canonical names and aliases — the set of names a caller may use. 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).

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)

WorkloadRouter (formerly ModelRouter, still exported as a deprecated alias) 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. ModelCatalog::profile(provider, model_id) turns an entry into a tinyinference_llm::model::ModelProfile.
  • ModelPricing (from tinyagents_harness::cost) gives the per-token prices.
  • ModelCapabilities is the feature matrix: streaming, tool_calling, parallel_tool_calling, json_schema, system_messages, vision, audio_input/video_input/audio_output, pdf_input, prompt_caching, reasoning.

When to use the registry

Use a CapabilityRegistry to let one agent or graph reference another by name instead of hardcoding it, to power a discovery UI over available models/tools/agents, 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.
  • Graph Runtime — the graph layer; Graph entries in the registry are name-only descriptors.
⚠️ **GitHub.com Fallback** ⚠️