Tool Approval Agent
Tool approval agent example.
Tool Approval Example.
Run it
python examples/ai/tool_approval_agent.py
"""
Tool Approval Example.
Demonstrates human-in-the-loop approval for dangerous tool calls. The agent
has the standard system tool set, with the shell tool gated by the engine's
``requires_approval`` primitive — when the model calls ``shell``, the
workflow pauses until an operator approves or rejects the call.
Prerequisites:
1. Install Ollama and pull a model: ollama pull llama3.2
2. Start Ollama service: ollama serve
Usage:
flux workflow register examples/ai/tool_approval_agent.py
flux workflow run tool_approval_demo '{"task": "List files in the current directory"}'
When the agent calls the shell tool the workflow pauses; inspect with:
flux execution approvals --execution <execution_id>
Approve:
flux execution approve <execution_id> <task_call_id> --reason "lgtm"
Reject:
flux execution reject <execution_id> <task_call_id> --reason "no"
"""
from __future__ import annotations
from typing import Any
from flux import ExecutionContext, workflow
from flux.tasks.ai import agent
from flux.tasks.ai.tools.system_tools import system_tools
def _gate_shell(tools: list) -> list:
"""Wrap only the ``shell`` tool with requires_approval=True; pass others through."""
gated: list = []
for tool in tools:
func = tool.func if hasattr(tool, "func") else tool
if getattr(func, "__name__", "") == "shell" and hasattr(tool, "with_options"):
gated.append(tool.with_options(requires_approval=True))
else:
gated.append(tool)
return gated
@workflow
async def tool_approval_demo(ctx: ExecutionContext[dict[str, Any]]):
raw = ctx.input or {}
task_description = raw.get("task", "List the files in the current directory")
tools = _gate_shell(system_tools("./workspace", timeout=10))
assistant = await agent(
"You are a helpful assistant with access to system tools. "
"Use them to complete the user's request.",
model="ollama/llama3.2",
name="tool_approval_assistant",
tools=tools,
stream=False,
)
return await assistant(task_description)
if __name__ == "__main__": # pragma: no cover
import json
result = tool_approval_demo.run({"task": "List all Python files"})
if result.is_paused:
print(f"Paused for approval. Execution ID: {result.execution_id}")
print(f"Pending: {json.dumps(result.output, indent=2)}")
elif result.has_succeeded:
print(result.output)
else:
print(f"Failed: {result.output}")
Last verified against Flux 0.56.0.