Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion catalog/live_enrich.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@
return nil, fmt.Errorf("catalog: provider %q has no live model list API", providerID)
}
env = registry.ScopedProviderEnv(spec, env)
if !registry.CredentialPresent(spec, env) {
if !spec.PublicModelCatalog && !registry.CredentialPresent(spec, env) {
return nil, fmt.Errorf("catalog: set %s for %s", spec.CredentialEnv, providerID)
}
entries, err := live.Fetch(spec.LiveFetcherKey, env)
Expand All @@ -137,6 +137,6 @@
}

// LiveDiscoverableDeploymentIDs returns provider IDs that have live model-list APIs.
func LiveDiscoverableDeploymentIDs() []string {

Check failure on line 140 in catalog/live_enrich.go

View workflow job for this annotation

GitHub Actions / deadcode

unreachable func: LiveDiscoverableDeploymentIDs
return registry.LiveFetcherKeys()
}
46 changes: 23 additions & 23 deletions catalog/registry/providers.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func providerSpecs() []ProviderSpec {
return []ProviderSpec{
// ── Direct API providers ──────────────────────────────────────────
{
ProviderID: "anthropic", DisplayName: "Anthropic", DeploymentID: "anthropic-direct", SortOrder: 1, ChatPreference: 2,
ProviderID: "anthropic", DisplayName: "Anthropic", DeploymentID: "anthropic-direct", SortOrder: 3, ChatPreference: 2,
TransportKind: "anthropic",
RequiresKey: true, CredentialEnv: "ANTHROPIC_API_KEY",
CredentialAliases: []string{"CLAUDE_API_KEY"},
Expand All @@ -28,7 +28,7 @@ func providerSpecs() []ProviderSpec {
DirectFallbacks: []string{"openai"},
},
{
ProviderID: "openai", DisplayName: "OpenAI", DeploymentID: "openai-direct", SortOrder: 2, ChatPreference: 1,
ProviderID: "openai", DisplayName: "OpenAI", DeploymentID: "openai-direct", SortOrder: 15, ChatPreference: 1,
TransportKind: "openai",
RequiresKey: true, CredentialEnv: "OPENAI_API_KEY",
BaseURLEnv: []string{"OPENAI_BASE_URL", "OPENAI_API_BASE"},
Expand All @@ -38,7 +38,7 @@ func providerSpecs() []ProviderSpec {
DirectFallbacks: []string{"anthropic"},
},
{
ProviderID: "gemini", DisplayName: "Gemini API", DeploymentID: "gemini-direct", SortOrder: 3, ChatPreference: 5,
ProviderID: "gemini", DisplayName: "Gemini API", DeploymentID: "gemini-direct", SortOrder: 9, ChatPreference: 5,
RuntimeBaseURL: "https://generativelanguage.googleapis.com/v1beta/openai",
RequiresKey: true, CredentialEnv: "GEMINI_API_KEY",
CredentialAliases: []string{"GOOGLE_API_KEY"},
Expand All @@ -48,31 +48,31 @@ func providerSpecs() []ProviderSpec {
ProtocolID: "gemini-generate-content", AdapterID: "gemini", RuntimeProfileKey: "gemini",
},
{
ProviderID: "deepseek", DisplayName: "DeepSeek", DeploymentID: "deepseek-direct", SortOrder: 4, ChatPreference: 11,
ProviderID: "deepseek", DisplayName: "DeepSeek", DeploymentID: "deepseek-direct", SortOrder: 8, ChatPreference: 11,
RequiresKey: true, CredentialEnv: "DEEPSEEK_API_KEY",
BaseURLEnv: []string{"DEEPSEEK_BASE_URL"},
ProbeKind: ProbeOpenAIModels, ProbeBaseURL: "https://api.deepseek.com/v1",
LiveFetcherKey: "deepseek", LiveCatalogKey: "deepseek",
ProtocolID: "openai-chat-completions", AdapterID: "deepseek", RuntimeProfileKey: "deepseek",
},
{
ProviderID: "grok", DisplayName: "xAI", DeploymentID: "grok-direct", SortOrder: 5, ChatPreference: 4,
ProviderID: "grok", DisplayName: "xAI", DeploymentID: "grok-direct", SortOrder: 21, ChatPreference: 4,
RequiresKey: true, CredentialEnv: "XAI_API_KEY",
BaseURLEnv: []string{"XAI_BASE_URL"},
ProbeKind: ProbeOpenAIModels, ProbeBaseURL: "https://api.x.ai/v1",
LiveFetcherKey: "grok", LiveCatalogKey: "grok",
ProtocolID: "openai-chat-completions", AdapterID: "grok", RuntimeProfileKey: "grok",
},
{
ProviderID: "kimi", DisplayName: "Kimi", DeploymentID: "kimi-direct", SortOrder: 6, ChatPreference: 14,
ProviderID: "kimi", DisplayName: "Kimi", DeploymentID: "kimi-direct", SortOrder: 11, ChatPreference: 14,
RequiresKey: true, CredentialEnv: "MOONSHOT_API_KEY",
BaseURLEnv: []string{"MOONSHOT_BASE_URL"},
ProbeKind: ProbeOpenAIModels, ProbeBaseURL: "https://api.moonshot.ai/v1",
LiveFetcherKey: "kimi", LiveCatalogKey: "kimi",
ProtocolID: "openai-chat-completions", AdapterID: "kimi", RuntimeProfileKey: "kimi",
},
{
ProviderID: "zai_coding", DisplayName: "Z.AI — Coding Plan", DeploymentID: "zai_coding-direct", SortOrder: 7, ChatPreference: 8,
ProviderID: "zai_coding", DisplayName: "Z.AI — Coding Plan", DeploymentID: "zai_coding-direct", SortOrder: 24, ChatPreference: 8,
RequiresKey: true, CredentialEnv: "ZAI_CODING_API_KEY",
BaseURLEnv: []string{"ZAI_CODING_BASE_URL", "ZAI_BASE_URL"},
ProbeKind: ProbeOpenAIModels, ProbeBaseURL: "https://api.z.ai/api/coding/paas/v4",
Expand All @@ -81,7 +81,7 @@ func providerSpecs() []ProviderSpec {
PrepareCredentialEnv: true,
},
{
ProviderID: "zai_payg", DisplayName: "Z.AI — Pay-as-you-go", DeploymentID: "zai_payg-direct", SortOrder: 8, ChatPreference: 9,
ProviderID: "zai_payg", DisplayName: "Z.AI — Pay-as-you-go", DeploymentID: "zai_payg-direct", SortOrder: 25, ChatPreference: 9,
RequiresKey: true, CredentialEnv: "ZAI_API_KEY",
BaseURLEnv: []string{"ZAI_BASE_URL", "ZAI_API_BASE"},
ProbeKind: ProbeOpenAIModels, ProbeBaseURL: "https://api.z.ai/api/paas/v4",
Expand All @@ -90,7 +90,7 @@ func providerSpecs() []ProviderSpec {
PrepareCredentialEnv: true,
},
{
ProviderID: "xiaomi_mimo_token_plan", DisplayName: "Xiaomi MiMo — Token Plan", DeploymentID: "xiaomi_mimo_token_plan-direct", SortOrder: 9, ChatPreference: 16,
ProviderID: "xiaomi_mimo_token_plan", DisplayName: "Xiaomi MiMo — Token Plan", DeploymentID: "xiaomi_mimo_token_plan-direct", SortOrder: 23, ChatPreference: 16,
RequiresKey: true, CredentialEnv: "XIAOMI_MIMO_TOKEN_PLAN_API_KEY",
BaseURLEnv: []string{"XIAOMI_MIMO_TOKEN_PLAN_BASE_URL"},
ProbeKind: ProbeOpenAIModels, ProbeBaseURL: "",
Expand All @@ -99,7 +99,7 @@ func providerSpecs() []ProviderSpec {
PrepareCredentialEnv: true,
},
{
ProviderID: "xiaomi_mimo_payg", DisplayName: "Xiaomi MiMo — Pay-as-you-go", DeploymentID: "xiaomi_mimo_payg-direct", SortOrder: 10, ChatPreference: 15,
ProviderID: "xiaomi_mimo_payg", DisplayName: "Xiaomi MiMo — Pay-as-you-go", DeploymentID: "xiaomi_mimo_payg-direct", SortOrder: 22, ChatPreference: 15,
RequiresKey: true, CredentialEnv: "XIAOMI_MIMO_PAYG_API_KEY",
CredentialAliases: []string{"XIAOMI_MIMO_API_KEY"},
BaseURLEnv: []string{"XIAOMI_MIMO_PAYG_BASE_URL", "XIAOMI_BASE_URL"},
Expand All @@ -108,15 +108,15 @@ func providerSpecs() []ProviderSpec {
ProtocolID: "openai-chat-completions", AdapterID: "xiaomi_mimo", RuntimeProfileKey: "xiaomi_mimo_payg",
},
{
ProviderID: "minimax_token_plan", DisplayName: "MiniMax — Token Plan", DeploymentID: "minimax_token_plan-direct", SortOrder: 11, ChatPreference: 17,
ProviderID: "minimax_token_plan", DisplayName: "MiniMax — Token Plan", DeploymentID: "minimax_token_plan-direct", SortOrder: 14, ChatPreference: 17,
RequiresKey: true, CredentialEnv: "MINIMAX_TOKEN_PLAN_API_KEY",
BaseURLEnv: []string{"MINIMAX_TOKEN_PLAN_BASE_URL"},
ProbeKind: ProbeOpenAIModels, ProbeBaseURL: "https://api.minimax.io/v1",
LiveFetcherKey: "minimax_token_plan", LiveCatalogKey: "minimax_token_plan",
ProtocolID: "openai-chat-completions", AdapterID: "openai", RuntimeProfileKey: "minimax_token_plan",
},
{
ProviderID: "minimax_payg", DisplayName: "MiniMax — Pay-as-you-go", DeploymentID: "minimax_payg-direct", SortOrder: 12, ChatPreference: 18,
ProviderID: "minimax_payg", DisplayName: "MiniMax — Pay-as-you-go", DeploymentID: "minimax_payg-direct", SortOrder: 13, ChatPreference: 18,
RequiresKey: true, CredentialEnv: "MINIMAX_PAYG_API_KEY",
BaseURLEnv: []string{"MINIMAX_PAYG_BASE_URL", "MINIMAX_BASE_URL"},
ProbeKind: ProbeOpenAIModels, ProbeBaseURL: "https://api.minimax.io/v1",
Expand All @@ -126,7 +126,7 @@ func providerSpecs() []ProviderSpec {

// ── Cloud platform providers ──────────────────────────────────────
{
ProviderID: "azure", DisplayName: "Azure OpenAI", DeploymentID: "openai-azure", SortOrder: 13, ChatPreference: 12,
ProviderID: "azure", DisplayName: "Azure OpenAI", DeploymentID: "openai-azure", SortOrder: 4, ChatPreference: 12,
TransportKind: "azure",
RequiresKey: true, CredentialEnv: "AZURE_OPENAI_API_KEY",
BaseURLEnv: []string{"AZURE_OPENAI_ENDPOINT"},
Expand All @@ -135,7 +135,7 @@ func providerSpecs() []ProviderSpec {
ProtocolID: "openai-chat-completions", AdapterID: "openai-azure", RuntimeProfileKey: "azure",
},
{
ProviderID: "bedrock", DisplayName: "Amazon Bedrock", DeploymentID: "anthropic-bedrock", SortOrder: 14, ChatPreference: 7,
ProviderID: "bedrock", DisplayName: "Amazon Bedrock", DeploymentID: "anthropic-bedrock", SortOrder: 2, ChatPreference: 7,
TransportKind: "bedrock",
RequiresKey: true, CredentialEnv: "AWS_SECRET_ACCESS_KEY",
CredentialEnvFallbacks: []string{"AWS_ACCESS_KEY_ID", "AWS_SESSION_TOKEN"},
Expand All @@ -145,7 +145,7 @@ func providerSpecs() []ProviderSpec {
ProtocolID: "anthropic-messages", AdapterID: "anthropic-bedrock", RuntimeProfileKey: "bedrock",
},
{
ProviderID: "vertex", DisplayName: "Vertex AI", DeploymentID: "gemini-vertex", SortOrder: 15, ChatPreference: 6,
ProviderID: "vertex", DisplayName: "Vertex AI", DeploymentID: "gemini-vertex", SortOrder: 20, ChatPreference: 6,
TransportKind: "vertex",
RequiresKey: true, CredentialEnv: "VERTEX_ACCESS_TOKEN",
CredentialEnvFallbacks: []string{"GOOGLE_OAUTH_ACCESS_TOKEN"},
Expand All @@ -157,7 +157,7 @@ func providerSpecs() []ProviderSpec {

// ── Aggregators ───────────────────────────────────────────────────
{
ProviderID: "openrouter", DisplayName: "OpenRouter", DeploymentID: "openrouter", SortOrder: 16, ChatPreference: 3,
ProviderID: "openrouter", DisplayName: "OpenRouter", DeploymentID: "openrouter", SortOrder: 17, ChatPreference: 3,
RequiresKey: true, CredentialEnv: "OPENROUTER_API_KEY",
BaseURLEnv: []string{"OPENROUTER_BASE_URL"},
ProbeKind: ProbeOpenAIModels, ProbeBaseURL: "https://openrouter.ai/api/v1",
Expand All @@ -174,7 +174,7 @@ func providerSpecs() []ProviderSpec {
ProtocolID: "openai-responses", AdapterID: "concentrate-responses", RuntimeProfileKey: "concentrate",
},
{
ProviderID: "stepfun", DisplayName: "StepFun", DeploymentID: "stepfun-direct", SortOrder: 2, ChatPreference: 27,
ProviderID: "stepfun", DisplayName: "StepFun", DeploymentID: "stepfun-direct", SortOrder: 26, ChatPreference: 27,
RequiresKey: true, CredentialEnv: "STEP_API_KEY",
BaseURLEnv: []string{"STEP_BASE_URL"},
ProbeKind: ProbeOpenAIModels, ProbeBaseURL: "https://api.stepfun.ai/v1",
Expand All @@ -200,31 +200,31 @@ func providerSpecs() []ProviderSpec {

// ── Niche ─────────────────────────────────────────────────────────
{
ProviderID: "canopywave", DisplayName: "CanopyWave", DeploymentID: "canopywave", SortOrder: 17, ChatPreference: 10,
ProviderID: "canopywave", DisplayName: "CanopyWave", DeploymentID: "canopywave", SortOrder: 5, ChatPreference: 10,
RequiresKey: true, CredentialEnv: "CANOPYWAVE_API_KEY",
BaseURLEnv: []string{"CANOPYWAVE_BASE_URL"},
ProbeKind: ProbeOpenAIModels, ProbeBaseURL: "https://inference.canopywave.io/v1",
LiveFetcherKey: "canopywave", LiveCatalogKey: "canopywave",
ProtocolID: "openai-chat-completions", AdapterID: "canopywave", RuntimeProfileKey: "canopywave",
},
{
ProviderID: "poolside", DisplayName: "Poolside", DeploymentID: "poolside", SortOrder: 18, ChatPreference: 20,
ProviderID: "poolside", DisplayName: "Poolside", DeploymentID: "poolside", SortOrder: 19, ChatPreference: 20,
RequiresKey: true, CredentialEnv: "POOLSIDE_API_KEY",
BaseURLEnv: []string{"POOLSIDE_BASE_URL"},
ProbeKind: ProbeOpenAIModels, ProbeBaseURL: "https://inference.poolside.ai/v1",
LiveFetcherKey: "poolside", LiveCatalogKey: "poolside",
ProtocolID: "openai-chat-completions", AdapterID: "poolside", RuntimeProfileKey: "poolside",
},
{
ProviderID: "groq", DisplayName: "Groq", DeploymentID: "groq-direct", SortOrder: 19, ChatPreference: 21,
ProviderID: "groq", DisplayName: "Groq", DeploymentID: "groq-direct", SortOrder: 10, ChatPreference: 21,
RequiresKey: true, CredentialEnv: "GROQ_API_KEY",
BaseURLEnv: []string{"GROQ_BASE_URL"},
ProbeKind: ProbeOpenAIModels, ProbeBaseURL: "https://api.groq.com/openai/v1",
LiveFetcherKey: "groq", LiveCatalogKey: "groq",
ProtocolID: "openai-chat-completions", AdapterID: "groq", RuntimeProfileKey: "groq",
},
{
ProviderID: "clinepass", DisplayName: "ClinePass", DeploymentID: "clinepass", SortOrder: 20, ChatPreference: 22,
ProviderID: "clinepass", DisplayName: "ClinePass", DeploymentID: "clinepass", SortOrder: 6, ChatPreference: 22,
RuntimeBaseURL: "https://api.cline.bot/api/v1",
RequiresKey: true, CredentialEnv: "CLINE_API_KEY",
BaseURLEnv: []string{"CLINE_API_BASE"},
Expand All @@ -233,7 +233,7 @@ func providerSpecs() []ProviderSpec {
ProtocolID: "openai-chat-completions", AdapterID: "clinepass", RuntimeProfileKey: "clinepass",
},
{
ProviderID: "opencodego", DisplayName: "OpenCode Go", DeploymentID: "opencodego", SortOrder: 21, ChatPreference: 13,
ProviderID: "opencodego", DisplayName: "OpenCode Go", DeploymentID: "opencodego", SortOrder: 16, ChatPreference: 13,
RequiresKey: true, CredentialEnv: "OPENCODEGO_API_KEY",
BaseURLEnv: []string{"OPENCODEGO_BASE_URL"},
ProbeKind: ProbeOpenAIModels,
Expand All @@ -244,7 +244,7 @@ func providerSpecs() []ProviderSpec {

// ── Local ─────────────────────────────────────────────────────────
{
ProviderID: "ollama", DisplayName: "Ollama", DeploymentID: "ollama-local", SortOrder: 22, ChatPreference: 19,
ProviderID: "ollama", DisplayName: "Ollama", DeploymentID: "ollama-local", SortOrder: 18, ChatPreference: 19,
RuntimeBaseURL: "http://localhost:11434/v1", RuntimeCredentialEnv: "OLLAMA_API_KEY",
RequiresKey: false, CredentialEnv: "OLLAMA_BASE_URL",
BaseURLEnv: []string{"OLLAMA_BASE_URL"},
Expand Down
14 changes: 14 additions & 0 deletions catalog/zai/endpoints.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,20 @@ func ResolveOpenAIBase(plan Plan, region Region, override string) (string, error
}
}

// Anthropic-compatible bases (fallback for /v1/messages protocol).
const (
InternationalAnthropicBase = "https://api.z.ai/api/anthropic"
ChinaAnthropicBase = "https://open.bigmodel.cn/api/anthropic"
)

// ResolveAnthropicBase returns the correct Anthropic-compat base for the region.
func ResolveAnthropicBase(region Region) string {
if region == RegionChina {
return ChinaAnthropicBase
}
return InternationalAnthropicBase
}

// KeyMismatchHint (kept for future key prefix detection).
func KeyMismatchHint(plan Plan, secret string) string {
secret = strings.TrimSpace(secret)
Expand Down
8 changes: 7 additions & 1 deletion client/adapters/anthropic.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,13 @@ func resolveThinking(opts core.ChatOptions) *anthropicThinking {
}
return thinking
default:
// Legacy behavior: if budget > 0, enable with budget
// Legacy behavior: ThinkingEnabled toggle wins, else budget > 0 enables with budget.
if opts.ThinkingEnabled != nil {
if *opts.ThinkingEnabled {
return thinkingAdaptive()
}
return thinkingDisabled()
}
return thinkingForBudget(opts.ThinkingBudgetTokens)
}
}
Expand Down
39 changes: 36 additions & 3 deletions client/adapters/compat.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,14 @@ type OpenAICompatConfig struct {
// core.ChatOptions.KimiContextCacheID is non-empty, buildRequestBase prepends a
// {"role":"cache","content":<id>} message per the MoonshotAI-Cookbook spec.
SupportsCacheRole bool `json:"supports_cache_role,omitempty"`
// OmitMaxTokens suppresses the max_tokens field so the provider applies
// its own default. Useful for providers that pre-authorize the maximum
// token cost (e.g. Agnes AI).
OmitMaxTokens bool `json:"omit_max_tokens,omitempty"`
// DefaultDisableThinking sets thinking to disabled when no thinking
// preference is provided. Useful for providers that enable thinking
// by default but don't support it in all configurations.
DefaultDisableThinking bool `json:"default_disable_thinking,omitempty"`
}

// Per-provider compat configs.
Expand Down Expand Up @@ -66,11 +74,15 @@ var (
MaxTokensField: "max_tokens",
}
KimiCompat = OpenAICompatConfig{
MaxTokensField: "max_tokens",
SupportsCacheRole: true,
MaxTokensField: "max_tokens",
SupportsCacheRole: true,
ThinkingFormat: "kimi",
DefaultDisableThinking: true,
}
XiaomiCompat = OpenAICompatConfig{
MaxTokensField: "max_completion_tokens",
MaxTokensField: "max_completion_tokens",
ThinkingFormat: "xiaomi",
DefaultDisableThinking: true,
}
AzureCompat = OpenAICompatConfig{
MaxTokensField: "max_tokens",
Expand All @@ -81,12 +93,33 @@ var (
VertexCompat = OpenAICompatConfig{
MaxTokensField: "max_tokens",
}
// AgnesCompat: OpenAI-compatible; pre-authorizes max token cost, so omit max_tokens.
AgnesCompat = OpenAICompatConfig{
OmitMaxTokens: true,
ThinkingFormat: "agnes",
}
// LongCatCompat: OpenAI-compatible; enables thinking by default, so disable it.
LongCatCompat = OpenAICompatConfig{
MaxTokensField: "max_tokens",
ThinkingFormat: "longcat",
DefaultDisableThinking: true,
StripReasoningFromInput: true,
}
// MiniMaxCompat: OpenAI-compatible; enables thinking by default, so disable it.
MiniMaxCompat = OpenAICompatConfig{
MaxTokensField: "max_tokens",
ThinkingFormat: "minimax",
DefaultDisableThinking: true,
}
// DeepSeekCompat: OpenAI-compatible with usage in streaming.
// The provider rejects reasoning_content in input messages with HTTP 400, so we strip it.
// Enables thinking by default, so disable it.
DeepSeekCompat = OpenAICompatConfig{
MaxTokensField: "max_tokens",
SupportsUsageInStreaming: true,
StripReasoningFromInput: true,
ThinkingFormat: "deepseek",
DefaultDisableThinking: true,
}
)

Expand Down
8 changes: 4 additions & 4 deletions client/adapters/deepseek_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import (

func TestNewDeepSeekClient_OpenAIOnly(t *testing.T) {
t.Parallel()
client := NewDeepSeekClient("ds-key", "https://api.deepseek.com/v1", &DeepSeekCompat)
if client == nil || client.openai == nil {
client := NewDeepSeekClient("ds-key", "https://api.deepseek.com/v1", "", &DeepSeekCompat)
if client == nil || client.router.OpenAI == nil {
t.Fatal("expected OpenAI client")
}
if client.Name() != "deepseek" {
Expand All @@ -38,7 +38,7 @@ func TestDeepSeekClient_ChatUsesOpenAIPath(t *testing.T) {
}))
defer server.Close()

client := NewDeepSeekClient("key", server.URL, &DeepSeekCompat, core.WithRetry(core.NewRetryConfig(0, 0, 0)))
client := NewDeepSeekClient("key", server.URL, "", &DeepSeekCompat, core.WithRetry(core.NewRetryConfig(0, 0, 0)))
resp, err := client.Chat(context.Background(), []core.EyrieMessage{{Role: "user", Content: "hi"}}, core.ChatOptions{Model: "deepseek-v4-flash", MaxTokens: 16})
if err != nil {
t.Fatal(err)
Expand All @@ -58,7 +58,7 @@ func TestDeepSeekClient_Ping(t *testing.T) {
_, _ = io.WriteString(w, `{"data":[]}`)
}))
defer server.Close()
client := NewDeepSeekClient("key", server.URL, &DeepSeekCompat, core.WithTimeout(2*time.Second))
client := NewDeepSeekClient("key", server.URL, "", &DeepSeekCompat, core.WithTimeout(2*time.Second))
if err := client.Ping(context.Background()); err != nil {
t.Fatal(err)
}
Expand Down
6 changes: 6 additions & 0 deletions client/adapters/gemini_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"io"
"log/slog"
"net/http"
"os"
"strings"
Expand All @@ -13,6 +14,11 @@ import (
"github.com/GrayCodeAI/eyrie/types"
)

func testLogger(t *testing.T) *slog.Logger {
t.Helper()
return slog.New(slog.NewTextHandler(os.Stderr, &slog.HandlerOptions{Level: slog.LevelError}))
}

func TestNewGeminiClient(t *testing.T) {
t.Parallel()
c := NewGeminiClient("AIza-test", "https://custom.example/v1beta")
Expand Down
2 changes: 2 additions & 0 deletions client/adapters/openai_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -586,3 +586,5 @@ func TestOpenAIClient_BuildOpenAIRequest(t *testing.T) {
t.Error("expected non-nil body")
}
}

func float64Ptr(f float64) *float64 { return &f }
Loading
Loading