feat(responses): tool calling on /v1/responses (#158) #159
Reference in New Issue
Block a user
Delete Branch "feat/158-responses-tool-calls"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Fixes #158. Follow-up to #156/#157 — ZeroClaw chats stream answers now; this makes the agent able to act.
Request side (
request_to_chat): Responses-flat tool definitions ({type:"function", name, description, parameters}) are normalized into the chat-wrapped shape and carried throughextra["tools"], which the chat path already consumes for Jinja prompt rendering and argument-type coercion (build_tool_schemastolerates both shapes). Already-wrapped tools pass through; hosted tool types (web_search, …) are dropped since there's no server-side implementation.Response side (
run_projection): harnessInferenceEvent::ToolCalls project into the OpenAI function_call event family:and the terminal
response.completedoutput array carries the completedfunction_callitems after the message item. ZeroClaw's parser consumes exactly this family (dedup acrossarguments.done/output_item.done/completed, verified against its source).Input-side round-tripping (
function_call→ assistanttool_calls,function_call_output→ tool-role message) already existed — chat templates read both — so the full agentic loop closes.Non-streaming
/v1/responsesstays text-only (matches the chat non-streaming path; ZeroClaw streams).Tests: tools normalization (flat/wrapped/hosted), full function_call event-family projection, plus the existing frame-shape suite.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Wpr9zRuucU5KXa7TCrQV6k
Request side: request_to_chat now normalizes Responses-flat tool definitions ({type:"function", name, …}) into the chat-wrapped shape ({type:"function", function:{…}}) and carries them through extra so the chat template renders them and build_tool_schemas coerces arguments. Hosted tool types (web_search, …) are dropped. Response side: the streaming projector maps InferenceEvent::ToolCall into the OpenAI function_call event family — output_item.added, function_call_arguments.delta, function_call_arguments.done, output_item.done — and the terminal response.completed output array carries the completed function_call items after the message item. Input-side round-tripping (function_call → assistant tool_calls, function_call_output → tool-role message) already existed and is now exercised end-to-end. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Wpr9zRuucU5KXa7TCrQV6k