pub struct Registry { /* private fields */ }Implementations§
Source§impl Registry
impl Registry
pub fn new() -> Self
Sourcepub fn insert(&mut self, tool: Arc<dyn Tool>)
pub fn insert(&mut self, tool: Arc<dyn Tool>)
Register a tool. A later registration with the same name replaces the earlier one, so MCP servers can shadow built-ins deliberately.
pub fn get(&self, name: &str) -> Option<&Arc<dyn Tool>>
Sourcepub fn available(&self, name: &str) -> Option<&Arc<dyn Tool>>
pub fn available(&self, name: &str) -> Option<&Arc<dyn Tool>>
The tool a call may actually reach: registered and inside whatever restriction is currently active.
Dispatch goes through this rather than get, because
a restriction that only shortened the spec list would be advisory. A
model that saw fs_write three turns ago can still name it, and a
narrowing enforced only in the list is one the model routes around by
remembering — the same reason the phase filter makes tools genuinely
absent rather than merely refused.
Sourcepub fn available_names(&self) -> Vec<&str>
pub fn available_names(&self) -> Vec<&str>
Names a call may reach right now, for the message that says so.
pub fn is_empty(&self) -> bool
pub fn len(&self) -> usize
pub fn iter(&self) -> impl Iterator<Item = &Arc<dyn Tool>>
Sourcepub fn carried_state(&self) -> Vec<CarriedState>
pub fn carried_state(&self) -> Vec<CarriedState>
Everything the registered tools want carried across a compaction.
In the registry’s stable order, so a compaction does not reorder the prompt for a reason nobody can see. Asked of every tool, including an MCP server’s — the loop does not learn which tools have state, only that some do, which is the same reason it never learns where a tool came from.
Sourcepub fn specs(&self) -> Vec<ToolSpec>
pub fn specs(&self) -> Vec<ToolSpec>
Specs in a stable order — the tool list is the very front of the prompt prefix, so reordering it would invalidate the cache on every request.
Sourcepub fn specs_for(&self, phase: Phase) -> Vec<ToolSpec>
pub fn specs_for(&self, phase: Phase) -> Vec<ToolSpec>
Specs a given phase permits, in the same stable order.
Note what this does to the prompt cache: planning sends a shorter tool list, so switching phase changes the front of the prefix and the next turn re-pays for it. That is the price of the tools being genuinely absent rather than merely refused, and it is the right trade.
Sourcepub fn forget_conversation_state(&self)
pub fn forget_conversation_state(&self)
The names the surface is currently narrowed to, if anything is narrowing it.
The union across everything that has an opinion, which is the only
composition that lets two restrictions coexist: each names the tools
its own procedure needs, and intersecting them would strand a run that
loaded two skills. The invariant that matters is not “smallest” but
“never larger than the unrestricted surface”, and a union of subsets is
still a subset — specs_for intersects with
what is registered, so a name nothing matches adds nothing.
A tool that is itself restricting stays in the surface whatever it
declared. Otherwise the first skill call could remove skill, and a
procedure that says “then load the follow-up skill” would name a tool
that had just been taken away — a restriction that eats its own
mechanism is a trap rather than a policy.
Tell every tool the conversation ended. See
Tool::forget_conversation_state.
pub fn surface_restriction(&self) -> Option<BTreeSet<String>>
Sourcepub fn with_builtins(self, cfg: &ToolsConfig, sandbox: Arc<Sandbox>) -> Self
pub fn with_builtins(self, cfg: &ToolsConfig, sandbox: Arc<Sandbox>) -> Self
Register the built-ins permitted by config.
The sandbox is passed in rather than read from config here because it
changes what shell is — an unconfined shell and a confined one
declare different capabilities, and the loop’s interlock reads them.