Registry - tinyhumansai/tinyagents GitHub Wiki
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).
Submodules:
-
component— identity and discovery types. -
capability— the name-addressableCapabilityRegistry. -
catalog— the offline model catalog (prices, context windows, capabilities). -
router—WorkloadRouter, a workload-alias layer over named models (ModelRouteris a deprecated alias of it). -
diagnostics—RegistrySnapshotandRegistryDiagnostic.
-
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? ModelArc<dyn ChatModel<State>>yes ToolArc<dyn tinytools::Tool>yes Agenttinyagents_definition::AgentDefinition(a declarative definition, not a live agent)yes (a stored definition) Capabilitya tinyagents_harness::capability::Capability<State, Ctx>bundle, stored type-erasedyes Graphname-only descriptor no Routername-only descriptor no Reducername-only descriptor no Storename-only descriptor no Middlewarename-only descriptor no Checkpointername-only descriptor no TaskStorename-only descriptor no Listenername-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.
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_capabilityoverwrite while preserving any richer metadata already attached. -
register_descriptor(kind, name)backs the name-only kinds. -
set_metadata(kind, name, metadata)replaces the recordedComponentMetadataof a registered component, andremove(kind, name)unregisters one (leaving any aliases dangling, whichdiagnostics()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).
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"));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 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_snapshotload a custom one.get(provider, model_id)andget_by_model_id(model_id)resolve an entry by id or alias;snapshot()exposes the rawModelCatalogSnapshotandmodels()the full entry slice. -
ModelCatalogSnapshotcarriesschema_version,snapshot_id, provenance, and themodelslist. -
ModelCatalogEntrydescribes one model:provider,model_id,aliases, token limits,pricing, andcapabilities.ModelCatalog::profile(provider, model_id)turns an entry into atinyinference_llm::model::ModelProfile. -
ModelPricing(fromtinyagents_harness::cost) gives the per-token prices. -
ModelCapabilitiesis 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.
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.
- Architecture — how the crates fit together.
-
Graph Runtime — the graph layer;
Graphentries in the registry are name-only descriptors.