[PR #22189] [CLOSED] fix: initialize streaming tool call arguments to '{}' instead of empty string #65397

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

📋 Pull Request Information

Original PR: https://github.com/open-webui/open-webui/pull/22189
Author: @Jseals38
Created: 3/3/2026
Status: Closed

Base: devHead: fix/empty-tool-call-arguments


📝 Commits (1)

  • 2004dd9 fix: initialize streaming tool call arguments to '{}' instead of empty string

📊 Changes

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

View changed files

📝 backend/open_webui/utils/middleware.py (+1 -1)

📄 Description

Pull Request Checklist

  • Target branch: Verify that the pull request targets the dev branch.
  • Description: Provided below.
  • Changelog: Included below.
  • Documentation: N/A — no user-facing behavior, env vars, or API changes.
  • Dependencies: N/A — no new or upgraded dependencies.
  • Testing: Manually tested with parameterless GET endpoint tools in streaming mode. Confirmed the error no longer occurs on first attempt.
  • Agentic AI Code: This PR was written and tested by a human.
  • Code review: Self-reviewed — one-line change.
  • Design & Architecture: Minimal fix, no new settings or architecture changes.
  • Git Hygiene: Single atomic commit, single file changed.
  • Title Prefix: fix:

Changelog Entry

Description

  • Parameterless tool calls fail during streaming because setdefault("arguments", "") seeds the arguments field with an empty string. Both ast.literal_eval("") and json.loads("") fail, producing "Tool call arguments could not be parsed" errors. Changing the seed to "{}" makes both parsers succeed, returning an empty dict {}.

Added

  • N/A

Changed

  • N/A

Deprecated

  • N/A

Removed

  • N/A

Fixed

  • Fixed streaming tool call argument initialization in middleware.py: changed setdefault("arguments", "") to setdefault("arguments", "{}") so parameterless tool calls parse correctly on the first attempt instead of failing and requiring a model retry.

Security

  • N/A

Breaking Changes

  • N/A

Additional Information

Root cause: During streaming, when a new tool call is encountered, the arguments field is initialized via setdefault("arguments", ""). For parameterless tools where the model never sends argument content, this empty string becomes the final value. The downstream parser at tool_call.get("function", {}).get("arguments", "{}") retrieves it (the .get default of "{}" only applies when the key is missing, but the key is present with value ""), then both ast.literal_eval("") and json.loads("") raise exceptions.

Scope & safety: setdefault only applies when the "arguments" key is absent from the first streaming chunk. When a model includes "arguments": "" explicitly (the standard behavior for tools that have parameters), setdefault does not fire and behavior is completely unchanged.

Edge case considered: If a model omitted the arguments key in the first chunk but then streamed argument content in subsequent chunks, the seeded "{}" would prepend to the streamed JSON. However, in OpenAI-compatible streaming the first tool call chunk virtually always includes "arguments": "" explicitly, so setdefault never activates in that path. This pattern is not observed in practice across OpenAI, Azure OpenAI, or other compatible providers.

Screenshots or Videos

Before fix — parameterless tool call fails on first attempt:

Error: Tool call arguments could not be parsed. The model generated malformed or incomplete JSON for tool_call. Please try again.

Model retries with explicit {} or {"key": {}}, wasting a round-trip.

After fix — parameterless tool call succeeds on first attempt with no retry needed.

Contributor License Agreement

By submitting this pull request, I confirm that I have read and fully agree to the Contributor License Agreement (CLA), and I am providing my contributions under its terms.


🔄 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/22189 **Author:** [@Jseals38](https://github.com/Jseals38) **Created:** 3/3/2026 **Status:** ❌ Closed **Base:** `dev` ← **Head:** `fix/empty-tool-call-arguments` --- ### 📝 Commits (1) - [`2004dd9`](https://github.com/open-webui/open-webui/commit/2004dd91b817f3d361a3c7c6b342cecbd50ef906) fix: initialize streaming tool call arguments to '{}' instead of empty string ### 📊 Changes **1 file changed** (+1 additions, -1 deletions) <details> <summary>View changed files</summary> 📝 `backend/open_webui/utils/middleware.py` (+1 -1) </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. --> # Pull Request Checklist - [x] **Target branch:** Verify that the pull request targets the `dev` branch. - [x] **Description:** Provided below. - [x] **Changelog:** Included below. - [ ] **Documentation:** N/A — no user-facing behavior, env vars, or API changes. - [ ] **Dependencies:** N/A — no new or upgraded dependencies. - [x] **Testing:** Manually tested with parameterless GET endpoint tools in streaming mode. Confirmed the error no longer occurs on first attempt. - [x] **Agentic AI Code:** This PR was written and tested by a human. - [x] **Code review:** Self-reviewed — one-line change. - [x] **Design & Architecture:** Minimal fix, no new settings or architecture changes. - [x] **Git Hygiene:** Single atomic commit, single file changed. - [x] **Title Prefix:** `fix:` # Changelog Entry ### Description - Parameterless tool calls fail during streaming because `setdefault("arguments", "")` seeds the arguments field with an empty string. Both `ast.literal_eval("")` and `json.loads("")` fail, producing "Tool call arguments could not be parsed" errors. Changing the seed to `"{}"` makes both parsers succeed, returning an empty dict `{}`. ### Added - N/A ### Changed - N/A ### Deprecated - N/A ### Removed - N/A ### Fixed - Fixed streaming tool call argument initialization in `middleware.py`: changed `setdefault("arguments", "")` to `setdefault("arguments", "{}")` so parameterless tool calls parse correctly on the first attempt instead of failing and requiring a model retry. ### Security - N/A ### Breaking Changes - N/A --- ### Additional Information **Root cause:** During streaming, when a new tool call is encountered, the arguments field is initialized via `setdefault("arguments", "")`. For parameterless tools where the model never sends argument content, this empty string becomes the final value. The downstream parser at `tool_call.get("function", {}).get("arguments", "{}")` retrieves it (the `.get` default of `"{}"` only applies when the key is *missing*, but the key *is* present with value `""`), then both `ast.literal_eval("")` and `json.loads("")` raise exceptions. **Scope & safety:** `setdefault` only applies when the `"arguments"` key is absent from the first streaming chunk. When a model includes `"arguments": ""` explicitly (the standard behavior for tools that have parameters), `setdefault` does not fire and behavior is completely unchanged. **Edge case considered:** If a model omitted the arguments key in the first chunk but then streamed argument content in subsequent chunks, the seeded `"{}"` would prepend to the streamed JSON. However, in OpenAI-compatible streaming the first tool call chunk virtually always includes `"arguments": ""` explicitly, so `setdefault` never activates in that path. This pattern is not observed in practice across OpenAI, Azure OpenAI, or other compatible providers. - Related: #13125, #14886, #15346, #14577 ### Screenshots or Videos **Before fix** — parameterless tool call fails on first attempt: Error: Tool call arguments could not be parsed. The model generated malformed or incomplete JSON for tool_call. Please try again. Model retries with explicit `{}` or `{"key": {}}`, wasting a round-trip. **After fix** — parameterless tool call succeeds on first attempt with no retry needed. ### Contributor License Agreement 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. --- <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 11:12:23 -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#65397