Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5a1bff4529 | |||
| 805a7f965d | |||
| 147f5e5ff5 |
@@ -33,6 +33,9 @@ boundary and constraints that framework work must preserve.
|
|||||||
|
|
||||||
## Release Guidance
|
## Release Guidance
|
||||||
|
|
||||||
|
Consumers upgrading from `v0.2.0` to `v0.3.0` should read the
|
||||||
|
[v0.3.0 changelog](docs/releases/v0.3.0.md).
|
||||||
|
|
||||||
Consumers moving from `v0.1.0` to `v0.2.0` should read the
|
Consumers moving from `v0.1.0` to `v0.2.0` should read the
|
||||||
[v0.2.0 changelog and migration guide](docs/releases/v0.2.0.md).
|
[v0.2.0 changelog and migration guide](docs/releases/v0.2.0.md).
|
||||||
|
|
||||||
|
|||||||
25
backends.go
25
backends.go
@@ -9,6 +9,11 @@ import (
|
|||||||
// backend.
|
// backend.
|
||||||
const BackendOpenRouter = backend.OpenRouterID
|
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 configures one engine-scoped OpenAI-compatible backend.
|
||||||
//
|
//
|
||||||
// Backend has no stable JSON representation. Use keyed literals so additions
|
// Backend has no stable JSON representation. Use keyed literals so additions
|
||||||
@@ -44,6 +49,26 @@ type Backend struct {
|
|||||||
QueueCapacity *int
|
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.
|
// WithBackend adds one Backend registration to the constructed Engine.
|
||||||
//
|
//
|
||||||
// Registrations accumulate in option order. Every normalized ID must be unique
|
// Registrations accumulate in option order. Every normalized ID must be unique
|
||||||
|
|||||||
@@ -124,35 +124,86 @@ providers. The
|
|||||||
[`RunRequest` and `ExecutionTargetOverride` GoDoc](../../types.go) owns the
|
[`RunRequest` and `ExecutionTargetOverride` GoDoc](../../types.go) owns the
|
||||||
exact normalization, precedence, error, copying, and exposure contract.
|
exact normalization, precedence, error, copying, and exposure contract.
|
||||||
|
|
||||||
### Register A Custom Backend
|
### Configure A Local OpenAI-Compatible Endpoint
|
||||||
|
|
||||||
Register a reusable OpenAI-compatible connection once, then select it from a
|
Choose the smallest configuration that fits how the endpoint will be reused.
|
||||||
profile. This local backend limits model generation to two simultaneous calls;
|
|
||||||
because `QueueCapacity` is omitted, the engine admits up to 1024 additional
|
#### Use An Endpoint-Only Profile
|
||||||
calls waiting behind them:
|
|
||||||
|
Put the endpoint directly on an in-memory profile when only that profile needs
|
||||||
|
it and shared backend identity or capacity policy is unnecessary:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
engine, err := promptkit.NewEngine(promptkit.Config{
|
engine, err := promptkit.NewEngine(promptkit.Config{
|
||||||
PromptDir: "prompts",
|
PromptDir: "prompts",
|
||||||
},
|
},
|
||||||
promptkit.WithBackend(promptkit.Backend{
|
|
||||||
ID: "local",
|
|
||||||
Endpoint: "http://localhost:8000/v1",
|
|
||||||
APIKeyEnv: "LOCAL_LLM_API_KEY",
|
|
||||||
ConcurrencyLimit: 2,
|
|
||||||
}),
|
|
||||||
promptkit.WithProfiles(promptkit.Profile{
|
promptkit.WithProfiles(promptkit.Profile{
|
||||||
ID: "local-summary",
|
ID: "local-summary",
|
||||||
BackendID: "local",
|
Endpoint: "http://localhost:8000/v1",
|
||||||
Model: "example-model",
|
Model: "example-model",
|
||||||
}),
|
}),
|
||||||
)
|
)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Endpoint-only profiles have an empty backend ID and remain unrestricted by
|
||||||
|
backend capacity policy.
|
||||||
|
|
||||||
|
#### Use The Conventional Local Backend
|
||||||
|
|
||||||
|
Use `LocalBackend` when profiles should share the conventional `local`
|
||||||
|
identity, endpoint, and concurrency limit:
|
||||||
|
|
||||||
|
```go
|
||||||
|
engine, err := promptkit.NewEngine(promptkit.Config{
|
||||||
|
PromptDir: "prompts",
|
||||||
|
},
|
||||||
|
promptkit.WithBackend(
|
||||||
|
promptkit.LocalBackend("http://localhost:8000/v1", 2),
|
||||||
|
),
|
||||||
|
promptkit.WithProfiles(promptkit.Profile{
|
||||||
|
ID: "local-summary",
|
||||||
|
BackendID: promptkit.BackendLocal,
|
||||||
|
Model: "example-model",
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
The helper is explicit: it does not pre-register a backend or read environment
|
||||||
|
variables. Supplying a positive limit leaves queue capacity omitted, so normal
|
||||||
|
backend registration selects the existing default waiting capacity of 1024.
|
||||||
|
The returned value still enters the engine through `WithBackend`.
|
||||||
|
|
||||||
|
#### Configure A Complete Backend
|
||||||
|
|
||||||
|
Use a keyed `Backend` value for authentication, extra request parameters, an
|
||||||
|
explicit queue capacity, a custom ID, or multiple local endpoints:
|
||||||
|
|
||||||
|
```go
|
||||||
|
noWaiting := 0
|
||||||
|
engine, err := promptkit.NewEngine(promptkit.Config{
|
||||||
|
PromptDir: "prompts",
|
||||||
|
},
|
||||||
|
promptkit.WithBackend(promptkit.Backend{
|
||||||
|
ID: "local-gpu",
|
||||||
|
Endpoint: "http://gpu-host:8000/v1",
|
||||||
|
APIKeyEnv: "LOCAL_GPU_API_KEY",
|
||||||
|
ExtraParams: map[string]any{"provider_option": "enabled"},
|
||||||
|
ConcurrencyLimit: 2,
|
||||||
|
QueueCapacity: &noWaiting,
|
||||||
|
}),
|
||||||
|
promptkit.WithProfiles(promptkit.Profile{
|
||||||
|
ID: "gpu-summary",
|
||||||
|
BackendID: "local-gpu",
|
||||||
|
Model: "example-model",
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
Use distinct custom IDs when registering multiple local endpoints.
|
||||||
Registrations belong to one engine and custom IDs cannot replace built-ins.
|
Registrations belong to one engine and custom IDs cannot replace built-ins.
|
||||||
The [`Backend` and `WithBackend` GoDoc](../../backends.go) defines validation,
|
The [`Backend`, `LocalBackend`, and `WithBackend` GoDoc](../../backends.go)
|
||||||
copying, uniqueness, exact concurrency-field semantics, and request-default
|
defines exact construction, validation, copying, uniqueness, concurrency, and
|
||||||
behavior.
|
request-default behavior.
|
||||||
|
|
||||||
Both file-backed and in-memory profiles select a registration through
|
Both file-backed and in-memory profiles select a registration through
|
||||||
`backend` or `Profile.BackendID`. Profile and request endpoint overrides retain
|
`backend` or `Profile.BackendID`. Profile and request endpoint overrides retain
|
||||||
@@ -173,8 +224,8 @@ zero:
|
|||||||
```go
|
```go
|
||||||
noWaiting := 0
|
noWaiting := 0
|
||||||
backend := promptkit.Backend{
|
backend := promptkit.Backend{
|
||||||
ID: "local",
|
ID: "local-gpu",
|
||||||
Endpoint: "http://localhost:8000/v1",
|
Endpoint: "http://gpu-host:8000/v1",
|
||||||
ConcurrencyLimit: 2,
|
ConcurrencyLimit: 2,
|
||||||
QueueCapacity: &noWaiting,
|
QueueCapacity: &noWaiting,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ engine, err := promptkit.NewEngine(
|
|||||||
```
|
```
|
||||||
|
|
||||||
See the
|
See the
|
||||||
[custom-backend consumer guide](../consumers/pkg-promptkit.md#register-a-custom-backend)
|
[local-endpoint consumer guide](../consumers/pkg-promptkit.md#configure-a-local-openai-compatible-endpoint)
|
||||||
for task-oriented usage. The
|
for task-oriented usage. The
|
||||||
[`Backend` and `WithBackend` GoDoc](../../backends.go) owns exact registration,
|
[`Backend` and `WithBackend` GoDoc](../../backends.go) owns exact registration,
|
||||||
validation, copying, defaulting, and uniqueness semantics. The
|
validation, copying, defaulting, and uniqueness semantics. The
|
||||||
|
|||||||
74
docs/releases/v0.3.0.md
Normal file
74
docs/releases/v0.3.0.md
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
# Promptkit v0.3.0
|
||||||
|
|
||||||
|
This supplemental changelog summarizes the consumer-facing changes from
|
||||||
|
`v0.2.0` to `v0.3.0`. The annotated `v0.3.0` tag is the authoritative release
|
||||||
|
record. Exact current contracts belong to the linked GoDoc and durable
|
||||||
|
documentation.
|
||||||
|
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
`v0.3.0` adds a concise way to register the common local OpenAI-compatible
|
||||||
|
backend configuration:
|
||||||
|
|
||||||
|
- `BackendLocal` provides the conventional, non-reserved backend ID `"local"`;
|
||||||
|
and
|
||||||
|
- `LocalBackend` constructs an ordinary `Backend` from an endpoint and
|
||||||
|
concurrency limit.
|
||||||
|
|
||||||
|
The helper is explicit and additive. It does not pre-register a backend, read
|
||||||
|
environment variables, select a model, or replace the complete `Backend`
|
||||||
|
configuration interface.
|
||||||
|
|
||||||
|
## Compatibility
|
||||||
|
|
||||||
|
Existing `v0.2.0` consumers require no migration. Endpoint-only profiles,
|
||||||
|
complete custom `Backend` values, the built-in OpenRouter backend, and existing
|
||||||
|
registrations using the literal ID `"local"` continue to work unchanged.
|
||||||
|
|
||||||
|
## Upgrade
|
||||||
|
|
||||||
|
Update the module dependency with:
|
||||||
|
|
||||||
|
```sh
|
||||||
|
go get gitea.maximumdirect.net/eric/promptkit@v0.3.0
|
||||||
|
go mod tidy
|
||||||
|
```
|
||||||
|
|
||||||
|
Run the consuming project's ordinary tests and race-enabled tests after the
|
||||||
|
upgrade.
|
||||||
|
|
||||||
|
## Configure A Local Backend
|
||||||
|
|
||||||
|
Register the convenience value through the existing `WithBackend` option and
|
||||||
|
select it from one or more profiles:
|
||||||
|
|
||||||
|
```go
|
||||||
|
engine, err := promptkit.NewEngine(
|
||||||
|
promptkit.Config{PromptDir: "prompts"},
|
||||||
|
promptkit.WithBackend(
|
||||||
|
promptkit.LocalBackend("http://localhost:8000/v1", 2),
|
||||||
|
),
|
||||||
|
promptkit.WithProfiles(promptkit.Profile{
|
||||||
|
ID: "local-summary",
|
||||||
|
BackendID: promptkit.BackendLocal,
|
||||||
|
Model: "example-model",
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
Use an endpoint-only profile when shared backend identity and capacity policy
|
||||||
|
are unnecessary. Continue to use a complete keyed `Backend` value for custom
|
||||||
|
IDs, authentication, extra request parameters, explicit queue capacity, or
|
||||||
|
multiple local endpoints.
|
||||||
|
|
||||||
|
See the
|
||||||
|
[local-endpoint consumer guide](../consumers/pkg-promptkit.md#configure-a-local-openai-compatible-endpoint)
|
||||||
|
for task-oriented configuration choices. The
|
||||||
|
[`BackendLocal`, `LocalBackend`, and `WithBackend` GoDoc](../../backends.go)
|
||||||
|
owns their exact construction, registration, validation, and concurrency
|
||||||
|
semantics.
|
||||||
|
|
||||||
|
## Consumer Action
|
||||||
|
|
||||||
|
None. Adopt the convenience constructor when it simplifies local endpoint
|
||||||
|
configuration.
|
||||||
@@ -11,7 +11,8 @@ consumer value, and important policy choices.
|
|||||||
This document is planning material, not a description of current behavior.
|
This document is planning material, not a description of current behavior.
|
||||||
Current exported contracts remain owned by Go declarations and GoDoc, backend
|
Current exported contracts remain owned by Go declarations and GoDoc, backend
|
||||||
registration guidance by the
|
registration guidance by the
|
||||||
[consumer guide](../consumers/pkg-promptkit.md#register-a-custom-backend), and
|
[consumer guide](../consumers/pkg-promptkit.md#configure-a-local-openai-compatible-endpoint),
|
||||||
|
and
|
||||||
implemented orchestration by the
|
implemented orchestration by the
|
||||||
[internal runner document](../internal/runner.md).
|
[internal runner document](../internal/runner.md).
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
163
docs/roadmap/local-backend.md
Normal file
163
docs/roadmap/local-backend.md
Normal file
@@ -0,0 +1,163 @@
|
|||||||
|
# Local Backend Convenience
|
||||||
|
|
||||||
|
**Status:** Complete.
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
Make the common case of using a local OpenAI-compatible endpoint concise and
|
||||||
|
easy to discover without introducing implicit configuration or a separate
|
||||||
|
backend abstraction.
|
||||||
|
|
||||||
|
The existing `Backend` type and registry remain the canonical, fully
|
||||||
|
configurable interface. A small convenience constructor will cover the usual
|
||||||
|
local-network case, while improved consumer documentation will make it clear
|
||||||
|
when an endpoint-only profile, the convenience constructor, or a complete
|
||||||
|
`Backend` value is appropriate.
|
||||||
|
|
||||||
|
## Motivation
|
||||||
|
|
||||||
|
Consumers can already use a local endpoint by setting `Profile.Endpoint`, or
|
||||||
|
register one as a backend with `WithBackend`. The first option is concise but
|
||||||
|
does not provide shared backend-level concurrency control. The second supports
|
||||||
|
the complete backend feature set but requires consumers to understand and
|
||||||
|
populate several fields for a common configuration.
|
||||||
|
|
||||||
|
Most consumers adding a local backend need only:
|
||||||
|
|
||||||
|
- a stable backend ID;
|
||||||
|
- an OpenAI-compatible endpoint; and
|
||||||
|
- a concurrency limit appropriate for the local server.
|
||||||
|
|
||||||
|
Promptkit should provide a direct path for that case while keeping all
|
||||||
|
configuration explicit and preserving the full registry interface for
|
||||||
|
advanced needs.
|
||||||
|
|
||||||
|
## Consumer Paths
|
||||||
|
|
||||||
|
Documentation should present three progressively more configurable paths:
|
||||||
|
|
||||||
|
1. Set `Profile.Endpoint` when a profile only needs to target a local endpoint
|
||||||
|
and does not need shared backend policy.
|
||||||
|
2. Use the local-backend convenience constructor when profiles should share a
|
||||||
|
named local endpoint and its concurrency limit.
|
||||||
|
3. Construct a complete `Backend` value when the consumer needs a custom
|
||||||
|
backend ID, authentication, extra request parameters, an explicit queue
|
||||||
|
capacity, or multiple local backends.
|
||||||
|
|
||||||
|
These are complementary interfaces. The convenience constructor must return an
|
||||||
|
ordinary `Backend`, so it does not create a second configuration model.
|
||||||
|
|
||||||
|
## Public Convenience API
|
||||||
|
|
||||||
|
The public package should expose:
|
||||||
|
|
||||||
|
```go
|
||||||
|
const BackendLocal = "local"
|
||||||
|
|
||||||
|
func LocalBackend(endpoint string, concurrencyLimit int) Backend
|
||||||
|
```
|
||||||
|
|
||||||
|
`LocalBackend` should return a `Backend` with:
|
||||||
|
|
||||||
|
- `ID` set to `BackendLocal`;
|
||||||
|
- `Endpoint` set to the supplied endpoint;
|
||||||
|
- `ConcurrencyLimit` set to the supplied limit; and
|
||||||
|
- all other fields left at their zero values.
|
||||||
|
|
||||||
|
The returned value is passed to `WithBackend` and follows the same copying,
|
||||||
|
normalization, validation, and registration rules as any consumer-constructed
|
||||||
|
`Backend`.
|
||||||
|
|
||||||
|
The constructor should be a transparent value constructor. It should not read
|
||||||
|
environment variables, mutate global state, register the backend, validate
|
||||||
|
arguments independently, or create profiles. Consumers may inspect or modify
|
||||||
|
the returned value before registration, although documentation should direct
|
||||||
|
substantially customized configurations to the full `Backend` form.
|
||||||
|
|
||||||
|
## Identity and Registration
|
||||||
|
|
||||||
|
`BackendLocal` is a conventional ID used by the convenience constructor. It is
|
||||||
|
not pre-registered and should not become a specially reserved registry ID.
|
||||||
|
Consumers remain responsible for registering the returned backend with
|
||||||
|
`WithBackend` and naming it from profiles through `BackendID`.
|
||||||
|
|
||||||
|
This distinction preserves compatibility with consumers that may already
|
||||||
|
register their own backend using the ID `"local"`. Normal duplicate-ID rules
|
||||||
|
still apply if a consumer attempts to register more than one backend with that
|
||||||
|
ID.
|
||||||
|
|
||||||
|
Consumers that need multiple local endpoints should choose distinct IDs and
|
||||||
|
use complete `Backend` values rather than the single conventional helper ID.
|
||||||
|
|
||||||
|
## Concurrency and Queue Semantics
|
||||||
|
|
||||||
|
The constructor must preserve the existing backend concurrency contract:
|
||||||
|
|
||||||
|
- a positive concurrency limit bounds simultaneous requests and uses the
|
||||||
|
existing default queue capacity because `QueueCapacity` remains `nil`;
|
||||||
|
- a zero concurrency limit leaves the backend unconstrained; and
|
||||||
|
- a negative concurrency limit is rejected through the existing engine
|
||||||
|
configuration validation path.
|
||||||
|
|
||||||
|
The constructor should not select a hidden default concurrency limit. Local
|
||||||
|
servers vary substantially in capacity, so the consumer should make this
|
||||||
|
choice explicitly.
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
The final documentation state has two canonical surfaces:
|
||||||
|
|
||||||
|
- Public Go documentation describes the exact contract of
|
||||||
|
`BackendLocal` and `LocalBackend`, including their conventional,
|
||||||
|
non-pre-registered nature.
|
||||||
|
- The [promptkit consumer guide](../consumers/pkg-promptkit.md) includes
|
||||||
|
a task-oriented local-endpoint section that shows the three consumer paths,
|
||||||
|
explains the decision between them, and provides concise examples of the
|
||||||
|
endpoint-only and convenience-constructor forms.
|
||||||
|
|
||||||
|
The consumer guide continues to document the full `Backend` interface as
|
||||||
|
the advanced path rather than attempting to reproduce every configuration
|
||||||
|
variation through convenience APIs.
|
||||||
|
|
||||||
|
## Compatibility
|
||||||
|
|
||||||
|
This feature is additive:
|
||||||
|
|
||||||
|
- existing endpoint-only profiles continue to work unchanged;
|
||||||
|
- existing `Backend` values and `WithBackend` registrations remain the
|
||||||
|
canonical general-purpose interface;
|
||||||
|
- existing registrations using the literal ID `"local"` remain valid; and
|
||||||
|
- OpenRouter defaults and all other backend behavior remain unchanged.
|
||||||
|
|
||||||
|
No consumer is required to adopt the convenience constructor.
|
||||||
|
|
||||||
|
## Non-Goals
|
||||||
|
|
||||||
|
This work does not include:
|
||||||
|
|
||||||
|
- pre-registering or implicitly enabling a local backend;
|
||||||
|
- discovering a local endpoint, API key, or concurrency limit from environment
|
||||||
|
variables;
|
||||||
|
- adding local-backend fields to `Config`;
|
||||||
|
- selecting a default local model or creating a profile automatically;
|
||||||
|
- adding a combined backend-and-profile constructor;
|
||||||
|
- adding convenience parameters for API keys, extra request parameters, or
|
||||||
|
queue capacity;
|
||||||
|
- replacing or redesigning the backend registry;
|
||||||
|
- adding support for non-OpenAI-compatible local APIs; or
|
||||||
|
- changing backend routing, scheduling, or queue behavior.
|
||||||
|
|
||||||
|
## Target End State
|
||||||
|
|
||||||
|
After this work:
|
||||||
|
|
||||||
|
- consumers with a simple one-profile local endpoint can continue to configure
|
||||||
|
it directly on the profile;
|
||||||
|
- consumers needing a shared local endpoint and concurrency policy can express
|
||||||
|
it with one `LocalBackend` call and register the returned value normally;
|
||||||
|
- consumers with advanced or multiple-local-backend requirements have a clear
|
||||||
|
path to the complete `Backend` interface;
|
||||||
|
- all local configuration remains explicit, inspectable, and compatible with
|
||||||
|
dependency injection; and
|
||||||
|
- canonical documentation makes the simplest suitable interface easy to find
|
||||||
|
without obscuring the underlying registry model.
|
||||||
@@ -5,6 +5,7 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
@@ -138,6 +139,49 @@ func TestUnknownProfileBackendHasProfileLoadIdentity(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestLocalBackendConstructsAndRegistersConventionalBackend(t *testing.T) {
|
||||||
|
const (
|
||||||
|
localBackendID = "local"
|
||||||
|
limit = 2
|
||||||
|
)
|
||||||
|
if promptkit.BackendLocal != localBackendID {
|
||||||
|
t.Fatalf("BackendLocal=%q, want %q", promptkit.BackendLocal, localBackendID)
|
||||||
|
}
|
||||||
|
|
||||||
|
endpoint := "http://local.example/v1"
|
||||||
|
backend := promptkit.LocalBackend(endpoint, limit)
|
||||||
|
want := promptkit.Backend{
|
||||||
|
ID: localBackendID,
|
||||||
|
Endpoint: endpoint,
|
||||||
|
ConcurrencyLimit: limit,
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(backend, want) {
|
||||||
|
t.Fatalf("LocalBackend()=%+v, want %+v", backend, want)
|
||||||
|
}
|
||||||
|
|
||||||
|
engine, err := promptkit.NewEngine(promptkit.Config{},
|
||||||
|
promptkit.WithPromptFS(contractPromptFS("prompt", "local-profile", "message"), "."),
|
||||||
|
promptkit.WithBackend(backend),
|
||||||
|
promptkit.WithProfiles(promptkit.Profile{
|
||||||
|
ID: "local-profile",
|
||||||
|
BackendID: localBackendID,
|
||||||
|
Model: "model",
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("construct engine with local backend: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
prepared, err := engine.Prepare(context.Background(), promptkit.RunRequest{PromptID: "prompt"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("prepare with local backend: %v", err)
|
||||||
|
}
|
||||||
|
if prepared.SelectedBackendID != localBackendID ||
|
||||||
|
prepared.EffectiveModelParams.Endpoint != endpoint {
|
||||||
|
t.Fatalf("unexpected local backend preparation: %+v", prepared)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCustomBackendFlowsThroughProfilesOverridesAndInjectedClient(t *testing.T) {
|
func TestCustomBackendFlowsThroughProfilesOverridesAndInjectedClient(t *testing.T) {
|
||||||
t.Setenv("CUSTOM_LLM_KEY", "test-key")
|
t.Setenv("CUSTOM_LLM_KEY", "test-key")
|
||||||
client := &fakeLLMClient{response: &promptkit.GenerateResponse{Content: "ok"}}
|
client := &fakeLLMClient{response: &promptkit.GenerateResponse{Content: "ok"}}
|
||||||
|
|||||||
Reference in New Issue
Block a user