feat: publish sanitized custom.97 source
This commit is contained in:
1022 files changed
+69903
-19207
No files matched your search
@@ -26,15 +26,25 @@ type claudeCapabilities struct {
|
||||
supportsManual bool
|
||||
defaultThinking bool
|
||||
supportsDisable bool
|
||||
supportsEffort bool
|
||||
supportsXHigh bool
|
||||
supportsMax bool
|
||||
strictSampling bool
|
||||
// disableAsBetweenTools marks models whose lowest thinking setting is
|
||||
// {"type":"between_tools"} instead of {"type":"disabled"}.
|
||||
disableAsBetweenTools bool
|
||||
supportsEffort bool
|
||||
supportsXHigh bool
|
||||
supportsMax bool
|
||||
strictSampling bool
|
||||
// offEffortAtMostHigh marks models that accept effort high or below only
|
||||
// while thinking is off (disabled or between_tools).
|
||||
offEffortAtMostHigh bool
|
||||
// defaultEffort is the effort the model runs at when a request sets none:
|
||||
// medium on Claude Opus 5.5 and Haiku 5.5 and high on every other model
|
||||
// (https://platform.claude.com/docs/en/build-with-claude/effort).
|
||||
defaultEffort Effort
|
||||
}
|
||||
|
||||
func claudeCapabilitiesFor(model string) claudeCapabilities {
|
||||
model = strings.ToLower(model)
|
||||
capabilities := claudeCapabilities{supportsManual: true, supportsDisable: true}
|
||||
capabilities := claudeCapabilities{supportsManual: true, supportsDisable: true, defaultEffort: EffortHigh}
|
||||
|
||||
switch {
|
||||
case strings.HasPrefix(model, "claude-fable-5"),
|
||||
@@ -43,6 +53,7 @@ func claudeCapabilitiesFor(model string) claudeCapabilities {
|
||||
capabilities.supportsManual = false
|
||||
capabilities.defaultThinking = true
|
||||
capabilities.supportsDisable = false
|
||||
capabilities.supportsEffort = true
|
||||
capabilities.supportsXHigh = true
|
||||
capabilities.supportsMax = true
|
||||
capabilities.strictSampling = true
|
||||
@@ -50,17 +61,41 @@ func claudeCapabilitiesFor(model string) claudeCapabilities {
|
||||
capabilities.adaptive = true
|
||||
capabilities.defaultThinking = true
|
||||
capabilities.supportsDisable = false
|
||||
capabilities.supportsEffort = true
|
||||
capabilities.supportsMax = true
|
||||
capabilities.strictSampling = true
|
||||
case strings.HasPrefix(model, "claude-opus-5-5"),
|
||||
strings.HasPrefix(model, "claude-sonnet-5-5"):
|
||||
// Opus 5.5 cannot turn thinking off at all; Sonnet 5.5 turns it off
|
||||
// with between_tools, which takes effort high or below only.
|
||||
capabilities.adaptive = true
|
||||
capabilities.supportsManual = false
|
||||
capabilities.defaultThinking = true
|
||||
capabilities.supportsDisable = false
|
||||
capabilities.disableAsBetweenTools = strings.HasPrefix(model, "claude-sonnet-5-5")
|
||||
capabilities.offEffortAtMostHigh = capabilities.disableAsBetweenTools
|
||||
if strings.HasPrefix(model, "claude-opus-5-5") {
|
||||
capabilities.defaultEffort = EffortMedium
|
||||
}
|
||||
capabilities.supportsEffort = true
|
||||
capabilities.supportsXHigh = true
|
||||
capabilities.supportsMax = true
|
||||
capabilities.strictSampling = true
|
||||
case strings.HasPrefix(model, "claude-opus-5"),
|
||||
strings.HasPrefix(model, "claude-sonnet-5"),
|
||||
strings.HasPrefix(model, "claude-haiku-5"),
|
||||
strings.HasPrefix(model, "claude-opus-4-8"),
|
||||
strings.HasPrefix(model, "claude-opus-4-7"):
|
||||
capabilities.adaptive = true
|
||||
capabilities.supportsManual = false
|
||||
if strings.HasPrefix(model, "claude-opus-5") || strings.HasPrefix(model, "claude-sonnet-5") {
|
||||
if strings.HasPrefix(model, "claude-opus-5") || strings.HasPrefix(model, "claude-sonnet-5") || strings.HasPrefix(model, "claude-haiku-5") {
|
||||
capabilities.defaultThinking = true
|
||||
}
|
||||
// Opus 5 and Haiku 5.5 reject disabled thinking with xhigh or max.
|
||||
capabilities.offEffortAtMostHigh = strings.HasPrefix(model, "claude-opus-5") || strings.HasPrefix(model, "claude-haiku-5")
|
||||
if strings.HasPrefix(model, "claude-haiku-5") {
|
||||
capabilities.defaultEffort = EffortMedium
|
||||
}
|
||||
capabilities.supportsEffort = true
|
||||
capabilities.supportsXHigh = true
|
||||
capabilities.supportsMax = true
|
||||
@@ -97,12 +132,6 @@ func RenderClaude(model string, intent Intent, maxTokens *uint, adapterBudgetPer
|
||||
diagnostics = append(diagnostics, normalizeDiagnostics...)
|
||||
}
|
||||
capabilities := claudeCapabilitiesFor(model)
|
||||
if disabledWithEffort {
|
||||
diagnostics = append(diagnostics, claudeReasoningDiagnostic(
|
||||
"claude_disabled_effort_ignored",
|
||||
fmt.Sprintf("model %q cannot apply effort %q while thinking is disabled; the effort was ignored", model, intent.Effort),
|
||||
))
|
||||
}
|
||||
if !intent.HasStrength() {
|
||||
if intent.IncludeThoughts != nil && capabilities.adaptive && capabilities.defaultThinking {
|
||||
thinking := &dto.Thinking{Type: "adaptive"}
|
||||
@@ -113,17 +142,43 @@ func RenderClaude(model string, intent Intent, maxTokens *uint, adapterBudgetPer
|
||||
}
|
||||
return ClaudeRender{
|
||||
Thinking: thinking,
|
||||
EffectiveEffort: EffortHigh,
|
||||
EffectiveEffort: capabilities.defaultEffort,
|
||||
ClearSampling: capabilities.strictSampling,
|
||||
}, nil
|
||||
}
|
||||
if capabilities.defaultThinking {
|
||||
return ClaudeRender{EffectiveEffort: EffortHigh, ClearSampling: capabilities.strictSampling}, nil
|
||||
return ClaudeRender{EffectiveEffort: capabilities.defaultEffort, ClearSampling: capabilities.strictSampling}, nil
|
||||
}
|
||||
return ClaudeRender{ClearSampling: capabilities.strictSampling}, nil
|
||||
}
|
||||
|
||||
if intent.Mode == ModeDisabled || intent.Effort == EffortNone {
|
||||
// Effort works without thinking, so a requested level is sent at one
|
||||
// the model accepts while thinking is off.
|
||||
outputEffort := Effort("")
|
||||
if disabledWithEffort && (capabilities.supportsDisable || capabilities.disableAsBetweenTools) {
|
||||
outputEffort = ClaudeEffort(model, intent.Effort)
|
||||
if capabilities.offEffortAtMostHigh && (outputEffort == EffortXHigh || outputEffort == EffortMax) {
|
||||
outputEffort = EffortHigh
|
||||
}
|
||||
diagnostics = append(diagnostics, claudeEffortDiagnostics(model, intent.Effort, outputEffort)...)
|
||||
}
|
||||
if capabilities.disableAsBetweenTools {
|
||||
// between_tools takes no other thinking field and runs at the
|
||||
// default effort or the requested one, both within its "high or
|
||||
// below" limit.
|
||||
diagnostics = append(diagnostics, claudeReasoningDiagnostic(
|
||||
"claude_thinking_disable_as_between_tools",
|
||||
fmt.Sprintf("model %q rejects disabled thinking; using between_tools, its lowest thinking setting", model),
|
||||
))
|
||||
return ClaudeRender{
|
||||
Thinking: &dto.Thinking{Type: "between_tools"},
|
||||
OutputEffort: outputEffort,
|
||||
EffectiveEffort: EffortNone,
|
||||
ClearSampling: capabilities.strictSampling,
|
||||
Diagnostics: diagnostics,
|
||||
}, nil
|
||||
}
|
||||
if !capabilities.supportsDisable {
|
||||
diagnostics = append(diagnostics, claudeReasoningDiagnostic(
|
||||
"claude_thinking_disable_unsupported",
|
||||
@@ -138,8 +193,7 @@ func RenderClaude(model string, intent Intent, maxTokens *uint, adapterBudgetPer
|
||||
thinking.Display = "omitted"
|
||||
}
|
||||
}
|
||||
outputEffort := Effort("")
|
||||
effectiveEffort := EffortHigh
|
||||
effectiveEffort := capabilities.defaultEffort
|
||||
if capabilities.supportsEffort {
|
||||
outputEffort = EffortLow
|
||||
effectiveEffort = EffortLow
|
||||
@@ -156,6 +210,7 @@ func RenderClaude(model string, intent Intent, maxTokens *uint, adapterBudgetPer
|
||||
}
|
||||
return ClaudeRender{
|
||||
Thinking: &dto.Thinking{Type: "disabled"},
|
||||
OutputEffort: outputEffort,
|
||||
EffectiveEffort: EffortNone,
|
||||
ClearSampling: capabilities.strictSampling,
|
||||
Diagnostics: diagnostics,
|
||||
@@ -175,7 +230,7 @@ func RenderClaude(model string, intent Intent, maxTokens *uint, adapterBudgetPer
|
||||
effort = EffortFromBudget(*intent.BudgetTokens)
|
||||
}
|
||||
if effort == "" && intent.Mode == ModeEnabled {
|
||||
effort = EffortHigh
|
||||
effort = capabilities.defaultEffort
|
||||
}
|
||||
normalizedEffort := normalizeClaudeEffort(effort, capabilities)
|
||||
if effort != "" && normalizedEffort != effort {
|
||||
@@ -187,7 +242,7 @@ func RenderClaude(model string, intent Intent, maxTokens *uint, adapterBudgetPer
|
||||
effort = normalizedEffort
|
||||
effectiveEffort := effort
|
||||
if effectiveEffort == "" && intent.Mode == ModeAdaptive {
|
||||
effectiveEffort = EffortHigh
|
||||
effectiveEffort = capabilities.defaultEffort
|
||||
}
|
||||
|
||||
// Claude effort can be used without enabling thinking. Preserve that
|
||||
@@ -227,11 +282,22 @@ func RenderClaude(model string, intent Intent, maxTokens *uint, adapterBudgetPer
|
||||
))
|
||||
intent.Mode = ModeEnabled
|
||||
if intent.Effort == "" {
|
||||
intent.Effort = EffortHigh
|
||||
intent.Effort = capabilities.defaultEffort
|
||||
}
|
||||
}
|
||||
if intent.Mode == ModeUnset {
|
||||
return ClaudeRender{OutputEffort: intent.Effort, EffectiveEffort: intent.Effort, Diagnostics: diagnostics}, nil
|
||||
// Known models get the effort they accept. They think only when asked,
|
||||
// so a removed effort leaves none.
|
||||
effort := intent.Effort
|
||||
if isKnownClaudeModel(model) {
|
||||
effort = ClaudeEffort(model, intent.Effort)
|
||||
diagnostics = append(diagnostics, claudeEffortDiagnostics(model, intent.Effort, effort)...)
|
||||
}
|
||||
effectiveEffort := effort
|
||||
if effectiveEffort == "" {
|
||||
effectiveEffort = EffortNone
|
||||
}
|
||||
return ClaudeRender{OutputEffort: effort, EffectiveEffort: effectiveEffort, Diagnostics: diagnostics}, nil
|
||||
}
|
||||
var raisedMaxTokens *uint
|
||||
if maxTokens == nil || *maxTokens <= 1024 {
|
||||
@@ -289,9 +355,8 @@ func RenderClaude(model string, intent Intent, maxTokens *uint, adapterBudgetPer
|
||||
} else if effectiveEffort == "" {
|
||||
effectiveEffort = EffortFromBudget(budget)
|
||||
}
|
||||
outputEffort := Effort("")
|
||||
if capabilities.supportsEffort && intent.Effort != "" {
|
||||
outputEffort = normalizeClaudeEffort(intent.Effort, capabilities)
|
||||
outputEffort := ClaudeEffort(model, intent.Effort)
|
||||
if outputEffort != "" {
|
||||
effectiveEffort = outputEffort
|
||||
}
|
||||
thinking := &dto.Thinking{Type: "enabled", BudgetTokens: &budget}
|
||||
@@ -322,6 +387,25 @@ func claudeReasoningDiagnostic(code string, message string) types.ConversionDiag
|
||||
}
|
||||
}
|
||||
|
||||
// claudeEffortDiagnostics reports a requested effort that is sent at another
|
||||
// level or removed because the model takes none.
|
||||
func claudeEffortDiagnostics(model string, requested Effort, sent Effort) []types.ConversionDiagnostic {
|
||||
switch {
|
||||
case requested == "" || requested == EffortNone || requested == sent:
|
||||
return nil
|
||||
case sent == "":
|
||||
return []types.ConversionDiagnostic{claudeReasoningDiagnostic(
|
||||
"claude_effort_unsupported",
|
||||
fmt.Sprintf("model %q does not support effort %q; the effort was removed", model, requested),
|
||||
)}
|
||||
default:
|
||||
return []types.ConversionDiagnostic{claudeReasoningDiagnostic(
|
||||
"claude_effort_adjusted",
|
||||
fmt.Sprintf("model %q does not support effort %q with the selected thinking mode; using %q", model, requested, sent),
|
||||
)}
|
||||
}
|
||||
}
|
||||
|
||||
// ClaudeUsesManualThinking reports whether an exact numeric budget is rendered
|
||||
// as legacy extended thinking rather than being reduced to adaptive effort.
|
||||
func ClaudeUsesManualThinking(model string, intent Intent) bool {
|
||||
@@ -333,12 +417,39 @@ func IsKnownClaudeModel(model string) bool {
|
||||
return isKnownClaudeModel(model)
|
||||
}
|
||||
|
||||
// ClaudeDefaultEffort is the effort the model runs at when a request sets
|
||||
// none.
|
||||
func ClaudeDefaultEffort(model string) Effort {
|
||||
return claudeCapabilitiesFor(model).defaultEffort
|
||||
}
|
||||
|
||||
// ClaudeEffort returns the effort level the model accepts in place of the
|
||||
// requested one. It returns empty when no effort is requested or the model
|
||||
// takes none, which includes models missing from the capability table.
|
||||
func ClaudeEffort(model string, effort Effort) Effort {
|
||||
capabilities := claudeCapabilitiesFor(model)
|
||||
if !capabilities.supportsEffort || effort == "" || effort == EffortNone {
|
||||
return ""
|
||||
}
|
||||
return normalizeClaudeEffort(effort, capabilities)
|
||||
}
|
||||
|
||||
// ResolveClaudeDefault makes the Claude model's default thinking explicit for
|
||||
// a non-Claude target: no intent becomes adaptive thinking on models that
|
||||
// think by default, and thinking without a strength takes the model's
|
||||
// default effort.
|
||||
func ResolveClaudeDefault(model string, intent Intent) Intent {
|
||||
if intent.HasStrength() || !claudeCapabilitiesFor(model).defaultThinking {
|
||||
return intent
|
||||
capabilities := claudeCapabilitiesFor(model)
|
||||
switch {
|
||||
case !intent.HasStrength():
|
||||
if !capabilities.defaultThinking {
|
||||
return intent
|
||||
}
|
||||
intent.Mode = ModeAdaptive
|
||||
intent.Effort = capabilities.defaultEffort
|
||||
case intent.Effort == "" && intent.BudgetTokens == nil && (intent.Mode == ModeAdaptive || intent.Mode == ModeEnabled):
|
||||
intent.Effort = capabilities.defaultEffort
|
||||
}
|
||||
intent.Mode = ModeAdaptive
|
||||
intent.Effort = EffortHigh
|
||||
return intent
|
||||
}
|
||||
|
||||
|
||||
@@ -145,7 +145,7 @@ func RenderGemini(model string, intent Intent, maxOutputTokens *uint, adapterBud
|
||||
}
|
||||
hasBudget = true
|
||||
} else if intent.Effort != "" {
|
||||
budget = gemini25BudgetForEffort(intent.Effort)
|
||||
budget = gemini25BudgetForEffort(intent.Effort, capabilities.maxBudget)
|
||||
hasBudget = true
|
||||
} else if intent.Mode != ModeUnset && maxOutputTokens != nil && *maxOutputTokens > 0 {
|
||||
if uint64(*maxOutputTokens) > uint64(math.MaxInt) {
|
||||
@@ -295,7 +295,7 @@ func NormalizeGeminiThinkingConfig(model string, generation *dto.GeminiChatGener
|
||||
|
||||
if capabilities.kind == geminiThinkingBudget {
|
||||
if config.ThinkingLevel != "" {
|
||||
budget := gemini25BudgetForEffort(intent.Effort)
|
||||
budget := gemini25BudgetForEffort(intent.Effort, capabilities.maxBudget)
|
||||
diagnostics = append(diagnostics, geminiReasoningDiagnostic(
|
||||
"gemini_level_to_budget",
|
||||
fmt.Sprintf("model %q uses thinkingBudget; thinkingLevel %q was converted to budget %d", model, config.ThinkingLevel, budget),
|
||||
@@ -476,14 +476,19 @@ func EquivalentGeminiStrength(model string, left Intent, right Intent) (bool, er
|
||||
return leftConfig.ThinkingBudget == nil || *leftConfig.ThinkingBudget == *rightConfig.ThinkingBudget, nil
|
||||
}
|
||||
|
||||
func gemini25BudgetForEffort(effort Effort) int {
|
||||
// gemini25BudgetForEffort follows Google's OpenAI-compatible mapping, where
|
||||
// high is 24576; xhigh and max, which that mapping lacks, take the model's
|
||||
// largest budget.
|
||||
func gemini25BudgetForEffort(effort Effort, maxBudget int) int {
|
||||
switch effort {
|
||||
case EffortMinimal, EffortLow:
|
||||
return 1024
|
||||
case EffortMedium:
|
||||
return 8192
|
||||
case EffortHigh, EffortXHigh, EffortMax:
|
||||
case EffortHigh:
|
||||
return 24576
|
||||
case EffortXHigh, EffortMax:
|
||||
return maxBudget
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ var EffortSuffixes = []string{"-max", "-xhigh", "-high", "-medium", "-low", "-mi
|
||||
|
||||
var OpenAIEffortSuffixes = []string{"-max", "-xhigh", "-high", "-medium", "-low", "-minimal", "-none"}
|
||||
|
||||
var DeepSeekV4EffortSuffixes = []string{"-none", "-max"}
|
||||
var DeepSeekV4EffortSuffixes = []string{"-none", "-low", "-max"}
|
||||
|
||||
var (
|
||||
legacyOpenAIModelPattern = regexp.MustCompile(`^(gpt-[a-z0-9][a-z0-9._-]*|o[1-9][a-z0-9._-]*)$`)
|
||||
@@ -136,12 +136,16 @@ func ParseOpenAIReasoningEffortFromModelSuffix(modelName string, preserveEffortT
|
||||
return effort, baseModel
|
||||
}
|
||||
|
||||
func ParseClaudeModelSuffix(modelName string, allowThinkingAlias bool) (string, Intent, bool, error) {
|
||||
// ParseClaudeModelSuffix folds the naked claude-* aliases (-thinking,
|
||||
// -nothinking, -thinking-<budget>, and effort tails such as -high) into an
|
||||
// Intent. allowSuffixAlias is the host thinking-adapter toggle; when false the
|
||||
// name is returned verbatim and no intent is produced.
|
||||
func ParseClaudeModelSuffix(modelName string, allowSuffixAlias bool) (string, Intent, bool, error) {
|
||||
prefix, bare := splitModelNamespace(modelName)
|
||||
if !strings.HasPrefix(bare, "claude-") {
|
||||
return modelName, Intent{}, false, nil
|
||||
}
|
||||
base, intent, found, err := parseProviderModelSuffix(bare, "claude-", allowThinkingAlias, true)
|
||||
base, intent, found, err := parseProviderModelSuffix(bare, "claude-", allowSuffixAlias, true)
|
||||
if err != nil || !found || !legacyClaudeModelPattern.MatchString(base) {
|
||||
return modelName, Intent{}, false, err
|
||||
}
|
||||
@@ -157,7 +161,7 @@ func isKnownClaudeModel(modelName string) bool {
|
||||
}
|
||||
knownPrefixes := []string{
|
||||
"claude-fable-5", "claude-mythos-5", "claude-mythos-preview",
|
||||
"claude-opus-5", "claude-sonnet-5", "claude-opus-4-8",
|
||||
"claude-opus-5", "claude-sonnet-5", "claude-haiku-5", "claude-opus-4-8",
|
||||
"claude-opus-4-7", "claude-opus-4-6", "claude-sonnet-4-6",
|
||||
"claude-opus-4-5", "claude-sonnet-4-5", "claude-haiku-4-5",
|
||||
"claude-opus-4-1", "claude-opus-4-", "claude-sonnet-4-",
|
||||
@@ -171,12 +175,14 @@ func isKnownClaudeModel(modelName string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func ParseGeminiModelSuffix(modelName string, allowThinkingAlias bool) (string, Intent, bool, error) {
|
||||
// ParseGeminiModelSuffix is the gemini-* counterpart of ParseClaudeModelSuffix
|
||||
// and honours allowSuffixAlias the same way.
|
||||
func ParseGeminiModelSuffix(modelName string, allowSuffixAlias bool) (string, Intent, bool, error) {
|
||||
prefix, bare := splitModelNamespace(modelName)
|
||||
if !strings.HasPrefix(bare, "gemini-") {
|
||||
return modelName, Intent{}, false, nil
|
||||
}
|
||||
base, intent, found, err := parseProviderModelSuffix(bare, "gemini-", allowThinkingAlias, true)
|
||||
base, intent, found, err := parseProviderModelSuffix(bare, "gemini-", allowSuffixAlias, true)
|
||||
if err != nil || !found || !legacyGeminiModelPattern.MatchString(base) {
|
||||
return modelName, Intent{}, false, err
|
||||
}
|
||||
@@ -186,13 +192,13 @@ func ParseGeminiModelSuffix(modelName string, allowThinkingAlias bool) (string,
|
||||
// ParseKnownProviderModelSuffix extracts a canonical intent only when the
|
||||
// origin identifies a provider family whose suffix vocabulary is defined by
|
||||
// relaykit. Unknown OpenAI-compatible model names are deliberately untouched.
|
||||
func ParseKnownProviderModelSuffix(modelName string, allowThinkingAlias bool) (string, Intent, bool, error) {
|
||||
func ParseKnownProviderModelSuffix(modelName string, allowSuffixAlias bool) (string, Intent, bool, error) {
|
||||
bare := lastModelPathSegment(modelName)
|
||||
if strings.HasPrefix(bare, "claude-") {
|
||||
return ParseClaudeModelSuffix(modelName, allowThinkingAlias)
|
||||
return ParseClaudeModelSuffix(modelName, allowSuffixAlias)
|
||||
}
|
||||
if strings.HasPrefix(bare, "gemini-") {
|
||||
return ParseGeminiModelSuffix(modelName, allowThinkingAlias)
|
||||
return ParseGeminiModelSuffix(modelName, allowSuffixAlias)
|
||||
}
|
||||
return modelName, Intent{}, false, nil
|
||||
}
|
||||
@@ -214,37 +220,39 @@ func TrimGeminiThinkingSuffix(modelName string) (string, bool) {
|
||||
return baseModel, ok && err == nil
|
||||
}
|
||||
|
||||
func parseProviderModelSuffix(modelName string, requiredPrefix string, allowThinkingAlias bool, includeThoughts bool) (string, Intent, bool, error) {
|
||||
if allowThinkingAlias {
|
||||
if marker := strings.LastIndex(modelName, "-thinking-"); marker >= 0 {
|
||||
baseModel := modelName[:marker]
|
||||
if !strings.HasPrefix(baseModel, requiredPrefix) {
|
||||
return modelName, Intent{}, false, nil
|
||||
}
|
||||
budget, err := strconv.Atoi(modelName[marker+len("-thinking-"):])
|
||||
if err != nil {
|
||||
return modelName, Intent{}, false, fmt.Errorf("invalid thinking budget suffix on model %q: %w", modelName, err)
|
||||
}
|
||||
intent := Intent{BudgetTokens: &budget, Source: SourceSuffix, BudgetSource: SourceSuffix}
|
||||
if includeThoughts {
|
||||
value := true
|
||||
intent.IncludeThoughts = &value
|
||||
}
|
||||
return baseModel, intent, true, nil
|
||||
// parseProviderModelSuffix recognises a provider family's naked model-name
|
||||
// aliases. allowSuffixAlias gates all of them, including effort tails, so a
|
||||
// disabled thinking adapter leaves the model name untouched.
|
||||
func parseProviderModelSuffix(modelName string, requiredPrefix string, allowSuffixAlias bool, includeThoughts bool) (string, Intent, bool, error) {
|
||||
if !allowSuffixAlias {
|
||||
return modelName, Intent{}, false, nil
|
||||
}
|
||||
if marker := strings.LastIndex(modelName, "-thinking-"); marker >= 0 {
|
||||
baseModel := modelName[:marker]
|
||||
if !strings.HasPrefix(baseModel, requiredPrefix) {
|
||||
return modelName, Intent{}, false, nil
|
||||
}
|
||||
if before, ok := strings.CutSuffix(modelName, "-nothinking"); ok {
|
||||
baseModel := before
|
||||
return baseModel, Intent{Mode: ModeDisabled, Effort: EffortNone, Source: SourceSuffix}, true, nil
|
||||
budget, err := strconv.Atoi(modelName[marker+len("-thinking-"):])
|
||||
if err != nil {
|
||||
return modelName, Intent{}, false, fmt.Errorf("invalid thinking budget suffix on model %q: %w", modelName, err)
|
||||
}
|
||||
if before, ok := strings.CutSuffix(modelName, "-thinking"); ok {
|
||||
baseModel := before
|
||||
intent := Intent{Mode: ModeEnabled, Source: SourceSuffix}
|
||||
if includeThoughts {
|
||||
value := true
|
||||
intent.IncludeThoughts = &value
|
||||
}
|
||||
return baseModel, intent, true, nil
|
||||
intent := Intent{BudgetTokens: &budget, Source: SourceSuffix, BudgetSource: SourceSuffix}
|
||||
if includeThoughts {
|
||||
value := true
|
||||
intent.IncludeThoughts = &value
|
||||
}
|
||||
return baseModel, intent, true, nil
|
||||
}
|
||||
if baseModel, ok := strings.CutSuffix(modelName, "-nothinking"); ok {
|
||||
return baseModel, Intent{Mode: ModeDisabled, Effort: EffortNone, Source: SourceSuffix}, true, nil
|
||||
}
|
||||
if baseModel, ok := strings.CutSuffix(modelName, "-thinking"); ok {
|
||||
intent := Intent{Mode: ModeEnabled, Source: SourceSuffix}
|
||||
if includeThoughts {
|
||||
value := true
|
||||
intent.IncludeThoughts = &value
|
||||
}
|
||||
return baseModel, intent, true, nil
|
||||
}
|
||||
|
||||
suffixes := []string{"-max", "-xhigh", "-high", "-medium", "-low", "-minimal", "-none"}
|
||||
@@ -266,16 +274,19 @@ func parseProviderModelSuffix(modelName string, requiredPrefix string, allowThin
|
||||
return baseModel, intent, true, nil
|
||||
}
|
||||
|
||||
// ParseDeepSeekV4ThinkingSuffix maps the -none/-low/-max tails of
|
||||
// deepseek-flash and deepseek-v4-* onto DeepSeek's thinking switch and
|
||||
// effort. A bare name keeps DeepSeek's default (thinking on, effort high).
|
||||
func ParseDeepSeekV4ThinkingSuffix(modelName string) (baseModel string, thinkingType string, effort string, ok bool) {
|
||||
baseModel, suffix, ok := TrimEffortSuffixWithSuffixes(modelName, DeepSeekV4EffortSuffixes)
|
||||
if !ok || !strings.HasPrefix(baseModel, "deepseek-v4-") {
|
||||
if !ok || baseModel != "deepseek-flash" && !strings.HasPrefix(baseModel, "deepseek-v4-") {
|
||||
return modelName, "", "", false
|
||||
}
|
||||
switch suffix {
|
||||
case "none":
|
||||
return baseModel, "disabled", "", true
|
||||
case "max":
|
||||
return baseModel, "enabled", "max", true
|
||||
case "low", "max":
|
||||
return baseModel, "enabled", suffix, true
|
||||
default:
|
||||
return modelName, "", "", false
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user