# 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). - `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>` | yes | | `Tool` | `Arc>` | yes | | `Graph` | `Blueprint` (a compiled `.rag` graph) | serializable value | | `Agent` | `Arc` | 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` 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. ```rust 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` 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 }`. ```rust 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 `RegistryDiagnostic`s 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). ```rust 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. ```mermaid 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] ``` See [Expressive Language (.rag)](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 - [Architecture](Architecture) — how the crates fit together. - [Graph Runtime](Graph-Runtime) — what registered `Graph` blueprints become. - [Expressive Language (.rag)](Expressive-Language-RAG) — the language that binds against registered capabilities.