Repository navigation
Agent permissions: team tools decide by their approved definition; denied tools are never offered - #466
Merged
Conversation
…d denied tools are never offered
The planner was offered a team's approved tools (tool_find_order and the
like) but the policy engine had no risk for them, so every call was denied
as unknown and the model kept calling them.
- Tools a team sets up form families (team tools, connection tools). Each
registers its tools where it offers them, with the risk its definition
gives: a team tool from its approved version's kind (every kind is a
checked read), a connection tool from the server's own hints, else its
name. The engine reads built-ins, then registrations.
- A team tool with no runnable version stays denied with a plain reason:
no approved version, switched off, or changed since it was approved.
- Every model loop (runs, plan chat, Chat) drops tools the policy denies
whatever the call says before the model sees them; attempted calls are
still decided and logged.
- Decision log lines carry the tool's name for people ("Find order"), and
the activity endpoint fills it in for team tools logged before.
- The settings "test a call" box reads a team tool's standing.
- Tests: a team tool reads under the default policy, a changed one is
denied with the reason, denied tools aren't offered (gate, worker, chat),
and every runtime tool name belongs to a family with a risk mapping.
This was referenced Nov 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
On a self-hosted install the planner kept calling the team's own approved tools (
tool_find_classand others) and every call was denied: "Nothing says what tool_find_class does, so it doesn't run. Unknown tools are always denied." The policy engine resolved risk only from a fixed built-in list, so a team's tools had none, yet the model was still offered them.Team tools now get their risk from their approved definition, the same way built-ins do, and no agent is offered a tool the policy would refuse whatever the call says.
Changes
agent_policy::registry): tools a team sets up (team toolstool_<name>, connection tools<server>__<tool>) register where they are offered, with the risk their definition gives.registry::knownreads built-ins, then registrations, then a connection tool's name. Team tools: risk from the approved version's kind (ToolKind::risk, all four kinds are checked reads). Connection tools: the server's own hints (read only, destructive), else the name.tools_store::standingsays why a team tool can't run (no approved version, switched off, changed since it was approved; "approve the new version in Settings, Tools"). The engine takesKnown::Refused(reason)and denies with that reason.Gate::offerabledrops tools that are unknown, unrunnable, switched off for the agent or denied by a rule. Used by every worker model loop (agent::policy::offerableinprovider::converse) and both chats (chat_policy::offer). Nothing is logged for the offer; attempted calls are still decided and logged.policy.tool_label("Find order");/api/agents/activityfills it in for team tool events logged before this.Verification
cargo fmt --check,cargo clippy --workspace --all-targets -D warnings,cargo test --workspace(common 1395, gateway 697, worker 1180): all pass.read_fileand the approved tool, and attempted calls to withheld tools are refused and logged; chats drop unknown tools;every_tool_family_has_a_risk_mappingandevery_runtime_tool_name_belongs_to_a_familyfail when a family or a runtime-built tool name has no risk.