2026-07-29 16:59:43 +00:00
|
|
|
// Package backend owns validated, immutable OpenAI-compatible backend
|
|
|
|
|
// definitions.
|
|
|
|
|
package backend
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"errors"
|
|
|
|
|
"fmt"
|
|
|
|
|
|
|
|
|
|
"gitea.maximumdirect.net/eric/promptkit/internal/domain"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
const (
|
2026-10-17 06:08:35 +00:00
|
|
|
// OpenRouterID is the conventional OpenRouter backend identifier.
|
2026-07-29 16:59:43 +00:00
|
|
|
OpenRouterID = "openrouter"
|
2026-10-17 06:08:35 +00:00
|
|
|
// RakestrawHomeID is the conventional Rakestrawhome backend identifier.
|
2026-08-23 17:10:34 +00:00
|
|
|
RakestrawHomeID = "rakestrawhome"
|
2026-07-29 16:59:43 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// ErrBackendNotFound identifies a registry lookup for an unknown backend ID.
|
|
|
|
|
var ErrBackendNotFound = errors.New("backend not found")
|
|
|
|
|
|
|
|
|
|
// Registry is an immutable collection of validated backend definitions.
|
|
|
|
|
type Registry struct {
|
|
|
|
|
backends map[string]domain.Backend
|
|
|
|
|
}
|
|
|
|
|
|
2026-09-30 02:32:54 +00:00
|
|
|
// NewEffectiveRegistry stores already-validated effective backend definitions
|
|
|
|
|
// under their exact configuration keys. Configuration validation and
|
|
|
|
|
// normalization precede this ownership boundary.
|
|
|
|
|
func NewEffectiveRegistry(definitions map[string]domain.Backend) (*Registry, error) {
|
|
|
|
|
registry := &Registry{backends: make(map[string]domain.Backend, len(definitions))}
|
|
|
|
|
for id, definition := range definitions {
|
2026-10-13 15:53:27 +00:00
|
|
|
definition.ID = id
|
|
|
|
|
cloned, err := domain.CloneBackend(definition)
|
2026-09-30 02:32:54 +00:00
|
|
|
if err != nil {
|
2026-10-13 15:53:27 +00:00
|
|
|
return nil, fmt.Errorf("backend %q: %w", id, err)
|
2026-09-30 02:32:54 +00:00
|
|
|
}
|
2026-10-13 15:53:27 +00:00
|
|
|
registry.backends[id] = cloned
|
2026-09-30 02:32:54 +00:00
|
|
|
}
|
|
|
|
|
return registry, nil
|
|
|
|
|
}
|
|
|
|
|
|
2026-07-29 16:59:43 +00:00
|
|
|
// GetBackend returns a defensive copy of the backend registered with id.
|
|
|
|
|
func (r *Registry) GetBackend(id string) (domain.Backend, error) {
|
|
|
|
|
if r == nil {
|
|
|
|
|
return domain.Backend{}, fmt.Errorf("%w: %q", ErrBackendNotFound, id)
|
|
|
|
|
}
|
|
|
|
|
definition, ok := r.backends[id]
|
|
|
|
|
if !ok {
|
|
|
|
|
return domain.Backend{}, fmt.Errorf("%w: %q", ErrBackendNotFound, id)
|
|
|
|
|
}
|
2026-10-13 15:53:27 +00:00
|
|
|
cloned, err := domain.CloneBackend(definition)
|
2026-07-29 16:59:43 +00:00
|
|
|
if err != nil {
|
|
|
|
|
return domain.Backend{}, fmt.Errorf("copy backend %q: %w", id, err)
|
|
|
|
|
}
|
2026-10-13 15:53:27 +00:00
|
|
|
return cloned, nil
|
2026-07-29 16:59:43 +00:00
|
|
|
}
|
|
|
|
|
|
2026-07-29 20:48:10 +00:00
|
|
|
// CapacityPolicies returns a copy of the normalized policies for limited
|
|
|
|
|
// backends.
|
|
|
|
|
func (r *Registry) CapacityPolicies() map[string]domain.BackendCapacityPolicy {
|
|
|
|
|
policies := make(map[string]domain.BackendCapacityPolicy)
|
|
|
|
|
if r == nil {
|
|
|
|
|
return policies
|
|
|
|
|
}
|
|
|
|
|
for id, definition := range r.backends {
|
|
|
|
|
if definition.ConcurrencyLimit == 0 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
policies[id] = domain.BackendCapacityPolicy{
|
|
|
|
|
ConcurrencyLimit: definition.ConcurrencyLimit,
|
|
|
|
|
QueueCapacity: definition.QueueCapacity,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return policies
|
|
|
|
|
}
|