Skip to content

fix(openai): skip unsupported Responses tools#1644

Closed
rosetta-livekit-bot[bot] wants to merge 1 commit into
mainfrom
ruled-ellipses-bars
Closed

fix(openai): skip unsupported Responses tools#1644
rosetta-livekit-bot[bot] wants to merge 1 commit into
mainfrom
ruled-ellipses-bars

Conversation

@rosetta-livekit-bot

@rosetta-livekit-bot rosetta-livekit-bot Bot commented May 29, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes a regression that's been red on `main` CI since #5865 + #5884 landed back-to-back.

#5865 added a required keyword-only `provider_tool_type` to `to_responses_fnc_ctx`, but `ToolContext.parse_function_tools` forwards `**kwargs` blindly:

elif format == "openai.responses":
    return _provider_format.openai.to_responses_fnc_ctx(self, **kwargs)

So any caller that goes through `parse_function_tools("openai.responses")` without explicitly threading `provider_tool_type` hits a `TypeError`. #5884 landed exactly such a caller (the new `test_serialized_tool_order_is_sorted`):

for fmt in ("openai", "openai.responses", "anthropic", "aws", "google"):
    names = [tool_name(fmt, s) for s in ctx.parse_function_tools(fmt)]

Result: `tests/test_tools.py::TestToolContext::test_serialized_tool_order_is_sorted` fails on every CI run (e.g. run on `6d50c5da`).

Fix

Make `provider_tool_type` optional (`type[ProviderTool] | None = None`) and gate the provider-tool `isinstance` branch on its presence. Behavior is unchanged for legitimate callers — the openai.responses plugin always passes `provider_tool_type=self._llm._provider_tool_type`; the `None` path just emits function-tool schemas, which is the right thing for generic serialization where no provider-tool subtype is in scope.

Also widens the matching `@overload` signature in `tool_context.py` so static callers see the same default.

Test plan

  • `uv run pytest tests/test_tools.py` → 49 passed (was 1 failed on main)
  • `uv run ruff check` / `ruff format --check` → clean
  • `uv run mypy -p livekit.agents.llm` → clean

Made with Cursor

@changeset-bot

changeset-bot Bot commented May 29, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: b13c72d

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 33 packages
Name Type
@livekit/agents-plugin-openai Patch
@livekit/agents-plugin-anam Patch
@livekit/agents-plugin-cartesia Patch
@livekit/agents-plugin-cerebras Patch
@livekit/agents-plugin-elevenlabs Patch
@livekit/agents-plugin-fishaudio Patch
@livekit/agents-plugin-google Patch
@livekit/agents-plugin-hume Patch
@livekit/agents-plugin-inworld Patch
@livekit/agents-plugin-neuphonic Patch
@livekit/agents-plugin-perplexity Patch
@livekit/agents-plugin-rime Patch
@livekit/agents-plugin-sarvam Patch
@livekit/agents-plugin-xai Patch
@livekit/agents Patch
@livekit/agents-plugin-assemblyai Patch
@livekit/agents-plugin-baseten Patch
@livekit/agents-plugin-bey Patch
@livekit/agents-plugin-deepgram Patch
@livekit/agents-plugin-hedra Patch
@livekit/agents-plugin-lemonslice Patch
@livekit/agents-plugin-liveavatar Patch
@livekit/agents-plugin-livekit Patch
@livekit/agents-plugin-minimax Patch
@livekit/agents-plugin-mistral Patch
@livekit/agents-plugin-mistralai Patch
@livekit/agents-plugin-phonic Patch
@livekit/agents-plugin-resemble Patch
@livekit/agents-plugin-runway Patch
@livekit/agents-plugin-silero Patch
@livekit/agents-plugin-tavus Patch
@livekit/agents-plugin-trugen Patch
@livekit/agents-plugins-test Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@devin-ai-integration devin-ai-integration Bot 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.

Devin Review found 2 potential issues.

View 3 additional findings in Devin Review.

Open in Devin Review

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.

🔴 Empty tools array after filtering bypasses !tools guard, sending tool_choice with no tools

When toolCtx is non-empty but all entries are provider-defined (non-function) tools, the new .filter(([, func]) => llm.isFunctionTool(func)) produces an empty array []. Since ![] is false in JavaScript, the guard at line 208 (if (!tools)) doesn't trigger, so tool_choice is not deleted from requestOptions. The API request is then sent with tools: [] and a tool_choice value (e.g., 'required' or a specific function name), which will cause an OpenAI API error. The same issue also affects parallel_tool_calls which is added to modelOptions at plugins/openai/src/responses/llm.ts:98-100 based on the unfiltered toolCtx.

(Refers to lines 208-210)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

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.

🔴 Empty tools array after filtering bypasses !tools guard in WebSocket path

Same issue as in the HTTP path: when toolCtx contains only provider-defined tools, the filter produces tools = []. The guard at line 473 (if (!tools)) doesn't catch empty arrays, so tool_choice remains in requestOptions and is sent alongside an empty tools list at line 481. This will cause an OpenAI API error when tool_choice is set to 'required' or references a specific function. The parallel_tool_calls option is also affected at plugins/openai/src/ws/llm.ts:273-275.

(Refers to lines 473-475)

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

@u9g u9g closed this Jun 8, 2026
@u9g u9g deleted the ruled-ellipses-bars branch June 8, 2026 10:02
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