Tool Calling¶
When a request declares tools, VidaiMock returns a correctly-shaped
tool-call response for that provider — echoing the caller's declared tool
name, not a hard-coded demo tool. This means SDK tests that assert "the
tool I registered was invoked" pass against the mock.
Per-provider shapes¶
| Provider | Request field | Response shape |
|---|---|---|
| OpenAI | tools[].function.name |
choices[].message.tool_calls[], finish_reason: "tool_calls" |
| Anthropic | tools[].name |
content[].type == "tool_use", stop_reason: "tool_use" |
| Gemini | tools[].functionDeclarations[].name |
candidates[].content.parts[].functionCall, finishMessage set |
Arguments default to an empty object ({} / args: {} / input: {}).
Tests assert on the tool name and shape, not synthesised argument values;
if you need specific arguments, override the template (see below).
OpenAI example¶
curl http://localhost:8100/v1/chat/completions \
-H "Content-Type: application/json" \
-d '{"model": "gpt-4o",
"messages": [{"role": "user", "content": "Weather?"}],
"tools": [{"type": "function",
"function": {"name": "get_weather", "parameters": {}}}]}'
Response:
{"choices":[{"message":{"role":"assistant","content":null,
"tool_calls":[{"id":"call_mock_...","type":"function",
"function":{"name":"get_weather","arguments":"{}"}}]},
"finish_reason":"tool_calls"}]}
If you had declared broken_tool instead, the response would name
broken_tool — the mock does not substitute its own tool.
Anthropic example¶
curl http://localhost:8100/v1/messages \
-H "Content-Type: application/json" \
-d '{"model": "claude", "max_tokens": 200,
"messages": [{"role": "user", "content": "Weather?"}],
"tools": [{"name": "get_weather", "description": "x",
"input_schema": {"type": "object"}}]}'
Returns a tool_use content block with caller.type: "direct".
Gemini example¶
curl http://localhost:8100/v1beta/models/gemini-2.5-flash:generateContent \
-H "Content-Type: application/json" \
-d '{"contents": [{"role": "user", "parts": [{"text": "Weather?"}]}],
"tools": [{"functionDeclarations": [{"name": "get_weather",
"parameters": {"type": "OBJECT"}}]}]}'
Streaming tool calls¶
A streaming request that returns a tool call emits the call as a single
structured frame — not word-chunked text. OpenAI streams a single
tool_calls delta; Anthropic streams a tool_use content_block_start
followed by input_json_delta; Gemini streams a single functionCall
frame. All single-line JSON, parseable by the real SDKs. See
Streaming.
Loop termination¶
The interesting part: a tool call alone is not enough — real agents loop. When the request history already contains a tool result, VidaiMock stops returning tool calls and answers in plain text, exactly like a real model. This is what makes agentic testing work. See Agentic workflow testing.
Customising the tool response¶
The bundled templates pick the first declared tool with empty args. To
return specific arguments, a fixed tool, or multiple parallel tool calls,
override the provider's template — see
Writing templates. The bundled
openai/tool_call.json.j2 is kept as a static-demo template you can point a
provider at if you want fixed get_weather behaviour.