Skip to content

fix: change SSE keepalive from event to comment format#1707

Open
danielzhou82 wants to merge 1 commit intoWei-Shaw:mainfrom
danielzhou82:fix/streaming-keepalive-format
Open

fix: change SSE keepalive from event to comment format#1707
danielzhou82 wants to merge 1 commit intoWei-Shaw:mainfrom
danielzhou82:fix/streaming-keepalive-format

Conversation

@danielzhou82
Copy link
Copy Markdown

Summary

  • Change SSE keepalive ping from event: ping\ndata: {"type": "ping"}\n\n (SSE event) to : keepalive\n\n (SSE comment) across all streaming handlers
  • SSE comments keep the HTTP connection alive (preventing proxy idle timeouts) but are not yielded by the Anthropic SDK to consumers, so client-side idle watchdogs (e.g. Claude Code's 90s timeout) continue counting down correctly
  • This fixes a bug where Claude Code hangs indefinitely during extended thinking: the upstream connection dies silently, sub2api's keepalive pings reset the client watchdog, and the client never retries

Problem

When using Claude Code through sub2api with extended thinking enabled, the client occasionally hangs (time keeps ticking but no tokens arrive). Root cause:

  1. Upstream connection (sub2api → Anthropic) dies during long thinking pauses
  2. sub2api's bufio.Scanner.Scan() blocks forever (Go's http.Transport has no read timeout on response body)
  3. sub2api sends keepalive pings as SSE events → Anthropic SDK yields them → Claude Code's idle watchdog resets
  4. Result: client never detects the stall, hangs indefinitely

Fix

Replace SSE event pings with SSE comments in all 4 streaming paths:

  • gateway_service.go — main Claude streaming handler
  • antigravity_gateway_service.go — two Antigravity streaming handlers
  • openai_gateway_messages.go — OpenAI-compat Anthropic streaming handler
  • gateway_helper.goSSEPingFormatClaude constant

SSE comments (:<space>text\n\n) are valid SSE frames that keep HTTP connections alive but are silently discarded by spec-compliant SSE parsers, including the Anthropic SDK.

Test plan

  • Verify streaming responses work normally (no regression in keepalive behavior)
  • Test extended thinking scenario through a proxy with idle timeout < keepalive interval
  • Confirm Claude Code's watchdog triggers correctly when upstream connection dies

🤖 Generated with Claude Code

@danielzhou82 danielzhou82 force-pushed the fix/streaming-keepalive-format branch from e20602e to 3eeeb85 Compare April 16, 2026 14:45
…ent watchdog

Change keepalive ping from SSE event (`event: ping\ndata: ...`) to SSE
comment (`: keepalive\n\n`) across all streaming handlers. SSE comments
keep HTTP connections alive but are not yielded by the Anthropic SDK,
so client-side idle watchdogs (e.g. Claude Code's 90s timeout) continue
counting down correctly when the upstream connection dies silently.
@danielzhou82 danielzhou82 force-pushed the fix/streaming-keepalive-format branch from 3eeeb85 to f24c270 Compare April 16, 2026 14:47
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