Keep the upstream payload prefixed for OAuth while passing the unprefixed request body into response translators. This avoids proxy_ leaking into OpenAI Responses echoed tool metadata while preserving the Claude OAuth workaround.
Prefix tool names with proxy_ for Claude OAuth requests and strip the prefix from streaming and non-streaming responses to restore client-facing names.
Updates the Claude executor to:
- add prefixing for tools, tool_choice, and tool_use messages when using OAuth tokens
- strip the prefix from tool_use events in SSE and non-streaming payloads
- add focused unit tests for prefix/strip helpers
Update the model name check in `buildRequest` to target "gemini-3-pro-preview" instead of "gemini-3-pro" when applying specific system instruction handling.
When streaming responses with tool calls, the finish_reason was being
overwritten. The upstream sends functionCall in chunk 1, then
finishReason: STOP in chunk 2. The old code would set finish_reason
from every chunk, causing "tool_calls" to be overwritten by "stop".
This broke clients like Claude Code that rely on finish_reason to
detect when tool calls are complete.
Changes:
- Add SawToolCall bool to track tool calls across entire stream
- Add UpstreamFinishReason to cache the finish reason
- Only emit finish_reason on final chunk (has both finishReason + usage)
- Priority: tool_calls > max_tokens > stop
Includes 5 unit tests covering:
- Tool calls not overwritten by subsequent STOP
- Normal text gets "stop"
- MAX_TOKENS without tool calls gets "max_tokens"
- Tool calls take priority over MAX_TOKENS
- Intermediate chunks have no finish_reason
Fixes streaming tool call detection for Claude Code + Gemini models.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>