CoolFace
Apppublic

FlyingNunchucks/07-tool-using-agent

sourceHugging Facemitupdated 14d agoView on Hugging Face
0likes
README.md428 linesDownload Raw Back to root
1---2title: Governed Tool-Using Agent3emoji: ๐Ÿ› ๏ธ4colorFrom: blue5colorTo: indigo6sdk: gradio7sdk_version: 5.50.08app_file: app.py9pinned: false10license: mit11---12 13# 07. Governed Tool-Using Agent โ€” Application-Controlled Capability Boundary14 15A 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.16 17**Live Demo:** https://huggingface.co/spaces/FlyingNunchucks/07-tool-using-agent18 19The core pattern is:20 21> **The model proposes. Application code owns authorization, validation, execution, and auditability.**22 23## Why This Project Matters24 25Tool use is often described as function calling: the model decides it needs a function, calls it, receives a result, and continues reasoning.26 27That description hides the most important production question:28 29> **How do you let an AI use business systems without giving the model unrestricted authority over those systems?**30 31This 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.32 33## Business Scenario34 35The public demo presents a fictional operations copilot that may need three different classes of capability:36 37- deterministic local computation;38- controlled access to an internal inventory database;39- controlled access to an approved external reference API.40 41A representative request is:42 43```text44We may ship equipment to Japan. Find the Electronics items currently in45inventory, calculate an accessory budget of $347 per matching item, and46give me Japan's capital, region, and income classification.47```48 49The 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.50 51## Who Controls What?52 53| Model controls | Application code controls |54| --- | --- |55| Whether a tool appears necessary | Which tools exist at all |56| Which approved tool to request | Whether arguments match the approved schema |57| How to combine returned results | Whether execution is authorized |58| When enough information exists to answer | Tool execution |59| Final natural-language explanation | Failure normalization and audit logging |60 61This separation is the central engineering lesson of Agent 7.62 63## Approved Tool Belt64 65### `calculator`66 67A constrained deterministic arithmetic capability.68 69**Allowed:** approved arithmetic expressions.  70**Not allowed:** arbitrary Python or unrestricted `eval()`.71 72The implementation parses expressions through Python AST and permits only approved mathematical operations.73 74### `search_inventory`75 76A narrow SQLite inventory query interface.77 78**Allowed:** item/category inventory search.  79**Not allowed:** arbitrary SQL, writes, schema changes, or database administration.80 81The tool uses explicit parameters and parameterized SQL.82 83### `lookup_country`84 85A structured World Bank country-information lookup.86 87**Allowed:** approved country lookup through the intended endpoint.  88**Not allowed:** arbitrary URLs, open-ended browsing, or unrestricted network access.89 90The tool includes timeouts, HTTP error handling, response-shape checks, and normalized structured output.91 92## Architecture93 94```text95User request96    โ†“97LLM decides whether it needs a capability98    โ†“99Structured ToolCall100    โ†“101Application authorization boundary102    โ”œโ”€ blocked103    โ”‚    โ†“104    โ”‚ normalized blocked ToolResult + audit record105    โ”‚106    โ””โ”€ approved107         โ†“108    Controlled executor109         โ†“110    Approved capability111         โ†“112    Normalized ToolResult + audit record113         โ†“114    Result returned to model115         โ†“116Additional approved tool request or final answer117```118 119The model never receives unrestricted shell, Python, filesystem, SQL, or arbitrary network execution.120 121## Authorization and Failure Semantics122 123The retrofit made an important distinction explicit: **a rejected request and a failed authorized tool are not the same event.**124 125### Blocked before execution126 127The application refuses the request before the underlying capability runs. Examples include:128 129- unregistered tool name;130- missing required argument;131- unexpected argument;132- wrong argument type;133- arguments that violate the approved schema.134 135These outcomes are represented as structured `blocked` results.136 137### Approved but execution failed138 139The request crossed the authorization boundary successfully, but the approved capability itself encountered a runtime or dependency error. Examples include:140 141- division by zero;142- external API failure;143- other runtime exceptions inside an approved tool.144 145These outcomes are represented as structured `error` results.146 147### Successful execution148 149The tool was registered, its arguments passed validation, execution was authorized, and the capability returned a normalized result.150 151These outcomes are represented as `success`.152 153That three-way distinction makes the audit trail much more useful:154 155```text156blocked  = application refused authority157error    = authority was granted, execution failed158success  = authority was granted, execution succeeded159```160 161## Real Execution Observability162 163The original version returned the final answer, raw tool calls, raw results, and audit JSON only after the run completed.164 165The upgraded agent adds `run_agent_iter()` so the live UI can observe the real model/application interaction as it happens.166 167The existing `run_agent()` API remains intact and consumes the same generator path, so the demo does not use a second fake orchestration implementation.168 169The UI can expose real events such as:170 171```text172Request accepted173AI deciding174Model requested: search_inventory175Application approved176Tool completed177AI deciding178Model requested: calculator179Application approved180Tool completed181AI deciding182Final response183```184 185If an invalid capability is requested, the application can instead expose:186 187```text188Model requested189Application blocked190```191 192The generic Gradio progress indicator is hidden so the system's own authorization and execution events remain the primary run experience.193 194## Business-First Demo Presentation195 196The approved September 2026 presentation reframes the project from a generic function-calling demo into a **governed AI capability demo**.197 198The live Space now includes:199 200- a centered 1080px reading path;201- the business problem before implementation details;202- an approved tool belt showing both allowed and disallowed capability boundaries;203- an explicit **Model controls / Application controls** comparison;204- a flagship multi-tool operations request;205- **Live Controlled Execution** driven by real `run_agent_iter()` events;206- a business-facing result and controlled-execution summary;207- raw structured calls, results, and current-run audit records under **Engineering Audit**;208- dedicated **Security & Failure Semantics** and **Architecture** views.209 210The presentation principle is:211 212> **Business story first. Engineering evidence second. Make the trust boundary visible while the agent works.**213 214## Auditability215 216Every requested tool execution is associated with a structured call ID and normalized result. Audit records capture:217 218- tool name;219- structured arguments;220- result status;221- output or normalized error;222- start and completion timestamps;223- execution duration.224 225The audit log is persisted as JSONL in:226 227```text228logs/tool_audit.jsonl229```230 231The public interface displays only audit records associated with the current run. Historical records from other visitors are not exposed through the current-run view.232 233This is a privacy-conscious portfolio/demo design, not a production-certified multi-tenant security boundary.234 235## Multi-Tool Behavior236 237A 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.238 239The maximum number of tool rounds is bounded, preventing an uncontrolled loop from running indefinitely.240 241This design keeps model reasoning flexible while keeping capability authority deterministic and application-owned.242 243## Testing244 245Run locally with:246 247```bash248python -m pytest -q249```250 251Final approved retrofit result:252 253```text25423 passed in 2.92s255```256 257The suite covers:258 259- calculator restrictions and deterministic arithmetic;260- SQLite inventory search;261- mocked external country lookup behavior;262- approved tool execution;263- unregistered-tool blocking;264- missing, unexpected, and incorrectly typed argument blocking;265- explicit authorization results;266- separation of `blocked` from execution `error`;267- normalized runtime failures;268- timing metadata;269- deterministic `run_agent_iter()` event sequencing;270- preservation of the original `run_agent()` behavior;271- business-first presentation framing;272- 1080px centered layout;273- visible intermediate model-request / application-approval / tool-completion events before the final answer.274 275The deterministic CI suite does not require a live model-provider call.276 277## CI/CD278 279The project was also upgraded to the current portfolio deployment standard.280 281```text282push to main283    โ†“284GitHub Actions installs dependencies285    โ†“286pytest287    โ†“288only if tests pass289    โ†“290GitHub โ†’ Hugging Face sync291    โ†“292Space rebuild293```294 295The previous workflow synced directly to Hugging Face without a test gate. The final version deploys only after the automated suite passes.296 297GitHub remains the source of truth.298 299## Security and Public-Demo Boundaries300 301The project intentionally keeps the capability surface narrow:302 303- explicit tool registry / allowlist;304- schema-based arguments;305- application-owned authorization;306- no unrestricted `eval()`;307- no arbitrary SQL;308- no shell tool;309- no filesystem tool;310- no arbitrary-network tool;311- bounded tool rounds;312- normalized failures;313- current-run audit scoping;314- environment-based secret management;315- runtime database and audit files excluded from source control.316 317Runtime inference uses `HF_TOKEN` in the Hugging Face Space. Deployment uses the separate GitHub repository secret `HF_DEPLOY_TOKEN`.318 319The public demo uses synthetic inventory data and should not be used for confidential, client, financial, personal, or proprietary information.320 321## Repository Structure322 323```text324.325โ”œโ”€โ”€ app.py326โ”œโ”€โ”€ requirements.txt327โ”œโ”€โ”€ .env.example328โ”œโ”€โ”€ data/329โ”œโ”€โ”€ logs/330โ”œโ”€โ”€ src/331โ”‚   โ”œโ”€โ”€ agent.py332โ”‚   โ”œโ”€โ”€ audit.py333โ”‚   โ”œโ”€โ”€ demo_presentation.py334โ”‚   โ”œโ”€โ”€ executor.py335โ”‚   โ”œโ”€โ”€ schemas.py336โ”‚   โ”œโ”€โ”€ tool_registry.py337โ”‚   โ””โ”€โ”€ tools/338โ”‚       โ”œโ”€โ”€ calculator.py339โ”‚       โ”œโ”€โ”€ database.py340โ”‚       โ””โ”€โ”€ external_api.py341โ””โ”€โ”€ tests/342    โ”œโ”€โ”€ test_agent.py343    โ”œโ”€โ”€ test_app.py344    โ”œโ”€โ”€ test_executor.py345    โ””โ”€โ”€ test_tools.py346```347 348## Local Setup349 350```bash351git clone https://github.com/wushuchris/07-tool-using-agent.git352cd 07-tool-using-agent353python -m venv .venv354source .venv/bin/activate355pip install -r requirements.txt356```357 358Create a local `.env` containing your own inference credential:359 360```bash361HF_TOKEN=your_huggingface_token_here362```363 364Optionally set:365 366```bash367MODEL_ID=openai/gpt-oss-120b:cerebras368```369 370Then run:371 372```bash373python app.py374```375 376## Production Upgrade Path377 378A production system could extend this primitive with:379 380- per-tool identity and authorization policy;381- user- or role-specific capability scopes;382- approval workflows for high-impact tools;383- stronger JSON Schema validation;384- idempotency keys for side-effecting tools;385- retry / circuit-breaker policy by tool;386- rate limits and budgets;387- secret brokering instead of direct credential exposure;388- persistent centralized audit storage;389- policy decision telemetry;390- sandboxing for selected execution classes;391- stronger tool-result provenance and downstream verification.392 393## Reusable Agent Primitive394 395The reusable primitive demonstrated here is an **application-owned capability boundary**:396 397```text398Governed tool use399= model-selected intent400+ explicit capability registry401+ typed arguments402+ authorization403+ controlled execution404+ normalized outcomes405+ bounded loops406+ auditability407```408 409The important idea is not that the LLM can call functions.410 411It is that the LLM **cannot grant itself authority**.412 413## Design Lessons414 4151. Function calling is a model interface; authorization is an application responsibility.4162. Tool selection and tool execution should remain separate concerns.4173. A model request is not permission to execute.4184. Blocked requests should be distinguishable from authorized execution failures.4195. Explicit schemas and allowlists create inspectable trust boundaries.4206. Tool failures should become normalized data rather than uncontrolled exceptions.4217. Multi-tool reasoning can remain flexible while execution authority remains deterministic.4228. Auditability should be tied to actual capability calls, not inferred afterward.4239. The strongest demo makes the model/application authority boundary visible while the system is running.424 425## License426 427MIT License.428