Add reasoning effort to usage events

This commit is contained in:
yavon007
2026-05-19 22:10:48 +08:00
parent bb5ac40a67
commit 0de0ad0d36
12 changed files with 268 additions and 51 deletions
+50
View File
@@ -339,6 +339,56 @@ func hasThinkingConfig(config ThinkingConfig) bool {
return config.Mode != ModeBudget || config.Budget != 0 || config.Level != ""
}
// ExtractReasoningEffort returns the request's thinking setting as a canonical
// reasoning_effort label for usage logging. Model suffixes have the same
// priority as ApplyThinking: a valid suffix overrides body fields.
func ExtractReasoningEffort(body []byte, provider, model string) string {
if effort := reasoningEffortFromSuffix(ParseSuffix(model)); effort != "" {
return effort
}
provider = strings.ToLower(strings.TrimSpace(provider))
config := extractThinkingConfig(body, provider)
if !hasThinkingConfig(config) {
switch provider {
case "openai-response":
config = extractCodexConfig(body)
case "openai":
config = extractCodexConfig(body)
}
}
return reasoningEffortFromConfig(config)
}
func reasoningEffortFromSuffix(suffix SuffixResult) string {
if !suffix.HasSuffix {
return ""
}
return reasoningEffortFromConfig(parseSuffixToConfig(suffix.RawSuffix, "", suffix.ModelName))
}
func reasoningEffortFromConfig(config ThinkingConfig) string {
if !hasThinkingConfig(config) {
return ""
}
switch config.Mode {
case ModeNone:
return string(LevelNone)
case ModeAuto:
return string(LevelAuto)
case ModeLevel:
return strings.ToLower(strings.TrimSpace(string(config.Level)))
case ModeBudget:
level, ok := ConvertBudgetToLevel(config.Budget)
if !ok {
return ""
}
return level
default:
return ""
}
}
// extractClaudeConfig extracts thinking configuration from Claude format request body.
//
// Claude API format:
@@ -0,0 +1,31 @@
package thinking
import "testing"
func TestExtractReasoningEffortUsesSuffixOverBody(t *testing.T) {
got := ExtractReasoningEffort([]byte(`{"reasoning_effort":"low"}`), "openai", "gpt-5.4(high)")
if got != "high" {
t.Fatalf("ExtractReasoningEffort() = %q, want %q", got, "high")
}
}
func TestExtractReasoningEffortConvertsBudgetToLevel(t *testing.T) {
got := ExtractReasoningEffort([]byte(`{"thinking":{"type":"enabled","budget_tokens":8192}}`), "claude", "claude-sonnet-4-5")
if got != "medium" {
t.Fatalf("ExtractReasoningEffort() = %q, want %q", got, "medium")
}
}
func TestExtractReasoningEffortSupportsOpenAIResponses(t *testing.T) {
got := ExtractReasoningEffort([]byte(`{"reasoning":{"effort":"medium"}}`), "openai-response", "gpt-5.4")
if got != "medium" {
t.Fatalf("ExtractReasoningEffort() = %q, want %q", got, "medium")
}
}
func TestExtractReasoningEffortMissingConfigIsEmpty(t *testing.T) {
got := ExtractReasoningEffort([]byte(`{"messages":[{"role":"user","content":"hi"}]}`), "openai", "gpt-5.4")
if got != "" {
t.Fatalf("ExtractReasoningEffort() = %q, want empty", got)
}
}