88 lines
3.3 KiB
Go
88 lines
3.3 KiB
Go
package model
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
|
|
"git.yeij.top/AskaEth/Cyrene_v2/internal/config"
|
|
)
|
|
|
|
// Provider names accepted by the provider-aware factory. These are the only two
|
|
// protocols the factory understands today; adding a vendor means adding a case
|
|
// here plus a matching adapter, not touching the rest of the package.
|
|
const (
|
|
// ProviderOpenAI selects the OpenAI-compatible /chat/completions protocol.
|
|
ProviderOpenAI = "openai"
|
|
// ProviderAnthropic selects the Anthropic Messages /v1/messages protocol.
|
|
ProviderAnthropic = "anthropic"
|
|
)
|
|
|
|
// ErrUnknownProvider is returned by the provider-aware factory when the
|
|
// configured provider name is not recognized.
|
|
var ErrUnknownProvider = errors.New("model: unknown provider")
|
|
|
|
// NewChatAdapter builds a single provider adapter selected by cfg.Provider. The
|
|
// empty provider defaults to openai for backward compatibility. An unrecognized
|
|
// provider returns ErrUnknownProvider.
|
|
func NewChatAdapter(cfg config.LLMConfig) (Adapter, error) {
|
|
switch cfg.Provider {
|
|
case ProviderOpenAI, "":
|
|
return NewOpenAIChat(cfg), nil
|
|
case ProviderAnthropic:
|
|
return NewAnthropicChat(cfg), nil
|
|
default:
|
|
return nil, fmt.Errorf("model: %w: provider %q", ErrUnknownProvider, cfg.Provider)
|
|
}
|
|
}
|
|
|
|
// NewChatChain builds a fallback Chain for the configured provider: the primary
|
|
// model first, then the provider's fallback model when set and distinct. Each
|
|
// step is served by an adapter of the selected protocol. The empty provider
|
|
// defaults to openai. An unrecognized provider returns ErrUnknownProvider.
|
|
func NewChatChain(cfg config.LLMConfig) (*Chain, error) {
|
|
switch cfg.Provider {
|
|
case ProviderOpenAI, "":
|
|
return newOpenAIChain(cfg)
|
|
case ProviderAnthropic:
|
|
return newAnthropicChain(cfg)
|
|
default:
|
|
return nil, fmt.Errorf("model: %w: provider %q", ErrUnknownProvider, cfg.Provider)
|
|
}
|
|
}
|
|
|
|
// newOpenAIChain builds a fallback chain from the OpenAI-compatible config block.
|
|
// Each step is an OpenAIChatAdapter against the configured endpoint.
|
|
func newOpenAIChain(cfg config.LLMConfig, opts ...OpenAIOption) (*Chain, error) {
|
|
if cfg.BaseURL == "" || cfg.Model == "" {
|
|
return nil, ErrNoModel
|
|
}
|
|
steps := []Step{{Model: cfg.Model, Adapter: NewOpenAIChat(cfg, opts...)}}
|
|
if cfg.Fallback != "" && cfg.Fallback != cfg.Model {
|
|
steps = append(steps, Step{Model: cfg.Fallback, Adapter: NewOpenAIChat(cfg, opts...)})
|
|
}
|
|
return NewChain(steps...), nil
|
|
}
|
|
|
|
// newAnthropicChain builds a fallback chain from the Anthropic config block. Each
|
|
// step is an AnthropicChatAdapter against the configured /v1/messages endpoint.
|
|
func newAnthropicChain(cfg config.LLMConfig) (*Chain, error) {
|
|
if cfg.AnthropicBaseURL == "" || cfg.AnthropicModel == "" {
|
|
return nil, ErrNoModel
|
|
}
|
|
steps := []Step{{Model: cfg.AnthropicModel, Adapter: NewAnthropicChat(cfg)}}
|
|
if cfg.AnthropicFallback != "" && cfg.AnthropicFallback != cfg.AnthropicModel {
|
|
steps = append(steps, Step{Model: cfg.AnthropicFallback, Adapter: NewAnthropicChat(cfg)})
|
|
}
|
|
return NewChain(steps...), nil
|
|
}
|
|
|
|
// DefaultModelForProvider returns the primary model name for the configured
|
|
// provider: the flat OpenAI Model for "openai", the Anthropic model for
|
|
// "anthropic". Used by callers (e.g. cmd/cyrene) to seed a Router's default.
|
|
func DefaultModelForProvider(cfg config.LLMConfig) string {
|
|
if cfg.Provider == ProviderAnthropic {
|
|
return cfg.AnthropicModel
|
|
}
|
|
return cfg.Model
|
|
}
|