Skip to content

fix(ai-proxy): drop tool_choice without tools and stop hanging Anthropic stream#13583

Open
AlinsRan wants to merge 1 commit into
apache:masterfrom
AlinsRan:fix/anthropic-converter-tool-choice-stream
Open

fix(ai-proxy): drop tool_choice without tools and stop hanging Anthropic stream#13583
AlinsRan wants to merge 1 commit into
apache:masterfrom
AlinsRan:fix/anthropic-converter-tool-choice-stream

Conversation

@AlinsRan

Copy link
Copy Markdown
Contributor

Description

Two bugs in the Anthropic-to-OpenAI converter (apisix/plugins/ai-protocols/converters/anthropic-messages-to-openai-chat.lua):

  1. tool_choice forwarded without tools → upstream 400. tool_choice (and parallel_tool_calls) were sent to the OpenAI-compatible upstream even when no tools ended up in the request — either the client provided none, or all were dropped as Anthropic built-ins (e.g. web_search) / invalid. OpenAI-compatible upstreams reject tool_choice without tools. They are now dropped when the tools array is empty.

  2. Streaming client hang. When a stream emitted message_start but the upstream sent [DONE] before any content block opened and without a finish_reason chunk, convert_sse_events returned nil and never emitted message_stop, leaving the client hanging until timeout. message_delta + message_stop are now emitted whenever the message was already started.

Tests

Added two unit tests to t/plugin/ai-proxy-anthropic.t:

  • tool_choice/parallel_tool_calls dropped when no tools are forwarded (no-tools and all-built-in cases); preserved when a real tool remains.
  • [DONE] after message_start without a content block still emits message_stop.

Checklist

  • I have explained the need for this PR and the problem it solves
  • I have explained the changes or the new features added to this PR
  • I have added tests corresponding to this change
  • I have updated the documentation to reflect this change (N/A — bugfix, no config/behavior doc change)
  • I have verified that this change is backward compatible

…pic stream

The Anthropic-to-OpenAI converter had two bugs:

- tool_choice (and parallel_tool_calls) were forwarded even when no tools
  reached the upstream -- either none were provided or all were dropped as
  Anthropic built-ins / invalid -- which makes OpenAI-compatible upstreams
  reject the request. Drop them when the tools array ends up empty.

- On a streaming [DONE] that arrives after message_start but before any
  content block was opened (no finish_reason chunk), convert_sse_events
  returned nil without emitting message_stop, leaving the client hanging.
  Emit message_delta + message_stop whenever the message was already started.

Add unit tests for both cases in t/plugin/ai-proxy-anthropic.t.

Signed-off-by: AlinsRan <alinsran@apache.org>
@dosubot dosubot Bot added size:L This PR changes 100-499 lines, ignoring generated files. bug Something isn't working labels Jun 22, 2026

@membphis membphis left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Approved. No blocking issues found.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants