fix(openai): harden GPT-5.6 billing and usage

This commit is contained in:
superman2003
2026-07-10 15:13:11 +08:00
parent 9a2f11b4e2
commit de28eba3c8
28 changed files with 524 additions and 49 deletions
@@ -53,6 +53,26 @@ func TestUsageConversionsPreserveCacheWriteTokens(t *testing.T) {
require.Equal(t, 200, roundTrip.InputTokensDetails.CacheWriteTokens)
}
func TestResponsesUsageNestedCacheWritePresenceOverridesTopLevelAlias(t *testing.T) {
tests := []struct {
name string
nestedJSON string
want int
}{
{name: "explicit zero", nestedJSON: `{"cache_write_tokens":0}`, want: 0},
{name: "nonzero", nestedJSON: `{"cache_write_tokens":7}`, want: 7},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
var usage ResponsesUsage
payload := []byte(`{"input_tokens":20,"output_tokens":2,"cache_creation_input_tokens":19,"input_tokens_details":` + tt.nestedJSON + `}`)
require.NoError(t, json.Unmarshal(payload, &usage))
require.Equal(t, tt.want, usage.CacheCreationInputTokens)
})
}
}
func TestChatCompletionsToResponses_SystemMessage(t *testing.T) {
req := &ChatCompletionsRequest{
Model: "gpt-4o",
+25
View File
@@ -332,6 +332,10 @@ type ResponsesUsage struct {
func (u *ResponsesUsage) UnmarshalJSON(data []byte) error {
type responsesUsageAlias ResponsesUsage
type cacheTokenPresence struct {
CacheCreationTokens *int `json:"cache_creation_tokens"`
CacheWriteTokens *int `json:"cache_write_tokens"`
}
var aux struct {
responsesUsageAlias
PromptTokens int `json:"prompt_tokens"`
@@ -345,6 +349,13 @@ func (u *ResponsesUsage) UnmarshalJSON(data []byte) error {
if err := json.Unmarshal(data, &aux); err != nil {
return err
}
var nestedPresence struct {
InputTokensDetails *cacheTokenPresence `json:"input_tokens_details"`
PromptTokensDetails *cacheTokenPresence `json:"prompt_tokens_details"`
}
if err := json.Unmarshal(data, &nestedPresence); err != nil {
return err
}
*u = ResponsesUsage(aux.responsesUsageAlias)
if u.InputTokens == 0 && aux.PromptTokens != 0 {
u.InputTokens = aux.PromptTokens
@@ -368,6 +379,20 @@ func (u *ResponsesUsage) UnmarshalJSON(data []byte) error {
if u.OutputTokensDetails == nil && aux.CompletionTokensDetails != nil {
u.OutputTokensDetails = aux.CompletionTokensDetails
}
var canonicalCacheCreationTokens *int
switch {
case nestedPresence.InputTokensDetails != nil && nestedPresence.InputTokensDetails.CacheWriteTokens != nil:
canonicalCacheCreationTokens = nestedPresence.InputTokensDetails.CacheWriteTokens
case nestedPresence.PromptTokensDetails != nil && nestedPresence.PromptTokensDetails.CacheWriteTokens != nil:
canonicalCacheCreationTokens = nestedPresence.PromptTokensDetails.CacheWriteTokens
case nestedPresence.InputTokensDetails != nil && nestedPresence.InputTokensDetails.CacheCreationTokens != nil:
canonicalCacheCreationTokens = nestedPresence.InputTokensDetails.CacheCreationTokens
case nestedPresence.PromptTokensDetails != nil && nestedPresence.PromptTokensDetails.CacheCreationTokens != nil:
canonicalCacheCreationTokens = nestedPresence.PromptTokensDetails.CacheCreationTokens
}
if canonicalCacheCreationTokens != nil {
u.CacheCreationInputTokens = max(*canonicalCacheCreationTokens, 0)
}
if u.TotalTokens == 0 && (u.InputTokens != 0 || u.OutputTokens != 0) {
u.TotalTokens = u.InputTokens + u.OutputTokens
}
+1
View File
@@ -18,6 +18,7 @@ type Model struct {
// DefaultModels OpenAI models list
var DefaultModels = []Model{
{ID: "gpt-5.6", Object: "model", Created: 1780876800, OwnedBy: "openai", Type: "model", DisplayName: "GPT-5.6 (Sol)"},
{ID: "gpt-5.6-sol", Object: "model", Created: 1780876800, OwnedBy: "openai", Type: "model", DisplayName: "GPT-5.6 Sol"},
{ID: "gpt-5.6-terra", Object: "model", Created: 1780876800, OwnedBy: "openai", Type: "model", DisplayName: "GPT-5.6 Terra"},
{ID: "gpt-5.6-luna", Object: "model", Created: 1780876800, OwnedBy: "openai", Type: "model", DisplayName: "GPT-5.6 Luna"},
@@ -0,0 +1,11 @@
package openai
import (
"testing"
"github.com/stretchr/testify/require"
)
func TestDefaultModelsIncludeBareGPT56Alias(t *testing.T) {
require.Contains(t, DefaultModelIDs(), "gpt-5.6")
}