Skip to content

fix: do not mutate Tool schemas (and handle empty tools) in OpenAIResponsesChatGenerator - #12067

Merged
sjrl merged 3 commits into
deepset-ai:mainfrom
TimurRakhmatullin86:fix/openai-responses-tool-handling
Jul 21, 2026
Merged

fix: do not mutate Tool schemas (and handle empty tools) in OpenAIResponsesChatGenerator#12067
sjrl merged 3 commits into
deepset-ai:mainfrom
TimurRakhmatullin86:fix/openai-responses-tool-handling

Conversation

@TimurRakhmatullin86

Copy link
Copy Markdown
Contributor

Related Issues

None — two self-contained bugs found in OpenAIResponsesChatGenerator tool handling.

Proposed Changes

1. Do not mutate the user's Tool schema in place.
In _prepare_api_call, tool definitions were built like:

function_spec = {**t.tool_spec}
function_spec["parameters"]["additionalProperties"] = False

Tool.tool_spec returns {"name": ..., "description": ..., "parameters": self.parameters}parameters by reference — and {**t.tool_spec} only shallow-copies the outer dict. So additionalProperties: False was written permanently into the caller's live Tool.parameters. Consequences: the same Tool passed to another generator (e.g. OpenAIChatGenerator with tools_strict=False, which intentionally leaves schemas open) is contaminated, and tool.to_dict() / a serialize→load→serialize round trip is no longer stable. Fixed by building the definition on a copied parameters dict: {**function_spec["parameters"], "additionalProperties": False}.

2. Guard _warm_up_tools against an empty tools list.
is_openai_tool = isinstance(self.tools, list) and isinstance(self.tools[0], dict) raised IndexError for tools=[] (an ordinary value when tools are built programmatically). Every sibling check already guards emptiness; this one now does too via bool(self.tools).

How did you test it?

Unit tests in test/components/generators/chat/test_openai_responses.py:

  • test_prepare_api_call_does_not_mutate_tool_parameters — asserts the original Tool.parameters is untouched while the API payload still carries additionalProperties=False.
  • test_warm_up_with_empty_tools_list_does_not_raise — warms up with tools=[] without error.

Both fail against the current code (AssertionError / IndexError respectively) and pass with the fix. Full test_openai_responses.py unit suite passes; ruff check/ruff format --check clean.

Checklist

_prepare_api_call wrote additionalProperties into the Tool.parameters dict
that Tool.tool_spec exposes by reference, permanently altering the user's
Tool (and any other generator sharing it) and making serialization round
trips unstable. Build the tool definition on a copied parameters dict
instead.

Also guard _warm_up_tools against an empty tools list, which previously
raised IndexError on the unguarded self.tools[0] access.
@TimurRakhmatullin86
TimurRakhmatullin86 requested a review from a team as a code owner July 19, 2026 20:17
@TimurRakhmatullin86
TimurRakhmatullin86 requested review from sjrl and removed request for a team July 19, 2026 20:17
@vercel

vercel Bot commented Jul 19, 2026

Copy link
Copy Markdown

@TimurRakhmatullin86 is attempting to deploy a commit to the deepset Team on Vercel.

A member of the Team first needs to authorize it.

@CLAassistant

CLAassistant commented Jul 19, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@HaystackBot

Copy link
Copy Markdown
Contributor

Hi @TimurRakhmatullin86, thanks a lot for your contribution! 🙏

We noticed that the Contributor License Agreement (CLA) check (license/cla) hasn't passed yet, so we've temporarily moved this PR to draft and paused the review assignment.

To get your PR reviewed, please sign the CLA via the link in the license/cla check below (or in the CLA bot comment). As soon as the check turns green, this PR will automatically be marked ready for review again and a reviewer will be re-assigned.

@HaystackBot
HaystackBot removed the request for review from sjrl July 19, 2026 21:36
@HaystackBot HaystackBot added the cla-pending PR is in draft until the contributor signs the CLA label Jul 19, 2026
@HaystackBot
HaystackBot marked this pull request as draft July 19, 2026 21:36
@HaystackBot
HaystackBot marked this pull request as ready for review July 20, 2026 21:18
@HaystackBot
HaystackBot requested a review from sjrl July 20, 2026 21:18
@HaystackBot

Copy link
Copy Markdown
Contributor

Thanks for signing the CLA, @TimurRakhmatullin86! 🎉 This PR is now ready for review again and the reviewer has been re-assigned.

@HaystackBot HaystackBot removed the cla-pending PR is in draft until the contributor signs the CLA label Jul 20, 2026
@sjrl sjrl self-assigned this Jul 21, 2026
Comment thread haystack/components/generators/chat/openai_responses.py Outdated
@github-actions github-actions Bot added the type:documentation Improvements on the docs label Jul 21, 2026
@github-actions

github-actions Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Coverage report

Click to see where and how coverage changed

FileStatementsMissingCoverageCoverage
(new stmts)
Lines missing
  haystack/components/generators/chat
  openai_responses.py
Project Total  

This report was generated by python-coverage-comment-action

@sjrl sjrl left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@sjrl
sjrl merged commit d71f9ab into deepset-ai:main Jul 21, 2026
22 of 23 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

topic:tests type:documentation Improvements on the docs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants