mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-12 20:15:42 +00:00
- Add providerTypeOf() to extract provider_type via type assertion (e.g. "chatgpt_oauth") instead of config name (user-set "openai") - Exclude "compat" providers (openai_compat → OpenRouter/DeepSeek/Groq) from strict mode and SOUL echo — they proxy to non-OpenAI models - Fix isOpenAIStrict matching openai_compat incorrectly
106 lines
3.5 KiB
Go
106 lines
3.5 KiB
Go
package providers
|
|
|
|
import "strings"
|
|
|
|
// SchemaProfile controls which normalizations apply to a provider's tool schemas.
|
|
// Add new fields here to introduce additional transforms; implement them in
|
|
// schema_normalize.go and wire them in NormalizeSchema.
|
|
type SchemaProfile struct {
|
|
ResolveRefs bool // inline $ref from $defs/definitions
|
|
FlattenUnions bool // merge anyOf/oneOf → single object
|
|
InjectObjectType bool // add type:"object" when missing but has properties/required
|
|
ConvertConst bool // const → enum (Gemini requires enum, not const)
|
|
StripNullType bool // anyOf:[T, null] → T
|
|
RemoveTypeOnUnion bool // strip "type" when anyOf/oneOf present (Gemini conflict)
|
|
StripKeys []string // keys to recursively remove
|
|
StrictToolMode bool // OpenAI strict mode: optional→nullable, all props required, additionalProperties:false
|
|
}
|
|
|
|
// Provider-specific strip key lists.
|
|
var (
|
|
geminiStripKeys = []string{
|
|
"$ref", "$defs", "definitions", "additionalProperties",
|
|
"patternProperties", "$schema", "$id",
|
|
"examples", "default",
|
|
"minLength", "maxLength", "minimum", "maximum", "multipleOf",
|
|
"pattern", "format",
|
|
"minItems", "maxItems", "uniqueItems",
|
|
"minProperties", "maxProperties",
|
|
}
|
|
xaiStripKeys = []string{
|
|
"minLength", "maxLength",
|
|
"minItems", "maxItems",
|
|
"minContains", "maxContains",
|
|
}
|
|
refOnlyStripKeys = []string{"$ref", "$defs", "definitions"}
|
|
)
|
|
|
|
// profileForProvider returns the normalization profile for a provider.
|
|
// Unknown providers get a safe default (resolve + flatten + inject type).
|
|
func profileForProvider(name string) SchemaProfile {
|
|
switch {
|
|
case name == "anthropic":
|
|
return SchemaProfile{
|
|
ResolveRefs: true,
|
|
StripKeys: refOnlyStripKeys,
|
|
}
|
|
case isGeminiName(name):
|
|
return SchemaProfile{
|
|
ResolveRefs: true,
|
|
FlattenUnions: true,
|
|
ConvertConst: true,
|
|
StripNullType: true,
|
|
RemoveTypeOnUnion: true,
|
|
StripKeys: geminiStripKeys,
|
|
}
|
|
case name == "xai" || strings.HasPrefix(name, "xai-"):
|
|
return SchemaProfile{
|
|
ResolveRefs: true,
|
|
FlattenUnions: true,
|
|
InjectObjectType: true,
|
|
StripKeys: xaiStripKeys,
|
|
}
|
|
case isOpenAIStrict(name):
|
|
return SchemaProfile{
|
|
ResolveRefs: true,
|
|
FlattenUnions: true,
|
|
InjectObjectType: true,
|
|
StrictToolMode: true,
|
|
StripKeys: refOnlyStripKeys,
|
|
}
|
|
default: // openrouter, deepseek, groq, dashscope, bailian, minimax, etc.
|
|
return SchemaProfile{
|
|
ResolveRefs: true,
|
|
FlattenUnions: true,
|
|
InjectObjectType: true,
|
|
StripKeys: refOnlyStripKeys,
|
|
}
|
|
}
|
|
}
|
|
|
|
// isOpenAIStrict returns true for providers known to support strict tool mode.
|
|
// Matches first-party OpenAI (including chatgpt_oauth) and Codex.
|
|
// Explicitly excludes openai_compat (proxy for OpenRouter, DeepSeek, Groq, etc.).
|
|
func isOpenAIStrict(name string) bool {
|
|
lower := strings.ToLower(name)
|
|
// Exclude compat/proxy providers first — they route to non-OpenAI models.
|
|
if strings.Contains(lower, "compat") {
|
|
return false
|
|
}
|
|
switch {
|
|
case lower == "openai" || lower == "codex":
|
|
return true
|
|
case strings.Contains(lower, "chatgpt"):
|
|
return true // chatgpt_oauth, chatgpt_plus, etc.
|
|
}
|
|
return false
|
|
}
|
|
|
|
// isGeminiName matches config names ("gemini", "gemini-flash") and
|
|
// DB provider types ("gemini_native"). Uses Contains for robustness
|
|
// with user-defined names (e.g. "my-gemini-proxy").
|
|
func isGeminiName(name string) bool {
|
|
lower := strings.ToLower(name)
|
|
return strings.Contains(lower, "gemini")
|
|
}
|