Skip to content

feat: OpenAI-compatible tool calling support#14

Open
timbellay wants to merge 1 commit into
jasl:mainfrom
timbellay:feat/tool-calling
Open

feat: OpenAI-compatible tool calling support#14
timbellay wants to merge 1 commit into
jasl:mainfrom
timbellay:feat/tool-calling

Conversation

@timbellay

Copy link
Copy Markdown

Description:
Adds tool calling to the chat completions endpoint, enabling use with AI agent frameworks (MCP, LangChain, AgentPack) that expect the OpenAI tools API.

What changed
app/routes/chat.py

tools and tool_choice fields in ChatCompletionRequest
tool role with tool_call_id in ChatMessage for multi-turn tool conversations
_parse_tool_calls() — extracts structured tool calls from raw model output (Qwen3 <tool_call> tags, Mistral [TOOL_CALLS] format)
tool_calls array and nullable content in response, finish_reason: "tool_calls"

app/models/text_chat.py and app/models/qwen_vl.py

tools parameter threaded through count_tokens() and prepare_inputs() to tokenizer.apply_chat_template(tools=...)
HF tokenizers handle prompt formatting per model family automatically — no custom templates needed

How it works

Client sends tools array in the request (OpenAI format)
Tools are passed to apply_chat_template(tools=...) — the model's tokenizer handles injection
Model output is scanned by _parse_tool_calls() for known patterns
If tool calls are detected, response returns structured tool_calls with finish_reason: "tool_calls"
Client executes tools, sends results back as role: "tool" messages
Model generates final natural language response

Tested on
Jetson Thor (CUDA 13, JetPack 7) with Qwen/Qwen3-4B-Instruct-2507:

Single tool call ✅
Parallel multi-tool calls (2 simultaneous) ✅
Full tool result round-trip (tool results → natural language synthesis) ✅
112/112 existing tests pass ✅

- tools + tool_choice fields in ChatCompletionRequest schema
- tool role messages with tool_call_id for multi-turn conversations
- Tools threaded to tokenizer.apply_chat_template(tools=...)
- Output parser for Qwen3 <tool_call> and Mistral [TOOL_CALLS] formats
- Structured tool_calls array in response with finish_reason: tool_calls
- All 112 existing tests pass
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant