FlyingNunchucks/07-tool-using-agent
07. Governed Tool-Using Agent — Application-Controlled Capability Boundary
A business-facing demonstration of how an LLM can use approved capabilities without being given unrestricted access to code execution, databases, filesystems, or arbitrary network resources.
Live Demo: https://huggingface.co/spaces/FlyingNunchucks/07-tool-using-agent
The core pattern is:
The model proposes. Application code owns authorization, validation, execution, and auditability.
Why This Project Matters
Tool use is often described as function calling: the model decides it needs a function, calls it, receives a result, and continues reasoning.
That description hides the most important production question:
How do you let an AI use business systems without giving the model unrestricted authority over those systems?
This project answers that with an explicit application-owned capability boundary. The model may decide that a tool is useful, but every requested action must pass through a controlled registry, schema validation, authorization, normalized execution, and audit logging before an approved capability can run.
Business Scenario
The public demo presents a fictional operations copilot that may need three different classes of capability:
- deterministic local computation;
- controlled access to an internal inventory database;
- controlled access to an approved external reference API.
A representative request is:
We may ship equipment to Japan. Find the Electronics items currently in
inventory, calculate an accessory budget of $347 per matching item, and
give me Japan's capital, region, and income classification.The request is intentionally multi-tool. The workflow is not hardcoded: the model chooses which approved tools to request and when, while application code decides what is actually allowed to execute.
Who Controls What?
This separation is the central engineering lesson of Agent 7.
Approved Tool Belt
calculator
A constrained deterministic arithmetic capability.
Allowed: approved arithmetic expressions. Not allowed: arbitrary Python or unrestricted eval().
The implementation parses expressions through Python AST and permits only approved mathematical operations.
search_inventory
A narrow SQLite inventory query interface.
Allowed: item/category inventory search. Not allowed: arbitrary SQL, writes, schema changes, or database administration.
The tool uses explicit parameters and parameterized SQL.
lookup_country
A structured World Bank country-information lookup.
Allowed: approved country lookup through the intended endpoint. Not allowed: arbitrary URLs, open-ended browsing, or unrestricted network access.
The tool includes timeouts, HTTP error handling, response-shape checks, and normalized structured output.
Architecture
User request
↓
LLM decides whether it needs a capability
↓
Structured ToolCall
↓
Application authorization boundary
├─ blocked
│ ↓
│ normalized blocked ToolResult + audit record
│
└─ approved
↓
Controlled executor
↓
Approved capability
↓
Normalized ToolResult + audit record
↓
Result returned to model
↓
Additional approved tool request or final answerThe model never receives unrestricted shell, Python, filesystem, SQL, or arbitrary network execution.
Authorization and Failure Semantics
The retrofit made an important distinction explicit: a rejected request and a failed authorized tool are not the same event.
Blocked before execution
The application refuses the request before the underlying capability runs. Examples include:
- unregistered tool name;
- missing required argument;
- unexpected argument;
- wrong argument type;
- arguments that violate the approved schema.
These outcomes are represented as structured blocked results.
Approved but execution failed
The request crossed the authorization boundary successfully, but the approved capability itself encountered a runtime or dependency error. Examples include:
- division by zero;
- external API failure;
- other runtime exceptions inside an approved tool.
These outcomes are represented as structured error results.
Successful execution
The tool was registered, its arguments passed validation, execution was authorized, and the capability returned a normalized result.
These outcomes are represented as success.
That three-way distinction makes the audit trail much more useful:
blocked = application refused authority
error = authority was granted, execution failed
success = authority was granted, execution succeededReal Execution Observability
The original version returned the final answer, raw tool calls, raw results, and audit JSON only after the run completed.
The upgraded agent adds run_agent_iter() so the live UI can observe the real model/application interaction as it happens.
The existing run_agent() API remains intact and consumes the same generator path, so the demo does not use a second fake orchestration implementation.
The UI can expose real events such as:
Request accepted
AI deciding
Model requested: search_inventory
Application approved
Tool completed
AI deciding
Model requested: calculator
Application approved
Tool completed
AI deciding
Final responseIf an invalid capability is requested, the application can instead expose:
Model requested
Application blockedThe generic Gradio progress indicator is hidden so the system's own authorization and execution events remain the primary run experience.
Business-First Demo Presentation
The approved September 2026 presentation reframes the project from a generic function-calling demo into a governed AI capability demo.
The live Space now includes:
- a centered 1080px reading path;
- the business problem before implementation details;
- an approved tool belt showing both allowed and disallowed capability boundaries;
- an explicit Model controls / Application controls comparison;
- a flagship multi-tool operations request;
- Live Controlled Execution driven by real
run_agent_iter()events; - a business-facing result and controlled-execution summary;
- raw structured calls, results, and current-run audit records under Engineering Audit;
- dedicated Security & Failure Semantics and Architecture views.
The presentation principle is:
Business story first. Engineering evidence second. Make the trust boundary visible while the agent works.
Auditability
Every requested tool execution is associated with a structured call ID and normalized result. Audit records capture:
- tool name;
- structured arguments;
- result status;
- output or normalized error;
- start and completion timestamps;
- execution duration.
The audit log is persisted as JSONL in:
logs/tool_audit.jsonlThe public interface displays only audit records associated with the current run. Historical records from other visitors are not exposed through the current-run view.
This is a privacy-conscious portfolio/demo design, not a production-certified multi-tenant security boundary.
Multi-Tool Behavior
A model can request several approved capabilities over multiple rounds. Tool results are returned to the model as structured messages, allowing it to determine whether another tool is required before producing a final answer.
The maximum number of tool rounds is bounded, preventing an uncontrolled loop from running indefinitely.
This design keeps model reasoning flexible while keeping capability authority deterministic and application-owned.
Testing
Run locally with:
python -m pytest -qFinal approved retrofit result:
23 passed in 2.92sThe suite covers:
- calculator restrictions and deterministic arithmetic;
- SQLite inventory search;
- mocked external country lookup behavior;
- approved tool execution;
- unregistered-tool blocking;
- missing, unexpected, and incorrectly typed argument blocking;
- explicit authorization results;
- separation of
blockedfrom executionerror; - normalized runtime failures;
- timing metadata;
- deterministic
run_agent_iter()event sequencing; - preservation of the original
run_agent()behavior; - business-first presentation framing;
- 1080px centered layout;
- visible intermediate model-request / application-approval / tool-completion events before the final answer.
The deterministic CI suite does not require a live model-provider call.
CI/CD
The project was also upgraded to the current portfolio deployment standard.
push to main
↓
GitHub Actions installs dependencies
↓
pytest
↓
only if tests pass
↓
GitHub → Hugging Face sync
↓
Space rebuildThe previous workflow synced directly to Hugging Face without a test gate. The final version deploys only after the automated suite passes.
GitHub remains the source of truth.
Security and Public-Demo Boundaries
The project intentionally keeps the capability surface narrow:
- explicit tool registry / allowlist;
- schema-based arguments;
- application-owned authorization;
- no unrestricted
eval(); - no arbitrary SQL;
- no shell tool;
- no filesystem tool;
- no arbitrary-network tool;
- bounded tool rounds;
- normalized failures;
- current-run audit scoping;
- environment-based secret management;
- runtime database and audit files excluded from source control.
Runtime inference uses HF_TOKEN in the Hugging Face Space. Deployment uses the separate GitHub repository secret HF_DEPLOY_TOKEN.
The public demo uses synthetic inventory data and should not be used for confidential, client, financial, personal, or proprietary information.
Repository Structure
.
├── app.py
├── requirements.txt
├── .env.example
├── data/
├── logs/
├── src/
│ ├── agent.py
│ ├── audit.py
│ ├── demo_presentation.py
│ ├── executor.py
│ ├── schemas.py
│ ├── tool_registry.py
│ └── tools/
│ ├── calculator.py
│ ├── database.py
│ └── external_api.py
└── tests/
├── test_agent.py
├── test_app.py
├── test_executor.py
└── test_tools.pyLocal Setup
git clone https://github.com/wushuchris/07-tool-using-agent.git
cd 07-tool-using-agent
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtCreate a local .env containing your own inference credential:
HF_TOKEN=your_huggingface_token_hereOptionally set:
MODEL_ID=openai/gpt-oss-120b:cerebrasThen run:
python app.pyProduction Upgrade Path
A production system could extend this primitive with:
- per-tool identity and authorization policy;
- user- or role-specific capability scopes;
- approval workflows for high-impact tools;
- stronger JSON Schema validation;
- idempotency keys for side-effecting tools;
- retry / circuit-breaker policy by tool;
- rate limits and budgets;
- secret brokering instead of direct credential exposure;
- persistent centralized audit storage;
- policy decision telemetry;
- sandboxing for selected execution classes;
- stronger tool-result provenance and downstream verification.
Reusable Agent Primitive
The reusable primitive demonstrated here is an application-owned capability boundary:
Governed tool use
= model-selected intent
+ explicit capability registry
+ typed arguments
+ authorization
+ controlled execution
+ normalized outcomes
+ bounded loops
+ auditabilityThe important idea is not that the LLM can call functions.
It is that the LLM cannot grant itself authority.
Design Lessons
- Function calling is a model interface; authorization is an application responsibility.
- Tool selection and tool execution should remain separate concerns.
- A model request is not permission to execute.
- Blocked requests should be distinguishable from authorized execution failures.
- Explicit schemas and allowlists create inspectable trust boundaries.
- Tool failures should become normalized data rather than uncontrolled exceptions.
- Multi-tool reasoning can remain flexible while execution authority remains deterministic.
- Auditability should be tied to actual capability calls, not inferred afterward.
- The strongest demo makes the model/application authority boundary visible while the system is running.
License
MIT License.
