14 Commits

Author SHA1 Message Date
JIA-ss
20f5340784 fix(apicompat): Responses→Chat 转换补齐 completion_tokens_details 透传
OpenAI Responses API 在 gpt-5.x 等 reasoning 模型上会返回
output_tokens_details.reasoning_tokens, 但 ResponsesToChatCompletions
只映射了 input_tokens_details.cached_tokens, 导致客户端拿到的
chat.completion.usage 中 completion_tokens 出现无法解释的波动
(短 prompt 也可能 30+ token), 且缺失 reasoning_tokens 细分字段,
难以与 OpenAI 原生 Chat Completions 响应对账。

按 OpenAI 官方 CompletionUsage schema (openai/openai-go SDK
completion.go) 补齐所有 token-details 字段, 全部 omitempty:

  prompt_tokens_details:
    - cached_tokens   (原已支持)
    - audio_tokens    (新增)
  completion_tokens_details:
    - reasoning_tokens             (新增)
    - audio_tokens                 (新增)
    - accepted_prediction_tokens   (新增)
    - rejected_prediction_tokens   (新增)

实现细节:
- 抽出 promptDetailsFromResponses / completionDetailsFromResponses
  两个 helper, 全零字段返回 nil
- 非流路径 ResponsesToChatCompletions 复用已存在的
  chatUsageFromResponsesUsage helper, 消除两条路径间的重复
- 非 reasoning / 非 audio 上游 (Anthropic, Gemini, gpt-4o) 不填这些
  字段, helper 返回 nil → CompletionTokensDetails 不输出, 对现有响应
  字节级兼容

新增单测:
- TestResponsesToChatCompletions_ReasoningTokens
- TestResponsesToChatCompletions_AllTokenDetailsPassThrough
- TestResponsesToChatCompletions_NoReasoningTokensWhenZero
- TestResponsesEventToChatChunks_CompletedWithReasoningTokens
2026-05-28 00:38:25 +08:00
shaw
f7ac5e5931 fix(openai): preserve chat responses usage billing 2026-05-26 21:33:28 +08:00
wucm667
276b5c7755 fix(apicompat): strip temperature/top_p for reasoning models in Responses conversion
gpt-5.x models served via the OpenAI Responses API reject requests that
include temperature or top_p with:
  {"detail":"Unsupported parameter: temperature"}

This caused ClaudeCode agent/subagent tool requests to fail with a 400
error when an OpenAI group had the Messages-format support enabled.

Root cause: AnthropicToResponses and ChatCompletionsToResponses were
unconditionally forwarding temperature and top_p from the incoming
request to the ResponsesRequest, even though all gpt-5.x reasoning
models reject these sampling parameters.

Fix:
- Add isReasoningModel(model string) bool helper that returns true for
  any model whose name starts with "gpt-5".
- Skip temperature and top_p when converting to ResponsesRequest for
  reasoning models. Non-reasoning models (e.g. gpt-4o) are unaffected.
- ResponsesRequest.Temperature and TopP are already *float64 with
  omitempty, so nil values are safely omitted from the JSON body.

Tests:
- TestAnthropicToResponses_TemperatureStrippedForReasoningModel
- TestAnthropicToResponses_TemperatureStrippedForAllGpt5Variants
- TestChatCompletionsToResponses_TemperatureStrippedForReasoningModel
- TestChatCompletionsToResponses_TemperaturePreservedForNonReasoningModel

Fixes #2487
2026-05-19 20:03:16 +08:00
L494264Tt
6082d02d22 Merge origin/main into fix/deepseek-reasoning-content 2026-05-19 17:00:57 +08:00
L494264Tt
1d47fd6300 This preserves DeepSeek reasoning_content across chat compatibility paths.
DeepSeek thinking-mode tool-call conversations may require the assistant
  reasoning_content from previous turns to be sent back in later requests. Without
  preserving it, those conversations can fail or lose reasoning context.

  Changes:
  - Preserve assistant reasoning_content when converting Chat Completions messages
    to Responses input by wrapping it as a thinking block.
  - Add regression coverage for non-streaming DeepSeek responses.
  - Add regression coverage for streaming DeepSeek deltas.
  - Add regression coverage that request-side messages[].reasoning_content is
    passed through with tool calls.

  Tests:
  go test -tags=unit ./internal/pkg/apicompat ./internal/service -run
  'TestChatCompletionsToResponses_AssistantReasoningContentPreserved|
  TestChatCompletionsToResponses_AssistantThinkingTagPreserved|
  TestForwardAsRawChatCompletions_PreservesDeepSeekReasoningContent|
  TestForwardAsRawChatCompletions_ForcesStreamUsageUpstreamAndPassesUsageDownstream
2026-05-18 11:22:23 +08:00
wucm667
df82a3bc69 fix(openai): avoid null content when converting chat-completions to responses
When a chat-completions message has no usable content parts (empty array,
empty text part, or filtered-out image part), marshalChatInputContent
marshalled a nil slice to JSON null. The upstream Responses API rejects a
null content field with HTTP 400. Fall back to an empty string instead.

Fixes #2515
2026-05-17 11:20:05 +08:00
shaw
72d5ee4cd1 fix: drain OpenAI compat streams for usage 2026-05-03 17:11:27 +08:00
ivanvolt
04b2866f65 fix: use Responses-compatible function tool_choice format 2026-04-28 16:26:09 +08:00
Wesley Liddick
5088e91566
Merge pull request #1417 from YanzheL/fix/openai-empty-base64-image-payloads
fix: sanitize empty base64 image payloads for OpenAI requests
2026-04-08 14:20:38 +08:00
shaw
b2e379cf7a fix: 非流式路径在上游终态事件output为空时从delta事件重建响应内容
上游API近期更新后,response.completed终态SSE事件的output字段可能为空,
实际内容仅通过response.output_text.delta等增量事件下发。流式路径不受影响,
但chat_completions非流式路径和responses OAuth非流式路径只依赖终态事件的
output,导致返回空响应。

新增BufferedResponseAccumulator累积器,在SSE扫描过程中收集delta事件内容
(文本、function_call、reasoning),当终态output为空时补充重建。

同时修复handleChatBufferedStreamingResponse遗漏response.done事件类型的问题。
2026-04-07 19:35:56 +08:00
YanzheL
936fce68d0
fix(apicompat): skip empty base64 image URLs 2026-04-01 00:46:16 +08:00
mutuyihao
4feacf2213 fix(apicompat): support array content for system and tool messages 2026-03-21 15:34:28 +08:00
Ethan0x0000
ece0606fed fix: consolidate chat-completions compatibility fixes
- apply default mapped model only when scheduling fallback is actually used

- preserve reasoning in OpenAI-compatible output via reasoning_content and avoid invalid input function_call ids
2026-03-14 12:12:08 +08:00
shaw
9d81467937 refactor: 重构 Chat Completions 端点,采用类型安全的 Responses API 转换
将 /v1/chat/completions 端点从 ResponseWriter 劫持模式重构为独立的
类型安全转换路径,与 Anthropic Messages 端点架构对齐:

- 在 apicompat 包新增 Chat Completions 完整类型定义和双向转换器
- 新增 ForwardAsChatCompletions service 方法,走 Responses API 上游
- Handler 改为独立的账号选择/failover 循环,不再劫持 Responses handler
- 提取 handleCompatErrorResponse 为 Chat Completions 和 Messages 共用
- 删除旧的 forwardChatCompletions 直传路径及相关死代码
2026-03-11 22:15:32 +08:00