diff --git a/internal/runtime/executor/usage_helpers.go b/internal/runtime/executor/usage_helpers.go index 7d8d345e..3aa1e7ff 100644 --- a/internal/runtime/executor/usage_helpers.go +++ b/internal/runtime/executor/usage_helpers.go @@ -236,11 +236,7 @@ func parseOpenAIStreamUsage(line []byte) (usage.Detail, bool) { return detail, true } -func parseOpenAIResponsesUsage(data []byte) usage.Detail { - usageNode := gjson.ParseBytes(data).Get("usage") - if !usageNode.Exists() { - return usage.Detail{} - } +func parseOpenAIResponsesUsageDetail(usageNode gjson.Result) usage.Detail { detail := usage.Detail{ InputTokens: usageNode.Get("input_tokens").Int(), OutputTokens: usageNode.Get("output_tokens").Int(), @@ -258,6 +254,14 @@ func parseOpenAIResponsesUsage(data []byte) usage.Detail { return detail } +func parseOpenAIResponsesUsage(data []byte) usage.Detail { + usageNode := gjson.ParseBytes(data).Get("usage") + if !usageNode.Exists() { + return usage.Detail{} + } + return parseOpenAIResponsesUsageDetail(usageNode) +} + func parseOpenAIResponsesStreamUsage(line []byte) (usage.Detail, bool) { payload := jsonPayload(line) if len(payload) == 0 || !gjson.ValidBytes(payload) { @@ -267,21 +271,7 @@ func parseOpenAIResponsesStreamUsage(line []byte) (usage.Detail, bool) { if !usageNode.Exists() { return usage.Detail{}, false } - detail := usage.Detail{ - InputTokens: usageNode.Get("input_tokens").Int(), - OutputTokens: usageNode.Get("output_tokens").Int(), - TotalTokens: usageNode.Get("total_tokens").Int(), - } - if detail.TotalTokens == 0 { - detail.TotalTokens = detail.InputTokens + detail.OutputTokens - } - if cached := usageNode.Get("input_tokens_details.cached_tokens"); cached.Exists() { - detail.CachedTokens = cached.Int() - } - if reasoning := usageNode.Get("output_tokens_details.reasoning_tokens"); reasoning.Exists() { - detail.ReasoningTokens = reasoning.Int() - } - return detail, true + return parseOpenAIResponsesUsageDetail(usageNode), true } func parseClaudeUsage(data []byte) usage.Detail { diff --git a/sdk/api/handlers/openai/openai_handlers.go b/sdk/api/handlers/openai/openai_handlers.go index c8aaba78..f1dd5a07 100644 --- a/sdk/api/handlers/openai/openai_handlers.go +++ b/sdk/api/handlers/openai/openai_handlers.go @@ -536,7 +536,12 @@ func (h *OpenAIAPIHandler) handleNonStreamingResponseViaResponses(c *gin.Context } converted := convertResponsesObjectToChatCompletion(cliCtx, modelName, originalChatJSON, rawJSON, resp) if converted == nil { - converted = resp + h.WriteErrorResponse(c, &interfaces.ErrorMessage{ + StatusCode: http.StatusInternalServerError, + Error: fmt.Errorf("failed to convert response to chat completion format"), + }) + cliCancel(fmt.Errorf("response conversion failed")) + return } _, _ = c.Writer.Write(converted) cliCancel() diff --git a/sdk/api/handlers/openai/openai_responses_handlers.go b/sdk/api/handlers/openai/openai_responses_handlers.go index e6c29001..952e44e0 100644 --- a/sdk/api/handlers/openai/openai_responses_handlers.go +++ b/sdk/api/handlers/openai/openai_responses_handlers.go @@ -145,8 +145,11 @@ func (h *OpenAIResponsesAPIHandler) handleNonStreamingResponseViaChat(c *gin.Con var param any converted := responsesconverter.ConvertOpenAIChatCompletionsResponseToOpenAIResponsesNonStream(cliCtx, modelName, originalResponsesJSON, originalResponsesJSON, resp, ¶m) if converted == "" { - _, _ = c.Writer.Write(resp) - cliCancel() + h.WriteErrorResponse(c, &interfaces.ErrorMessage{ + StatusCode: http.StatusInternalServerError, + Error: fmt.Errorf("failed to convert chat completion response to responses format"), + }) + cliCancel(fmt.Errorf("response conversion failed")) return } _, _ = c.Writer.Write([]byte(converted))