Why tool calls need their own testing story
Tools are where your agent touches the real world: bookings, transfers, payments, SMS. That makes them both the riskiest thing to test (a test call that books a real appointment is not a test, it is an incident) and the most important thing to verify (a perfectly polite agent that callsbook_appointment with the wrong date is failing its job).
Roark solves both halves:
The rest of this page walks them in the order a new project adopts them.
Step 1: Make test calls safe (the tool guard)
Wrap a side-effecting tool once. On a real caller’s session the wrapper is a pass-through. During a Roark test call the tool body never runs: the wrapper sends the invocation to Roark and returns a simulated backend response that matches the tool’s contract, follows the test scenario (a scenario about a fully booked calendar gets a realistic “no availability” from a booking tool), and stays consistent with earlier tool responses in the same call.book, cancel, send_sms, transfer, charge); leave read-only lookups unwrapped when live data makes the test more realistic. Two safety properties hold by construction: a real caller can never receive a fake response (the guard only diverts on sessions Roark itself identified as simulations, and the endpoint re-validates the simulation before answering), and a guarded tool can never fire during a test (every error path maps to “use your static fallback”, except a 404, which genuinely means the session is not a known simulation).
Full setup: code-first agents
The complete decorator, framework wiring for LiveKit and Pipecat, and the exact failure contract.
Step 2: Force the outcomes you want to test (fixtures)
Generated mocks are plausible; sometimes a test needs exact. A fixture pins a tool’s response so a scenario always exercises one branch: what does the agent do when there are no slots, when the payment is declined, when the lookup finds two accounts?Step 3: Verify what your agent actually called
After a test call, ask Roark what the agent tried to do. Every guarded invocation is recorded against the simulation: tool, arguments verbatim, the response served, and whether it came from a fixture or the model.charge_card on the refund scenario, the booking arguments match what the caller asked for. The list is empty when the tools are not guarded; that usually means step 1 is not wired for this agent.
Step 4: Grade it automatically (metrics)
For judgment calls that raw assertions cannot express (“was this the right tool at the right moment?”), Roark ships the Tool Invocation Analysis package. Find it under Metrics > Library:
Configure once, use everywhere: under Tool Scoping, select a specific tool and define when it should be called and what result is expected, or leave scoping empty to evaluate all tools. Use Additional Instructions for cross-tool rules like “Never call any tool before greeting the customer.”
In simulations
1
Create a Run Plan
Follow the run plan guide and pick the scenarios that should trigger the tool calls under test. Add fixtures (step 2) to the scenarios that need forced outcomes.
2
Add Tool Invocation Metrics
In the Metrics section of the run plan, select the metrics you configured above.
3
Enable Enriched Simulations
Metrics grade the tool data on your side of the call, so your agent must send its call data to Roark: see Enriched Simulations. If you use the tool guard, your guarded invocations are attached to the merged call automatically; you do not need to report them separately. Unguarded tools still need tool invocation data included with your call.
4
Run and read
Execute the plan. Once your agent’s call is matched with the simulation, the tool invocation metrics are evaluated automatically and land in the run report.
In production
The same metrics run continuously on live calls through a collector. Live calls always hit your real tools (the guard never mocks real traffic; that property is structural), so this is pure observation:Production calls must include tool invocation data for these metrics to work. Tool calls are captured automatically for Vapi and Retell integrations; for the API or code-first stacks, include tool invocations when you create the call or attach them afterward.
The loop, end to end
A team starting from zero gets to a full tool-testing loop in an afternoon: wrap the writes with the guard, pin fixtures for the branches that matter, run the plan, assert on the mocked invocations in CI, and let the Tool Invocation Analysis metrics grade every run and every production call from then on. Nothing real is booked, sent, or charged along the way.Next Steps
Code-first agents
The tool guard’s full setup for LiveKit and Pipecat, plus Autoimprove on your own stack
Tool Invocations
How to submit tool call data with your calls
Enriched Simulations
Enable call matching for simulation tool testing
Collectors
Automate metric collection on production calls