100 lines
4.3 KiB
Go
100 lines
4.3 KiB
Go
package promptkit
|
|
|
|
import (
|
|
"gitea.maximumdirect.net/eric/promptkit/internal/backend"
|
|
"gitea.maximumdirect.net/eric/promptkit/internal/domain"
|
|
)
|
|
|
|
// BackendOpenRouter is the reserved ID of Promptkit's built-in OpenRouter
|
|
// backend.
|
|
const BackendOpenRouter = backend.OpenRouterID
|
|
|
|
// BackendLocal is the case-sensitive conventional ID used by [LocalBackend].
|
|
// It is not a built-in or reserved backend and must be registered with
|
|
// [WithBackend].
|
|
const BackendLocal = "local"
|
|
|
|
// Backend configures one engine-scoped OpenAI-compatible backend.
|
|
//
|
|
// Backend has no stable JSON representation. Use keyed literals so additions
|
|
// to this configuration value do not break source compatibility.
|
|
type Backend struct {
|
|
// ID is the stable, case-sensitive registry key. NewEngine trims it and
|
|
// requires a non-blank value. BackendOpenRouter is reserved.
|
|
ID string
|
|
// Endpoint is the OpenAI-compatible base endpoint. NewEngine trims it and
|
|
// requires an absolute HTTP or HTTPS URL with a host and without user
|
|
// information, a query string, or a fragment. Paths are allowed.
|
|
Endpoint string
|
|
// APIKeyEnv optionally names the environment variable containing the API
|
|
// key. NewEngine trims it and requires the portable form
|
|
// [A-Za-z_][A-Za-z0-9_]*. Store only the name, never a credential value.
|
|
APIKeyEnv string
|
|
// ExtraParams contains backend-wide request defaults. Values must be
|
|
// JSON-compatible, finite, acyclic, and keyed by non-empty strings. Keys
|
|
// must not be model, session_id, messages, temperature, max_tokens, top_p,
|
|
// service_tier, reasoning_effort, or response_format. An empty map supplies
|
|
// no defaults. NewEngine deeply copies the map.
|
|
ExtraParams map[string]any
|
|
// ConcurrencyLimit is the maximum number of simultaneous model-generation
|
|
// calls allowed for this backend within one Engine. Zero leaves the backend
|
|
// unlimited. A negative value makes NewEngine fail with ErrInvalidConfig.
|
|
ConcurrencyLimit int
|
|
// QueueCapacity controls how many additional Run calls may be admitted
|
|
// beyond ConcurrencyLimit. Nil uses 1024 when ConcurrencyLimit is positive;
|
|
// a pointer uses its exact value, including zero. The pointed-to value must
|
|
// be non-negative, and QueueCapacity must be nil when ConcurrencyLimit is
|
|
// zero. Their sum must fit in an int. WithBackend copies the value and does
|
|
// not retain the pointer.
|
|
QueueCapacity *int
|
|
}
|
|
|
|
// LocalBackend returns a caller-owned Backend for a conventional local
|
|
// OpenAI-compatible endpoint. It sets ID to BackendLocal and copies endpoint
|
|
// and concurrencyLimit into Endpoint and ConcurrencyLimit without
|
|
// normalization or validation. APIKeyEnv, ExtraParams, and QueueCapacity keep
|
|
// their zero values.
|
|
//
|
|
// LocalBackend does not read environment variables, register the value, or
|
|
// mutate engine or package state. Supply the returned value through
|
|
// [WithBackend]; [NewEngine] then applies the ordinary backend validation and
|
|
// concurrency semantics, including default queue capacity for a positive
|
|
// limit, unlimited behavior for zero, and ErrInvalidConfig for a negative
|
|
// limit.
|
|
func LocalBackend(endpoint string, concurrencyLimit int) Backend {
|
|
return Backend{
|
|
ID: BackendLocal,
|
|
Endpoint: endpoint,
|
|
ConcurrencyLimit: concurrencyLimit,
|
|
}
|
|
}
|
|
|
|
// WithBackend adds one Backend registration to the constructed Engine.
|
|
//
|
|
// Registrations accumulate in option order. Every normalized ID must be unique
|
|
// across consumer registrations and built-ins; a duplicate or invalid
|
|
// definition makes NewEngine fail with ErrInvalidConfig. In particular,
|
|
// BackendOpenRouter cannot be replaced. The immutable registration is scoped
|
|
// to the resulting Engine and cannot be enumerated, replaced, removed, or
|
|
// mutated after construction. WithBackend does not install package-global
|
|
// state.
|
|
func WithBackend(backend Backend) Option {
|
|
queueCapacity := 0
|
|
queueCapacitySet := backend.QueueCapacity != nil
|
|
if queueCapacitySet {
|
|
queueCapacity = *backend.QueueCapacity
|
|
}
|
|
return optionFunc(func(options *engineOptions) error {
|
|
options.backends = append(options.backends, domain.Backend{
|
|
ID: backend.ID,
|
|
Endpoint: backend.Endpoint,
|
|
APIKeyEnv: backend.APIKeyEnv,
|
|
ExtraParams: backend.ExtraParams,
|
|
ConcurrencyLimit: backend.ConcurrencyLimit,
|
|
QueueCapacity: queueCapacity,
|
|
QueueCapacitySet: queueCapacitySet,
|
|
})
|
|
return nil
|
|
})
|
|
}
|