[PR #23581] [CLOSED] fix: native function calling for REST API consumers #66120

Closed
opened 2026-05-06 12:16:16 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/open-webui/open-webui/pull/23581
Author: @PedroFCM
Created: 4/10/2026
Status: Closed

Base: devHead: fix/native-tool-calling-api-loop


📝 Commits (1)

  • ec17516 fix: native function calling for REST API consumers

📊 Changes

1 file changed (+70 additions, -7 deletions)

View changed files

📝 backend/open_webui/main.py (+70 -7)

📄 Description

Two fixes for native function calling, especially for REST API consumers that bypass the frontend WebSocket session:

  1. Pass through the function_calling value as-is instead of only checking for 'native' and falling back to 'default'. This respects values set via DEFAULT_MODEL_PARAMS or per-model params.

  2. Add server-side tool-calling loop for API calls (no session_id). The native tool execution loop is driven by the frontend via WebSocket. REST API calls never enter that loop, so tool_calls are returned raw and tools are never executed. This adds a loop that executes tools and re-invokes the LLM until finish_reason != 'tool_calls' or CHAT_RESPONSE_MAX_TOOL_CALL_RETRIES is reached.

Ref: #9435
Replaces PR: #23515 (closed - updated based on bot review feedback)

Pull Request Checklist

  • Target branch: dev
  • Description: See above and changelog below
  • Changelog: See below
  • Documentation: N/A - no new env vars or user-facing config; uses existing CHAT_RESPONSE_MAX_TOOL_CALL_RETRIES
  • Dependencies: No new dependencies
  • Testing: Tested on a deployment environment (AWS ECS Fargate + Bedrock Access Gateway) with Claude models. Verified via REST API (/api/chat/completions) with both stream: true and stream: false. Tool calls are executed server-side and the LLM produces a final response incorporating tool results. Frontend WebSocket flow unaffected.
  • Agentic AI Code: AI-assisted with human review and manual testing on deployment environment
  • Code review: Self-reviewed; addressed both findings from automated review on #23515
  • Design & Architecture: No new settings; uses existing CHAT_RESPONSE_MAX_TOOL_CALL_RETRIES
  • Git Hygiene: Single atomic commit rebased on dev
  • Title Prefix: fix:

Changelog Entry

Description

  • Fix native function calling for REST API consumers (/api/chat/completions) that don't use a WebSocket session

Fixed

  • function_calling parameter now passes through the configured value instead of only recognizing 'native' and falling back to 'default'
  • REST API calls with native function calling now execute tools server-side and re-invoke the LLM with tool results, matching the behavior of the frontend WebSocket flow
  • Falsy tool results (0, False, "") are preserved correctly via is not None check

Breaking Changes

  • None. Behavioral change is scoped to REST API requests with function_calling: native and tools - these previously returned raw tool_calls without execution.

Additional Information

  • Related discussion: #9435 ("The model does nothing with the result of a native tool call") - reported by 30+ users since Feb 2025
  • The server-side loop only activates when: no session_id (REST API), function_calling == 'native', and tools are present in metadata
  • Loop is bounded by existing CHAT_RESPONSE_MAX_TOOL_CALL_RETRIES setting
  • The loop forces stream=False to parse tool_calls from JSON. After the loop, the final LLM call is only made when:
    • Tool results are pending (LLM hasn't seen them), OR
    • The caller requested streaming (loop response is JSON, caller expects SSE)
    • Non-streaming callers reuse the loop's response directly - no extra LLM call

Contributor License Agreement

Note

Deleting the CLA section will lead to immediate closure of your PR and it will not be merged in.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/open-webui/open-webui/pull/23581 **Author:** [@PedroFCM](https://github.com/PedroFCM) **Created:** 4/10/2026 **Status:** ❌ Closed **Base:** `dev` ← **Head:** `fix/native-tool-calling-api-loop` --- ### 📝 Commits (1) - [`ec17516`](https://github.com/open-webui/open-webui/commit/ec175166c677bbad051cf4dc36c5be51541f92f4) fix: native function calling for REST API consumers ### 📊 Changes **1 file changed** (+70 additions, -7 deletions) <details> <summary>View changed files</summary> 📝 `backend/open_webui/main.py` (+70 -7) </details> ### 📄 Description <!-- ⚠️ CRITICAL CHECKS FOR CONTRIBUTORS (READ, DON'T DELETE) ⚠️ 1. Target the `dev` branch. PRs targeting `main` will be automatically closed. 2. Do NOT delete the CLA section at the bottom. It is required for the bot to accept your PR. --> Two fixes for native function calling, especially for REST API consumers that bypass the frontend WebSocket session: 1. **Pass through the `function_calling` value as-is** instead of only checking for `'native'` and falling back to `'default'`. This respects values set via `DEFAULT_MODEL_PARAMS` or per-model params. 2. **Add server-side tool-calling loop for API calls** (no `session_id`). The native tool execution loop is driven by the frontend via WebSocket. REST API calls never enter that loop, so `tool_calls` are returned raw and tools are never executed. This adds a loop that executes tools and re-invokes the LLM until `finish_reason != 'tool_calls'` or `CHAT_RESPONSE_MAX_TOOL_CALL_RETRIES` is reached. Ref: #9435 Replaces PR: #23515 (closed - updated based on bot review feedback) # Pull Request Checklist - [x] **Target branch:** `dev` - [x] **Description:** See above and changelog below - [x] **Changelog:** See below - [x] **Documentation:** N/A - no new env vars or user-facing config; uses existing `CHAT_RESPONSE_MAX_TOOL_CALL_RETRIES` - [x] **Dependencies:** No new dependencies - [x] **Testing:** Tested on a deployment environment (AWS ECS Fargate + Bedrock Access Gateway) with Claude models. Verified via REST API (`/api/chat/completions`) with both `stream: true` and `stream: false`. Tool calls are executed server-side and the LLM produces a final response incorporating tool results. Frontend WebSocket flow unaffected. - [x] **Agentic AI Code:** AI-assisted with human review and manual testing on deployment environment - [x] **Code review:** Self-reviewed; addressed both findings from automated review on #23515 - [x] **Design & Architecture:** No new settings; uses existing `CHAT_RESPONSE_MAX_TOOL_CALL_RETRIES` - [x] **Git Hygiene:** Single atomic commit rebased on `dev` - [x] **Title Prefix:** `fix:` # Changelog Entry ### Description - Fix native function calling for REST API consumers (`/api/chat/completions`) that don't use a WebSocket session ### Fixed - `function_calling` parameter now passes through the configured value instead of only recognizing `'native'` and falling back to `'default'` - REST API calls with native function calling now execute tools server-side and re-invoke the LLM with tool results, matching the behavior of the frontend WebSocket flow - Falsy tool results (`0`, `False`, `""`) are preserved correctly via `is not None` check ### Breaking Changes - None. Behavioral change is scoped to REST API requests with `function_calling: native` and tools - these previously returned raw `tool_calls` without execution. --- ### Additional Information - Related discussion: #9435 ("The model does nothing with the result of a native tool call") - reported by 30+ users since Feb 2025 - The server-side loop only activates when: no `session_id` (REST API), `function_calling == 'native'`, and tools are present in metadata - Loop is bounded by existing `CHAT_RESPONSE_MAX_TOOL_CALL_RETRIES` setting - The loop forces `stream=False` to parse tool_calls from JSON. After the loop, the final LLM call is only made when: - Tool results are pending (LLM hasn't seen them), OR - The caller requested streaming (loop response is JSON, caller expects SSE) - Non-streaming callers reuse the loop's response directly - no extra LLM call ### Contributor License Agreement <!-- 🚨 DO NOT DELETE THE TEXT BELOW 🚨 Keep the "Contributor License Agreement" confirmation text intact. Deleting it will trigger the CLA-Bot to INVALIDATE your PR. Your PR will NOT be reviewed or merged until you check the box below confirming that you have read and agree to the terms of the CLA. --> - [x] By submitting this pull request, I confirm that I have read and fully agree to the [Contributor License Agreement (CLA)](https://github.com/open-webui/open-webui/blob/main/CONTRIBUTOR_LICENSE_AGREEMENT), and I am providing my contributions under its terms. > [!NOTE] > Deleting the CLA section will lead to immediate closure of your PR and it will not be merged in. --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-05-06 12:16:16 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/open-webui#66120