Skip to content

Bug: AnthropicToOpenAIResponsesStreamAdapter async generator hangs intermittently, never terminates #73

Description

@qcnhy

Problem

The AnthropicToOpenAIResponsesStreamAdapter.run() async generator intermittently never terminates after processing all input events, causing the consuming async for loop to hang indefinitely.

When the input async generator (src()) returns (after yielding all events + None sentinel), the adapter's run() method sometimes does not exhaust — it hangs at some internal await point, never yielding a final sentinel. This leaves the consumer blocked forever.

Reproduction

from ccproxy.llms.formatters.anthropic_to_openai.streams import AnthropicToOpenAIResponsesStreamAdapter
import asyncio

async def src():
    # Yield some Anthropic events then return
    yield {"type": "message_start", "_event_type": "message_start", "message": {...}}
    yield {"type": "message_stop", "_event_type": "message_stop"}
    # return (src exhausted)

async def test():
    converter = AnthropicToOpenAIResponsesStreamAdapter()
    async for out in converter.run(src()):
        print(out)
    # ↑ This line sometimes NEVER reached — the async for hangs forever
    print("done")  # ← this is the problem

asyncio.run(test())

Impact

This forces proxy scripts to:

  1. Implement a timeout on the drain loop (we use 8s × 2)
  2. Abandon the converter when it stalls
  3. Rewrite the entire Anthropic→Responses streaming translation by hand (~460 lines of synchronous code) to avoid the async bridge entirely

The hand-written sync translator (_converted_stream_sync) is currently the largest single block of workaround code in our proxy (460 lines).

Environment

  • ccproxy-api 0.2.10
  • Python 3.12 / 3.14
  • Used with GLM-5.2 Anthropic Messages API

Suggested fix

  1. Ensure run() always terminates when the input generator is exhausted
  2. Add a timeout/cancellation mechanism
  3. Or provide a synchronous API as an alternative

Activity

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions