mirror of
https://github.com/coder/coder.git
synced 2026-10-16 14:48:56 +08:00
refactor(chatprovider): move fallback option merging out of chatd
This commit is contained in:
+1
-348
@@ -1398,360 +1398,13 @@ func applyFallbackChatModelConfig(
|
||||
return config
|
||||
}
|
||||
|
||||
mergeMissingChatModelCallConfig(
|
||||
chatprovider.MergeMissingCallConfig(
|
||||
&config.ChatModelCallConfig,
|
||||
defaults.ChatModelCallConfig,
|
||||
)
|
||||
return config
|
||||
}
|
||||
|
||||
func mergeMissingChatModelCallConfig(
|
||||
dst *codersdk.ChatModelCallConfig,
|
||||
defaults codersdk.ChatModelCallConfig,
|
||||
) {
|
||||
if dst.MaxOutputTokens == nil {
|
||||
dst.MaxOutputTokens = defaults.MaxOutputTokens
|
||||
}
|
||||
if dst.Temperature == nil {
|
||||
dst.Temperature = defaults.Temperature
|
||||
}
|
||||
if dst.TopP == nil {
|
||||
dst.TopP = defaults.TopP
|
||||
}
|
||||
if dst.TopK == nil {
|
||||
dst.TopK = defaults.TopK
|
||||
}
|
||||
if dst.PresencePenalty == nil {
|
||||
dst.PresencePenalty = defaults.PresencePenalty
|
||||
}
|
||||
if dst.FrequencyPenalty == nil {
|
||||
dst.FrequencyPenalty = defaults.FrequencyPenalty
|
||||
}
|
||||
mergeMissingChatModelProviderOptions(&dst.ProviderOptions, defaults.ProviderOptions)
|
||||
}
|
||||
|
||||
func mergeMissingChatModelProviderOptions(
|
||||
dst **codersdk.ChatModelProviderOptions,
|
||||
defaults *codersdk.ChatModelProviderOptions,
|
||||
) {
|
||||
if defaults == nil {
|
||||
return
|
||||
}
|
||||
if *dst == nil {
|
||||
copied := *defaults
|
||||
*dst = &copied
|
||||
return
|
||||
}
|
||||
|
||||
mergeMissingOpenAIProviderOptions(&(*dst).OpenAI, defaults.OpenAI)
|
||||
mergeMissingAnthropicProviderOptions(&(*dst).Anthropic, defaults.Anthropic)
|
||||
mergeMissingGoogleProviderOptions(&(*dst).Google, defaults.Google)
|
||||
mergeMissingOpenAICompatProviderOptions(&(*dst).OpenAICompat, defaults.OpenAICompat)
|
||||
mergeMissingOpenRouterProviderOptions(&(*dst).OpenRouter, defaults.OpenRouter)
|
||||
mergeMissingVercelProviderOptions(&(*dst).Vercel, defaults.Vercel)
|
||||
}
|
||||
|
||||
func mergeMissingOpenAIProviderOptions(
|
||||
dst **codersdk.ChatModelOpenAIProviderOptions,
|
||||
defaults *codersdk.ChatModelOpenAIProviderOptions,
|
||||
) {
|
||||
if defaults == nil {
|
||||
return
|
||||
}
|
||||
if *dst == nil {
|
||||
copied := *defaults
|
||||
*dst = &copied
|
||||
return
|
||||
}
|
||||
|
||||
current := *dst
|
||||
if current.Include == nil {
|
||||
current.Include = defaults.Include
|
||||
}
|
||||
if current.Instructions == nil {
|
||||
current.Instructions = defaults.Instructions
|
||||
}
|
||||
if current.LogitBias == nil {
|
||||
current.LogitBias = defaults.LogitBias
|
||||
}
|
||||
if current.LogProbs == nil {
|
||||
current.LogProbs = defaults.LogProbs
|
||||
}
|
||||
if current.TopLogProbs == nil {
|
||||
current.TopLogProbs = defaults.TopLogProbs
|
||||
}
|
||||
if current.MaxToolCalls == nil {
|
||||
current.MaxToolCalls = defaults.MaxToolCalls
|
||||
}
|
||||
if current.ParallelToolCalls == nil {
|
||||
current.ParallelToolCalls = defaults.ParallelToolCalls
|
||||
}
|
||||
if current.User == nil {
|
||||
current.User = defaults.User
|
||||
}
|
||||
if current.ReasoningEffort == nil {
|
||||
current.ReasoningEffort = defaults.ReasoningEffort
|
||||
}
|
||||
if current.ReasoningSummary == nil {
|
||||
current.ReasoningSummary = defaults.ReasoningSummary
|
||||
}
|
||||
if current.MaxCompletionTokens == nil {
|
||||
current.MaxCompletionTokens = defaults.MaxCompletionTokens
|
||||
}
|
||||
if current.TextVerbosity == nil {
|
||||
current.TextVerbosity = defaults.TextVerbosity
|
||||
}
|
||||
if current.Prediction == nil {
|
||||
current.Prediction = defaults.Prediction
|
||||
}
|
||||
if current.Store == nil {
|
||||
current.Store = defaults.Store
|
||||
}
|
||||
if current.Metadata == nil {
|
||||
current.Metadata = defaults.Metadata
|
||||
}
|
||||
if current.PromptCacheKey == nil {
|
||||
current.PromptCacheKey = defaults.PromptCacheKey
|
||||
}
|
||||
if current.SafetyIdentifier == nil {
|
||||
current.SafetyIdentifier = defaults.SafetyIdentifier
|
||||
}
|
||||
if current.ServiceTier == nil {
|
||||
current.ServiceTier = defaults.ServiceTier
|
||||
}
|
||||
if current.StructuredOutputs == nil {
|
||||
current.StructuredOutputs = defaults.StructuredOutputs
|
||||
}
|
||||
if current.StrictJSONSchema == nil {
|
||||
current.StrictJSONSchema = defaults.StrictJSONSchema
|
||||
}
|
||||
}
|
||||
|
||||
func mergeMissingAnthropicProviderOptions(
|
||||
dst **codersdk.ChatModelAnthropicProviderOptions,
|
||||
defaults *codersdk.ChatModelAnthropicProviderOptions,
|
||||
) {
|
||||
if defaults == nil {
|
||||
return
|
||||
}
|
||||
if *dst == nil {
|
||||
copied := *defaults
|
||||
*dst = &copied
|
||||
return
|
||||
}
|
||||
|
||||
current := *dst
|
||||
if current.SendReasoning == nil {
|
||||
current.SendReasoning = defaults.SendReasoning
|
||||
}
|
||||
if current.Thinking == nil {
|
||||
current.Thinking = defaults.Thinking
|
||||
} else if defaults.Thinking != nil && current.Thinking.BudgetTokens == nil {
|
||||
current.Thinking.BudgetTokens = defaults.Thinking.BudgetTokens
|
||||
}
|
||||
if current.Effort == nil {
|
||||
current.Effort = defaults.Effort
|
||||
}
|
||||
if current.DisableParallelToolUse == nil {
|
||||
current.DisableParallelToolUse = defaults.DisableParallelToolUse
|
||||
}
|
||||
}
|
||||
|
||||
func mergeMissingGoogleProviderOptions(
|
||||
dst **codersdk.ChatModelGoogleProviderOptions,
|
||||
defaults *codersdk.ChatModelGoogleProviderOptions,
|
||||
) {
|
||||
if defaults == nil {
|
||||
return
|
||||
}
|
||||
if *dst == nil {
|
||||
copied := *defaults
|
||||
*dst = &copied
|
||||
return
|
||||
}
|
||||
|
||||
current := *dst
|
||||
if current.ThinkingConfig == nil {
|
||||
current.ThinkingConfig = defaults.ThinkingConfig
|
||||
} else if defaults.ThinkingConfig != nil {
|
||||
if current.ThinkingConfig.ThinkingBudget == nil {
|
||||
current.ThinkingConfig.ThinkingBudget = defaults.ThinkingConfig.ThinkingBudget
|
||||
}
|
||||
if current.ThinkingConfig.IncludeThoughts == nil {
|
||||
current.ThinkingConfig.IncludeThoughts = defaults.ThinkingConfig.IncludeThoughts
|
||||
}
|
||||
}
|
||||
if strings.TrimSpace(current.CachedContent) == "" {
|
||||
current.CachedContent = defaults.CachedContent
|
||||
}
|
||||
if current.SafetySettings == nil {
|
||||
current.SafetySettings = defaults.SafetySettings
|
||||
}
|
||||
if strings.TrimSpace(current.Threshold) == "" {
|
||||
current.Threshold = defaults.Threshold
|
||||
}
|
||||
}
|
||||
|
||||
func mergeMissingOpenAICompatProviderOptions(
|
||||
dst **codersdk.ChatModelOpenAICompatProviderOptions,
|
||||
defaults *codersdk.ChatModelOpenAICompatProviderOptions,
|
||||
) {
|
||||
if defaults == nil {
|
||||
return
|
||||
}
|
||||
if *dst == nil {
|
||||
copied := *defaults
|
||||
*dst = &copied
|
||||
return
|
||||
}
|
||||
|
||||
current := *dst
|
||||
if current.User == nil {
|
||||
current.User = defaults.User
|
||||
}
|
||||
if current.ReasoningEffort == nil {
|
||||
current.ReasoningEffort = defaults.ReasoningEffort
|
||||
}
|
||||
}
|
||||
|
||||
func mergeMissingOpenRouterProviderOptions(
|
||||
dst **codersdk.ChatModelOpenRouterProviderOptions,
|
||||
defaults *codersdk.ChatModelOpenRouterProviderOptions,
|
||||
) {
|
||||
if defaults == nil {
|
||||
return
|
||||
}
|
||||
if *dst == nil {
|
||||
copied := *defaults
|
||||
*dst = &copied
|
||||
return
|
||||
}
|
||||
|
||||
current := *dst
|
||||
if current.Reasoning == nil {
|
||||
current.Reasoning = defaults.Reasoning
|
||||
} else if defaults.Reasoning != nil {
|
||||
if current.Reasoning.Enabled == nil {
|
||||
current.Reasoning.Enabled = defaults.Reasoning.Enabled
|
||||
}
|
||||
if current.Reasoning.Exclude == nil {
|
||||
current.Reasoning.Exclude = defaults.Reasoning.Exclude
|
||||
}
|
||||
if current.Reasoning.MaxTokens == nil {
|
||||
current.Reasoning.MaxTokens = defaults.Reasoning.MaxTokens
|
||||
}
|
||||
if current.Reasoning.Effort == nil {
|
||||
current.Reasoning.Effort = defaults.Reasoning.Effort
|
||||
}
|
||||
}
|
||||
if current.ExtraBody == nil {
|
||||
current.ExtraBody = defaults.ExtraBody
|
||||
}
|
||||
if current.IncludeUsage == nil {
|
||||
current.IncludeUsage = defaults.IncludeUsage
|
||||
}
|
||||
if current.LogitBias == nil {
|
||||
current.LogitBias = defaults.LogitBias
|
||||
}
|
||||
if current.LogProbs == nil {
|
||||
current.LogProbs = defaults.LogProbs
|
||||
}
|
||||
if current.ParallelToolCalls == nil {
|
||||
current.ParallelToolCalls = defaults.ParallelToolCalls
|
||||
}
|
||||
if current.User == nil {
|
||||
current.User = defaults.User
|
||||
}
|
||||
if current.Provider == nil {
|
||||
current.Provider = defaults.Provider
|
||||
} else if defaults.Provider != nil {
|
||||
if current.Provider.Order == nil {
|
||||
current.Provider.Order = defaults.Provider.Order
|
||||
}
|
||||
if current.Provider.AllowFallbacks == nil {
|
||||
current.Provider.AllowFallbacks = defaults.Provider.AllowFallbacks
|
||||
}
|
||||
if current.Provider.RequireParameters == nil {
|
||||
current.Provider.RequireParameters = defaults.Provider.RequireParameters
|
||||
}
|
||||
if current.Provider.DataCollection == nil {
|
||||
current.Provider.DataCollection = defaults.Provider.DataCollection
|
||||
}
|
||||
if current.Provider.Only == nil {
|
||||
current.Provider.Only = defaults.Provider.Only
|
||||
}
|
||||
if current.Provider.Ignore == nil {
|
||||
current.Provider.Ignore = defaults.Provider.Ignore
|
||||
}
|
||||
if current.Provider.Quantizations == nil {
|
||||
current.Provider.Quantizations = defaults.Provider.Quantizations
|
||||
}
|
||||
if current.Provider.Sort == nil {
|
||||
current.Provider.Sort = defaults.Provider.Sort
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func mergeMissingVercelProviderOptions(
|
||||
dst **codersdk.ChatModelVercelProviderOptions,
|
||||
defaults *codersdk.ChatModelVercelProviderOptions,
|
||||
) {
|
||||
if defaults == nil {
|
||||
return
|
||||
}
|
||||
if *dst == nil {
|
||||
copied := *defaults
|
||||
*dst = &copied
|
||||
return
|
||||
}
|
||||
|
||||
current := *dst
|
||||
if current.Reasoning == nil {
|
||||
current.Reasoning = defaults.Reasoning
|
||||
} else if defaults.Reasoning != nil {
|
||||
if current.Reasoning.Enabled == nil {
|
||||
current.Reasoning.Enabled = defaults.Reasoning.Enabled
|
||||
}
|
||||
if current.Reasoning.MaxTokens == nil {
|
||||
current.Reasoning.MaxTokens = defaults.Reasoning.MaxTokens
|
||||
}
|
||||
if current.Reasoning.Effort == nil {
|
||||
current.Reasoning.Effort = defaults.Reasoning.Effort
|
||||
}
|
||||
if current.Reasoning.Exclude == nil {
|
||||
current.Reasoning.Exclude = defaults.Reasoning.Exclude
|
||||
}
|
||||
}
|
||||
if current.ProviderOptions == nil {
|
||||
current.ProviderOptions = defaults.ProviderOptions
|
||||
} else if defaults.ProviderOptions != nil {
|
||||
if current.ProviderOptions.Order == nil {
|
||||
current.ProviderOptions.Order = defaults.ProviderOptions.Order
|
||||
}
|
||||
if current.ProviderOptions.Models == nil {
|
||||
current.ProviderOptions.Models = defaults.ProviderOptions.Models
|
||||
}
|
||||
}
|
||||
if current.User == nil {
|
||||
current.User = defaults.User
|
||||
}
|
||||
if current.LogitBias == nil {
|
||||
current.LogitBias = defaults.LogitBias
|
||||
}
|
||||
if current.LogProbs == nil {
|
||||
current.LogProbs = defaults.LogProbs
|
||||
}
|
||||
if current.TopLogProbs == nil {
|
||||
current.TopLogProbs = defaults.TopLogProbs
|
||||
}
|
||||
if current.ParallelToolCalls == nil {
|
||||
current.ParallelToolCalls = defaults.ParallelToolCalls
|
||||
}
|
||||
if current.ExtraBody == nil {
|
||||
current.ExtraBody = defaults.ExtraBody
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Processor) resolveFallbackChatModelConfig(
|
||||
ctx context.Context,
|
||||
providerKeys ProviderAPIKeys,
|
||||
|
||||
@@ -557,6 +557,337 @@ func normalizedEnumValue(value string, allowed ...string) *string {
|
||||
return nil
|
||||
}
|
||||
|
||||
// MergeMissingCallConfig fills unset call config values from defaults.
|
||||
func MergeMissingCallConfig(
|
||||
dst *codersdk.ChatModelCallConfig,
|
||||
defaults codersdk.ChatModelCallConfig,
|
||||
) {
|
||||
if dst.MaxOutputTokens == nil {
|
||||
dst.MaxOutputTokens = defaults.MaxOutputTokens
|
||||
}
|
||||
if dst.Temperature == nil {
|
||||
dst.Temperature = defaults.Temperature
|
||||
}
|
||||
if dst.TopP == nil {
|
||||
dst.TopP = defaults.TopP
|
||||
}
|
||||
if dst.TopK == nil {
|
||||
dst.TopK = defaults.TopK
|
||||
}
|
||||
if dst.PresencePenalty == nil {
|
||||
dst.PresencePenalty = defaults.PresencePenalty
|
||||
}
|
||||
if dst.FrequencyPenalty == nil {
|
||||
dst.FrequencyPenalty = defaults.FrequencyPenalty
|
||||
}
|
||||
MergeMissingProviderOptions(&dst.ProviderOptions, defaults.ProviderOptions)
|
||||
}
|
||||
|
||||
// MergeMissingProviderOptions fills unset provider option fields from defaults.
|
||||
func MergeMissingProviderOptions(
|
||||
dst **codersdk.ChatModelProviderOptions,
|
||||
defaults *codersdk.ChatModelProviderOptions,
|
||||
) {
|
||||
if defaults == nil {
|
||||
return
|
||||
}
|
||||
if *dst == nil {
|
||||
copied := *defaults
|
||||
*dst = &copied
|
||||
return
|
||||
}
|
||||
|
||||
current := *dst
|
||||
for _, provider := range []string{
|
||||
fantasyopenai.Name,
|
||||
fantasyanthropic.Name,
|
||||
fantasygoogle.Name,
|
||||
fantasyopenaicompat.Name,
|
||||
fantasyopenrouter.Name,
|
||||
fantasyvercel.Name,
|
||||
} {
|
||||
switch provider {
|
||||
case fantasyopenai.Name:
|
||||
if defaults.OpenAI == nil {
|
||||
continue
|
||||
}
|
||||
if current.OpenAI == nil {
|
||||
copied := *defaults.OpenAI
|
||||
current.OpenAI = &copied
|
||||
continue
|
||||
}
|
||||
dstOpenAI := current.OpenAI
|
||||
defaultOpenAI := defaults.OpenAI
|
||||
if dstOpenAI.Include == nil {
|
||||
dstOpenAI.Include = defaultOpenAI.Include
|
||||
}
|
||||
if dstOpenAI.Instructions == nil {
|
||||
dstOpenAI.Instructions = defaultOpenAI.Instructions
|
||||
}
|
||||
if dstOpenAI.LogitBias == nil {
|
||||
dstOpenAI.LogitBias = defaultOpenAI.LogitBias
|
||||
}
|
||||
if dstOpenAI.LogProbs == nil {
|
||||
dstOpenAI.LogProbs = defaultOpenAI.LogProbs
|
||||
}
|
||||
if dstOpenAI.TopLogProbs == nil {
|
||||
dstOpenAI.TopLogProbs = defaultOpenAI.TopLogProbs
|
||||
}
|
||||
if dstOpenAI.MaxToolCalls == nil {
|
||||
dstOpenAI.MaxToolCalls = defaultOpenAI.MaxToolCalls
|
||||
}
|
||||
if dstOpenAI.ParallelToolCalls == nil {
|
||||
dstOpenAI.ParallelToolCalls = defaultOpenAI.ParallelToolCalls
|
||||
}
|
||||
if dstOpenAI.User == nil {
|
||||
dstOpenAI.User = defaultOpenAI.User
|
||||
}
|
||||
if dstOpenAI.ReasoningEffort == nil {
|
||||
dstOpenAI.ReasoningEffort = defaultOpenAI.ReasoningEffort
|
||||
}
|
||||
if dstOpenAI.ReasoningSummary == nil {
|
||||
dstOpenAI.ReasoningSummary = defaultOpenAI.ReasoningSummary
|
||||
}
|
||||
if dstOpenAI.MaxCompletionTokens == nil {
|
||||
dstOpenAI.MaxCompletionTokens = defaultOpenAI.MaxCompletionTokens
|
||||
}
|
||||
if dstOpenAI.TextVerbosity == nil {
|
||||
dstOpenAI.TextVerbosity = defaultOpenAI.TextVerbosity
|
||||
}
|
||||
if dstOpenAI.Prediction == nil {
|
||||
dstOpenAI.Prediction = defaultOpenAI.Prediction
|
||||
}
|
||||
if dstOpenAI.Store == nil {
|
||||
dstOpenAI.Store = defaultOpenAI.Store
|
||||
}
|
||||
if dstOpenAI.Metadata == nil {
|
||||
dstOpenAI.Metadata = defaultOpenAI.Metadata
|
||||
}
|
||||
if dstOpenAI.PromptCacheKey == nil {
|
||||
dstOpenAI.PromptCacheKey = defaultOpenAI.PromptCacheKey
|
||||
}
|
||||
if dstOpenAI.SafetyIdentifier == nil {
|
||||
dstOpenAI.SafetyIdentifier = defaultOpenAI.SafetyIdentifier
|
||||
}
|
||||
if dstOpenAI.ServiceTier == nil {
|
||||
dstOpenAI.ServiceTier = defaultOpenAI.ServiceTier
|
||||
}
|
||||
if dstOpenAI.StructuredOutputs == nil {
|
||||
dstOpenAI.StructuredOutputs = defaultOpenAI.StructuredOutputs
|
||||
}
|
||||
if dstOpenAI.StrictJSONSchema == nil {
|
||||
dstOpenAI.StrictJSONSchema = defaultOpenAI.StrictJSONSchema
|
||||
}
|
||||
|
||||
case fantasyanthropic.Name:
|
||||
if defaults.Anthropic == nil {
|
||||
continue
|
||||
}
|
||||
if current.Anthropic == nil {
|
||||
copied := *defaults.Anthropic
|
||||
current.Anthropic = &copied
|
||||
continue
|
||||
}
|
||||
dstAnthropic := current.Anthropic
|
||||
defaultAnthropic := defaults.Anthropic
|
||||
if dstAnthropic.SendReasoning == nil {
|
||||
dstAnthropic.SendReasoning = defaultAnthropic.SendReasoning
|
||||
}
|
||||
if dstAnthropic.Thinking == nil {
|
||||
dstAnthropic.Thinking = defaultAnthropic.Thinking
|
||||
} else if defaultAnthropic.Thinking != nil &&
|
||||
dstAnthropic.Thinking.BudgetTokens == nil {
|
||||
dstAnthropic.Thinking.BudgetTokens = defaultAnthropic.Thinking.BudgetTokens
|
||||
}
|
||||
if dstAnthropic.Effort == nil {
|
||||
dstAnthropic.Effort = defaultAnthropic.Effort
|
||||
}
|
||||
if dstAnthropic.DisableParallelToolUse == nil {
|
||||
dstAnthropic.DisableParallelToolUse = defaultAnthropic.DisableParallelToolUse
|
||||
}
|
||||
|
||||
case fantasygoogle.Name:
|
||||
if defaults.Google == nil {
|
||||
continue
|
||||
}
|
||||
if current.Google == nil {
|
||||
copied := *defaults.Google
|
||||
current.Google = &copied
|
||||
continue
|
||||
}
|
||||
dstGoogle := current.Google
|
||||
defaultGoogle := defaults.Google
|
||||
if dstGoogle.ThinkingConfig == nil {
|
||||
dstGoogle.ThinkingConfig = defaultGoogle.ThinkingConfig
|
||||
} else if defaultGoogle.ThinkingConfig != nil {
|
||||
if dstGoogle.ThinkingConfig.ThinkingBudget == nil {
|
||||
dstGoogle.ThinkingConfig.ThinkingBudget = defaultGoogle.ThinkingConfig.ThinkingBudget
|
||||
}
|
||||
if dstGoogle.ThinkingConfig.IncludeThoughts == nil {
|
||||
dstGoogle.ThinkingConfig.IncludeThoughts = defaultGoogle.ThinkingConfig.IncludeThoughts
|
||||
}
|
||||
}
|
||||
if strings.TrimSpace(dstGoogle.CachedContent) == "" {
|
||||
dstGoogle.CachedContent = defaultGoogle.CachedContent
|
||||
}
|
||||
if dstGoogle.SafetySettings == nil {
|
||||
dstGoogle.SafetySettings = defaultGoogle.SafetySettings
|
||||
}
|
||||
if strings.TrimSpace(dstGoogle.Threshold) == "" {
|
||||
dstGoogle.Threshold = defaultGoogle.Threshold
|
||||
}
|
||||
|
||||
case fantasyopenaicompat.Name:
|
||||
if defaults.OpenAICompat == nil {
|
||||
continue
|
||||
}
|
||||
if current.OpenAICompat == nil {
|
||||
copied := *defaults.OpenAICompat
|
||||
current.OpenAICompat = &copied
|
||||
continue
|
||||
}
|
||||
dstCompat := current.OpenAICompat
|
||||
defaultCompat := defaults.OpenAICompat
|
||||
if dstCompat.User == nil {
|
||||
dstCompat.User = defaultCompat.User
|
||||
}
|
||||
if dstCompat.ReasoningEffort == nil {
|
||||
dstCompat.ReasoningEffort = defaultCompat.ReasoningEffort
|
||||
}
|
||||
|
||||
case fantasyopenrouter.Name:
|
||||
if defaults.OpenRouter == nil {
|
||||
continue
|
||||
}
|
||||
if current.OpenRouter == nil {
|
||||
copied := *defaults.OpenRouter
|
||||
current.OpenRouter = &copied
|
||||
continue
|
||||
}
|
||||
dstRouter := current.OpenRouter
|
||||
defaultRouter := defaults.OpenRouter
|
||||
if dstRouter.Reasoning == nil {
|
||||
dstRouter.Reasoning = defaultRouter.Reasoning
|
||||
} else if defaultRouter.Reasoning != nil {
|
||||
if dstRouter.Reasoning.Enabled == nil {
|
||||
dstRouter.Reasoning.Enabled = defaultRouter.Reasoning.Enabled
|
||||
}
|
||||
if dstRouter.Reasoning.Exclude == nil {
|
||||
dstRouter.Reasoning.Exclude = defaultRouter.Reasoning.Exclude
|
||||
}
|
||||
if dstRouter.Reasoning.MaxTokens == nil {
|
||||
dstRouter.Reasoning.MaxTokens = defaultRouter.Reasoning.MaxTokens
|
||||
}
|
||||
if dstRouter.Reasoning.Effort == nil {
|
||||
dstRouter.Reasoning.Effort = defaultRouter.Reasoning.Effort
|
||||
}
|
||||
}
|
||||
if dstRouter.ExtraBody == nil {
|
||||
dstRouter.ExtraBody = defaultRouter.ExtraBody
|
||||
}
|
||||
if dstRouter.IncludeUsage == nil {
|
||||
dstRouter.IncludeUsage = defaultRouter.IncludeUsage
|
||||
}
|
||||
if dstRouter.LogitBias == nil {
|
||||
dstRouter.LogitBias = defaultRouter.LogitBias
|
||||
}
|
||||
if dstRouter.LogProbs == nil {
|
||||
dstRouter.LogProbs = defaultRouter.LogProbs
|
||||
}
|
||||
if dstRouter.ParallelToolCalls == nil {
|
||||
dstRouter.ParallelToolCalls = defaultRouter.ParallelToolCalls
|
||||
}
|
||||
if dstRouter.User == nil {
|
||||
dstRouter.User = defaultRouter.User
|
||||
}
|
||||
if dstRouter.Provider == nil {
|
||||
dstRouter.Provider = defaultRouter.Provider
|
||||
} else if defaultRouter.Provider != nil {
|
||||
if dstRouter.Provider.Order == nil {
|
||||
dstRouter.Provider.Order = defaultRouter.Provider.Order
|
||||
}
|
||||
if dstRouter.Provider.AllowFallbacks == nil {
|
||||
dstRouter.Provider.AllowFallbacks = defaultRouter.Provider.AllowFallbacks
|
||||
}
|
||||
if dstRouter.Provider.RequireParameters == nil {
|
||||
dstRouter.Provider.RequireParameters = defaultRouter.Provider.RequireParameters
|
||||
}
|
||||
if dstRouter.Provider.DataCollection == nil {
|
||||
dstRouter.Provider.DataCollection = defaultRouter.Provider.DataCollection
|
||||
}
|
||||
if dstRouter.Provider.Only == nil {
|
||||
dstRouter.Provider.Only = defaultRouter.Provider.Only
|
||||
}
|
||||
if dstRouter.Provider.Ignore == nil {
|
||||
dstRouter.Provider.Ignore = defaultRouter.Provider.Ignore
|
||||
}
|
||||
if dstRouter.Provider.Quantizations == nil {
|
||||
dstRouter.Provider.Quantizations = defaultRouter.Provider.Quantizations
|
||||
}
|
||||
if dstRouter.Provider.Sort == nil {
|
||||
dstRouter.Provider.Sort = defaultRouter.Provider.Sort
|
||||
}
|
||||
}
|
||||
|
||||
case fantasyvercel.Name:
|
||||
if defaults.Vercel == nil {
|
||||
continue
|
||||
}
|
||||
if current.Vercel == nil {
|
||||
copied := *defaults.Vercel
|
||||
current.Vercel = &copied
|
||||
continue
|
||||
}
|
||||
dstVercel := current.Vercel
|
||||
defaultVercel := defaults.Vercel
|
||||
if dstVercel.Reasoning == nil {
|
||||
dstVercel.Reasoning = defaultVercel.Reasoning
|
||||
} else if defaultVercel.Reasoning != nil {
|
||||
if dstVercel.Reasoning.Enabled == nil {
|
||||
dstVercel.Reasoning.Enabled = defaultVercel.Reasoning.Enabled
|
||||
}
|
||||
if dstVercel.Reasoning.MaxTokens == nil {
|
||||
dstVercel.Reasoning.MaxTokens = defaultVercel.Reasoning.MaxTokens
|
||||
}
|
||||
if dstVercel.Reasoning.Effort == nil {
|
||||
dstVercel.Reasoning.Effort = defaultVercel.Reasoning.Effort
|
||||
}
|
||||
if dstVercel.Reasoning.Exclude == nil {
|
||||
dstVercel.Reasoning.Exclude = defaultVercel.Reasoning.Exclude
|
||||
}
|
||||
}
|
||||
if dstVercel.ProviderOptions == nil {
|
||||
dstVercel.ProviderOptions = defaultVercel.ProviderOptions
|
||||
} else if defaultVercel.ProviderOptions != nil {
|
||||
if dstVercel.ProviderOptions.Order == nil {
|
||||
dstVercel.ProviderOptions.Order = defaultVercel.ProviderOptions.Order
|
||||
}
|
||||
if dstVercel.ProviderOptions.Models == nil {
|
||||
dstVercel.ProviderOptions.Models = defaultVercel.ProviderOptions.Models
|
||||
}
|
||||
}
|
||||
if dstVercel.User == nil {
|
||||
dstVercel.User = defaultVercel.User
|
||||
}
|
||||
if dstVercel.LogitBias == nil {
|
||||
dstVercel.LogitBias = defaultVercel.LogitBias
|
||||
}
|
||||
if dstVercel.LogProbs == nil {
|
||||
dstVercel.LogProbs = defaultVercel.LogProbs
|
||||
}
|
||||
if dstVercel.TopLogProbs == nil {
|
||||
dstVercel.TopLogProbs = defaultVercel.TopLogProbs
|
||||
}
|
||||
if dstVercel.ParallelToolCalls == nil {
|
||||
dstVercel.ParallelToolCalls = defaultVercel.ParallelToolCalls
|
||||
}
|
||||
if dstVercel.ExtraBody == nil {
|
||||
dstVercel.ExtraBody = defaultVercel.ExtraBody
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ModelFromConfig resolves a provider/model pair and constructs a fantasy
|
||||
// language model client using the provided provider credentials.
|
||||
func ModelFromConfig(
|
||||
|
||||
@@ -10,6 +10,7 @@ import (
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/coder/coder/v2/coderd/chatd/chatprovider"
|
||||
"github.com/coder/coder/v2/codersdk"
|
||||
)
|
||||
|
||||
func TestReasoningEffortFromChat(t *testing.T) {
|
||||
@@ -76,6 +77,115 @@ func TestReasoningEffortFromChat(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestMergeMissingProviderOptions_OpenRouterNested(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
options := &codersdk.ChatModelProviderOptions{
|
||||
OpenRouter: &codersdk.ChatModelOpenRouterProviderOptions{
|
||||
Reasoning: &codersdk.ChatModelOpenRouterReasoningOptions{
|
||||
Enabled: boolPtr(true),
|
||||
},
|
||||
Provider: &codersdk.ChatModelOpenRouterProvider{
|
||||
Order: []string{"openai"},
|
||||
},
|
||||
},
|
||||
}
|
||||
defaults := &codersdk.ChatModelProviderOptions{
|
||||
OpenRouter: &codersdk.ChatModelOpenRouterProviderOptions{
|
||||
Reasoning: &codersdk.ChatModelOpenRouterReasoningOptions{
|
||||
Enabled: boolPtr(false),
|
||||
Exclude: boolPtr(true),
|
||||
MaxTokens: int64Ptr(123),
|
||||
Effort: stringPtr("high"),
|
||||
},
|
||||
IncludeUsage: boolPtr(true),
|
||||
Provider: &codersdk.ChatModelOpenRouterProvider{
|
||||
Order: []string{"anthropic"},
|
||||
AllowFallbacks: boolPtr(true),
|
||||
RequireParameters: boolPtr(false),
|
||||
DataCollection: stringPtr("allow"),
|
||||
Only: []string{"openai"},
|
||||
Ignore: []string{"foo"},
|
||||
Quantizations: []string{"int8"},
|
||||
Sort: stringPtr("latency"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
chatprovider.MergeMissingProviderOptions(&options, defaults)
|
||||
|
||||
require.NotNil(t, options)
|
||||
require.NotNil(t, options.OpenRouter)
|
||||
require.NotNil(t, options.OpenRouter.Reasoning)
|
||||
require.True(t, *options.OpenRouter.Reasoning.Enabled)
|
||||
require.Equal(t, true, *options.OpenRouter.Reasoning.Exclude)
|
||||
require.EqualValues(t, 123, *options.OpenRouter.Reasoning.MaxTokens)
|
||||
require.Equal(t, "high", *options.OpenRouter.Reasoning.Effort)
|
||||
require.NotNil(t, options.OpenRouter.IncludeUsage)
|
||||
require.True(t, *options.OpenRouter.IncludeUsage)
|
||||
|
||||
require.NotNil(t, options.OpenRouter.Provider)
|
||||
require.Equal(t, []string{"openai"}, options.OpenRouter.Provider.Order)
|
||||
require.NotNil(t, options.OpenRouter.Provider.AllowFallbacks)
|
||||
require.True(t, *options.OpenRouter.Provider.AllowFallbacks)
|
||||
require.NotNil(t, options.OpenRouter.Provider.RequireParameters)
|
||||
require.False(t, *options.OpenRouter.Provider.RequireParameters)
|
||||
require.Equal(t, "allow", *options.OpenRouter.Provider.DataCollection)
|
||||
require.Equal(t, []string{"openai"}, options.OpenRouter.Provider.Only)
|
||||
require.Equal(t, []string{"foo"}, options.OpenRouter.Provider.Ignore)
|
||||
require.Equal(t, []string{"int8"}, options.OpenRouter.Provider.Quantizations)
|
||||
require.Equal(t, "latency", *options.OpenRouter.Provider.Sort)
|
||||
}
|
||||
|
||||
func TestMergeMissingCallConfig_FillsUnsetFields(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
dst := codersdk.ChatModelCallConfig{
|
||||
Temperature: float64Ptr(0.2),
|
||||
ProviderOptions: &codersdk.ChatModelProviderOptions{
|
||||
OpenAI: &codersdk.ChatModelOpenAIProviderOptions{
|
||||
User: stringPtr("alice"),
|
||||
},
|
||||
},
|
||||
}
|
||||
defaults := codersdk.ChatModelCallConfig{
|
||||
MaxOutputTokens: int64Ptr(512),
|
||||
Temperature: float64Ptr(0.9),
|
||||
TopP: float64Ptr(0.8),
|
||||
ProviderOptions: &codersdk.ChatModelProviderOptions{
|
||||
OpenAI: &codersdk.ChatModelOpenAIProviderOptions{
|
||||
User: stringPtr("bob"),
|
||||
ReasoningEffort: stringPtr("medium"),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
chatprovider.MergeMissingCallConfig(&dst, defaults)
|
||||
|
||||
require.NotNil(t, dst.MaxOutputTokens)
|
||||
require.EqualValues(t, 512, *dst.MaxOutputTokens)
|
||||
require.NotNil(t, dst.Temperature)
|
||||
require.Equal(t, 0.2, *dst.Temperature)
|
||||
require.NotNil(t, dst.TopP)
|
||||
require.Equal(t, 0.8, *dst.TopP)
|
||||
require.NotNil(t, dst.ProviderOptions)
|
||||
require.NotNil(t, dst.ProviderOptions.OpenAI)
|
||||
require.Equal(t, "alice", *dst.ProviderOptions.OpenAI.User)
|
||||
require.Equal(t, "medium", *dst.ProviderOptions.OpenAI.ReasoningEffort)
|
||||
}
|
||||
|
||||
func stringPtr(value string) *string {
|
||||
return &value
|
||||
}
|
||||
|
||||
func boolPtr(value bool) *bool {
|
||||
return &value
|
||||
}
|
||||
|
||||
func int64Ptr(value int64) *int64 {
|
||||
return &value
|
||||
}
|
||||
|
||||
func float64Ptr(value float64) *float64 {
|
||||
return &value
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user