Enable Tool Permission HITL
Use this when tool calls must be allow / deny / ask with human approval.
Prerequisites
tirea-extension-permissionis enabled.- Frontend can return approval decisions to run inputs.
Steps
- Register permission behaviors.
use std::sync::Arc;
use tirea::composition::{AgentDefinition, AgentDefinitionSpec, AgentOsBuilder};
use tirea::extensions::permission::{PermissionPlugin, ToolPolicyPlugin};
let os = AgentOsBuilder::new()
.with_registered_behavior("tool_policy", Arc::new(ToolPolicyPlugin))
.with_registered_behavior("permission", Arc::new(PermissionPlugin))
.with_agent_spec(AgentDefinitionSpec::local_with_id(
"assistant",
AgentDefinition::new("deepseek-chat").with_behavior_ids(vec![
"tool_policy".to_string(),
"permission".to_string(),
]),
))
.build()?;
- Configure permission policy state.
use tirea::extensions::permission::{
permission_state_action, PermissionAction, ToolPermissionBehavior,
};
let set_default = permission_state_action(PermissionAction::SetDefault {
behavior: ToolPermissionBehavior::Ask,
});
let allow_server_info = permission_state_action(PermissionAction::SetTool {
tool_id: "serverInfo".to_string(),
behavior: ToolPermissionBehavior::Allow,
});
- Optional: constrain tools per agent via
AgentDefinition.
AgentDefinition::new("deepseek-chat")
.with_allowed_tools(vec!["search".to_string()])
.with_excluded_tools(vec!["dangerous_tool".to_string()])
These populate RunPolicy.allowed_tools / RunPolicy.excluded_tools, which are enforced by ToolPolicyPlugin before tool execution.
- Forward approval decisions from client to active run.
curl -X POST \
-H 'content-type: application/json' \
-d '{"decisions":[{"target_id":"fc_call_1","decision_id":"d1","action":"resume","result":{"approved":true},"updated_at":1760000000000}]}' \
http://127.0.0.1:8080/v1/runs/<run_id>/inputs
Verify
allow: tool executes immediately.deny: tool execution is rejected by policy.ask: run suspends until decision is forwarded.
Common Errors
- Registering plugin but forgetting to include behavior ids in agent definition.
- Wrong behavior order (
permissionbeforetool_policy) makes out-of-scope checks less strict. - Missing
target_id/ malformed decisions prevents resume.
Related Example
examples/copilotkit-starter/README.mdis the most complete approval-focused frontend integrationexamples/travel-ui/README.mdshows approval-gated trip creationexamples/research-ui/README.mdshows approval-gated resource deletion
Key Files
crates/tirea-extension-permission/src/plugin.rsexamples/src/starter_backend/mod.rsexamples/ai-sdk-starter/src/components/tools/permission-dialog.tsxexamples/travel-ui/hooks/useTripApproval.tsxexamples/research-ui/hooks/useDeleteApproval.tsx