diff --git a/providers/openai/responses_language_model.go b/providers/openai/responses_language_model.go index aa48497945d6913d463bdfa49ed095e9f9cb8111..9126ac3c6366e270791fcca0a4d5446ea1647807 100644 --- a/providers/openai/responses_language_model.go +++ b/providers/openai/responses_language_model.go @@ -368,6 +368,21 @@ func responsesProviderMetadata(responseID string) fantasy.ProviderMetadata { } } +func responsesUsage(resp responses.Response) fantasy.Usage { + usage := fantasy.Usage{ + InputTokens: resp.Usage.InputTokens, + OutputTokens: resp.Usage.OutputTokens, + TotalTokens: resp.Usage.InputTokens + resp.Usage.OutputTokens, + } + if resp.Usage.OutputTokensDetails.ReasoningTokens != 0 { + usage.ReasoningTokens = resp.Usage.OutputTokensDetails.ReasoningTokens + } + if resp.Usage.InputTokensDetails.CachedTokens != 0 { + usage.CacheReadTokens = resp.Usage.InputTokensDetails.CachedTokens + } + return usage +} + func toResponsesPrompt(prompt fantasy.Prompt, systemMessageMode string) (responses.ResponseInputParam, []fantasy.CallWarning) { var input responses.ResponseInputParam var warnings []fantasy.CallWarning @@ -853,19 +868,7 @@ func (o responsesLanguageModel) Generate(ctx context.Context, call fantasy.Call) } } - usage := fantasy.Usage{ - InputTokens: response.Usage.InputTokens, - OutputTokens: response.Usage.OutputTokens, - TotalTokens: response.Usage.InputTokens + response.Usage.OutputTokens, - } - - if response.Usage.OutputTokensDetails.ReasoningTokens != 0 { - usage.ReasoningTokens = response.Usage.OutputTokensDetails.ReasoningTokens - } - if response.Usage.InputTokensDetails.CachedTokens != 0 { - usage.CacheReadTokens = response.Usage.InputTokensDetails.CachedTokens - } - + usage := responsesUsage(*response) finishReason := mapResponsesFinishReason(response.IncompleteDetails.Reason, hasFunctionCall) return &fantasy.Response{ @@ -1135,33 +1138,13 @@ func (o responsesLanguageModel) Stream(ctx context.Context, call fantasy.Call) ( completed := event.AsResponseCompleted() responseID = completed.Response.ID finishReason = mapResponsesFinishReason(completed.Response.IncompleteDetails.Reason, hasFunctionCall) - usage = fantasy.Usage{ - InputTokens: completed.Response.Usage.InputTokens, - OutputTokens: completed.Response.Usage.OutputTokens, - TotalTokens: completed.Response.Usage.InputTokens + completed.Response.Usage.OutputTokens, - } - if completed.Response.Usage.OutputTokensDetails.ReasoningTokens != 0 { - usage.ReasoningTokens = completed.Response.Usage.OutputTokensDetails.ReasoningTokens - } - if completed.Response.Usage.InputTokensDetails.CachedTokens != 0 { - usage.CacheReadTokens = completed.Response.Usage.InputTokensDetails.CachedTokens - } + usage = responsesUsage(completed.Response) case "response.incomplete": incomplete := event.AsResponseIncomplete() responseID = incomplete.Response.ID finishReason = mapResponsesFinishReason(incomplete.Response.IncompleteDetails.Reason, hasFunctionCall) - usage = fantasy.Usage{ - InputTokens: incomplete.Response.Usage.InputTokens, - OutputTokens: incomplete.Response.Usage.OutputTokens, - TotalTokens: incomplete.Response.Usage.InputTokens + incomplete.Response.Usage.OutputTokens, - } - if incomplete.Response.Usage.OutputTokensDetails.ReasoningTokens != 0 { - usage.ReasoningTokens = incomplete.Response.Usage.OutputTokensDetails.ReasoningTokens - } - if incomplete.Response.Usage.InputTokensDetails.CachedTokens != 0 { - usage.CacheReadTokens = incomplete.Response.Usage.InputTokensDetails.CachedTokens - } + usage = responsesUsage(incomplete.Response) case "error": errorEvent := event.AsError() @@ -1375,18 +1358,7 @@ func (o responsesLanguageModel) generateObjectWithJSONMode(ctx context.Context, obj, err = schema.ParseAndValidate(jsonText, call.Schema) } - usage := fantasy.Usage{ - InputTokens: response.Usage.InputTokens, - OutputTokens: response.Usage.OutputTokens, - TotalTokens: response.Usage.InputTokens + response.Usage.OutputTokens, - } - if response.Usage.OutputTokensDetails.ReasoningTokens != 0 { - usage.ReasoningTokens = response.Usage.OutputTokensDetails.ReasoningTokens - } - if response.Usage.InputTokensDetails.CachedTokens != 0 { - usage.CacheReadTokens = response.Usage.InputTokensDetails.CachedTokens - } - + usage := responsesUsage(*response) finishReason := mapResponsesFinishReason(response.IncompleteDetails.Reason, false) if err != nil { @@ -1521,33 +1493,13 @@ func (o responsesLanguageModel) streamObjectWithJSONMode(ctx context.Context, ca completed := event.AsResponseCompleted() responseID = completed.Response.ID finishReason = mapResponsesFinishReason(completed.Response.IncompleteDetails.Reason, hasFunctionCall) - usage = fantasy.Usage{ - InputTokens: completed.Response.Usage.InputTokens, - OutputTokens: completed.Response.Usage.OutputTokens, - TotalTokens: completed.Response.Usage.InputTokens + completed.Response.Usage.OutputTokens, - } - if completed.Response.Usage.OutputTokensDetails.ReasoningTokens != 0 { - usage.ReasoningTokens = completed.Response.Usage.OutputTokensDetails.ReasoningTokens - } - if completed.Response.Usage.InputTokensDetails.CachedTokens != 0 { - usage.CacheReadTokens = completed.Response.Usage.InputTokensDetails.CachedTokens - } + usage = responsesUsage(completed.Response) case "response.incomplete": incomplete := event.AsResponseIncomplete() responseID = incomplete.Response.ID finishReason = mapResponsesFinishReason(incomplete.Response.IncompleteDetails.Reason, hasFunctionCall) - usage = fantasy.Usage{ - InputTokens: incomplete.Response.Usage.InputTokens, - OutputTokens: incomplete.Response.Usage.OutputTokens, - TotalTokens: incomplete.Response.Usage.InputTokens + incomplete.Response.Usage.OutputTokens, - } - if incomplete.Response.Usage.OutputTokensDetails.ReasoningTokens != 0 { - usage.ReasoningTokens = incomplete.Response.Usage.OutputTokensDetails.ReasoningTokens - } - if incomplete.Response.Usage.InputTokensDetails.CachedTokens != 0 { - usage.CacheReadTokens = incomplete.Response.Usage.InputTokensDetails.CachedTokens - } + usage = responsesUsage(incomplete.Response) case "error": errorEvent := event.AsError()