feat: API collector — agent inspection in the proxy (phase 11b) - #18
Merged
Merged
Conversation
…proxy) Embedded AgentFirewall in the reverse proxy parses tool_use/tool_result blocks from OpenAI/Anthropic traffic and applies agent-layer verdicts. Stateless per-cycle (each request re-sends history), blockable moment is the response's tool_use, flag/shadow by default, off unless configured, fails open. v1 defers streaming tool_use parsing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
7 TDD tasks: relax the OpenAI request model for tool-call messages, agent_scan extraction (OpenAI + Anthropic tool_result/tool_use), per-cycle AgentFirewall, agent_inspection config, handler wiring on the response path, end-to-end test, README + PR. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
ChatMessage.content is now Option<String> (None for assistant tool-call messages) with a flattened rest map capturing tool_calls/tool_call_id, so tool-using conversations parse instead of 400-ing. The text pipeline skips null-content messages. Prereq for the agent collector to see tool blocks. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
OpenAI + Anthropic tool_result/tool_use extraction and inspect_cycle: feed request tool outputs as taint, check the response's tool calls against it, return the worst verdict. The single-request kill chain (tainted output -> exfil tool call) is caught. Adds the llm-firewall-agent dependency to the proxy. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
AppState gains an AgentFirewall (behind a Mutex). Both the OpenAI and Anthropic non-streaming response paths, when agent_inspection.enabled, extract the response's tool calls + the request's tool results, run inspect_cycle, and (only when enforce is on and the verdict is Deny) refuse the response with an error body. Otherwise the verdict is audited and the response passes (shadow-first). Derives AgentInspection::default. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Drives the router with a mock upstream returning a tool call that exfiltrates an AWS secret (a deterministic deny-secret-egress Deny). enforce -> 502; shadow -> 200 (audited only); disabled -> 200 unchanged. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Adds an 'Agent inspection in the API proxy' subsection (agent_inspection config, the stateless per-cycle model, the response-tool_use blockable moment, shadow- first, streaming gap), updates the test badge (405->415) and proxy crate count (24->34), and records phase 11b in the history and roadmap. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
Phase 11b — the API collector
The reverse proxy already inspected request/response text. This embeds an
AgentFirewallin it so it also inspects thetool_use/tool_resultblocks in OpenAI and Anthropic traffic — giving tool-boundary protection (taint, egress, secrets, injection) to any framework speaking those APIs, not just Claude Code.The stateless simplification
Every API request re-sends the whole conversation, so the collector works per request/response cycle with no state: the request's
tool_resultblocks build the taint set; the model response'stool_useblocks are the actions checked against it. No session store, no cross-request bleed.What it catches
Via the existing
AgentFirewall+ shipped policy: atool_useacting on content tainted by an earliertool_result(indirect injection), secrets/PII in tool arguments, egress to a non-allowlisted host, destructive/privilege actions.Verdict → action
The blockable moment is the response (the proxy can't stop a tool the client already ran).
Deny+enforce→ refuse the response with an error body; otherwise audit and pass. Off by default, shadow-first (agent_inspection.enabled/.enforce, both default false).Notable change
The OpenAI request model (
ChatMessage.content) is relaxed toOption<String>so tool-call conversations (assistant messages withcontent: null+tool_calls) parse instead of 400-ing.Tests
415 workspace tests (from 405), 0 failing; clippy
-D warningsclean; fmt clean. New: OpenAI + Anthropic tool-block extraction, the single-request taint kill chain,inspect_cycle, theagent_inspectionconfig, and 3 end-to-end handler tests (enforce → 502, shadow → 200, disabled → 200 unchanged).v1 deferrals
Streaming (SSE)
tool_useisn't structurally parsed — streamed responses skip agent inspection (the text layer's sliding scan still applies). Request-sidetool_use(already executed) isn't inspected.Denyrefuses the whole response rather than stripping the block.Design:
docs/superpowers/specs/2026-07-30-agent-firewall-11b-api-collector-design.md. Plan:docs/superpowers/plans/2026-07-30-agent-firewall-11b-api-collector.md.🤖 Generated with Claude Code