8.9 KiB
Promptkit v0.2.0
This supplemental changelog and migration guide summarizes the consumer-facing
changes from v0.1.0 to v0.2.0. The annotated v0.2.0 tag is the
authoritative release record. Exact current contracts belong to the linked
GoDoc and durable documentation.
Summary
v0.2.0 adds three major capabilities:
- an engine-scoped registry for reusable OpenAI-compatible backend definitions;
- bounded, backend-specific run admission and model-generation concurrency; and
- direct per-run session IDs and tri-state reasoning-effort overrides.
Existing endpoint-only profiles remain supported. Consumers can adopt backend registration and runtime overrides incrementally rather than rewriting all profiles during the upgrade.
Compatibility At A Glance
Promptkit remains pre-v1, and this minor release includes source-level and
behavioral changes that deserve review.
| Area | v0.1.0 consumer impact |
|---|---|
| Endpoint-only profiles | Continue to work without migration. |
| Built-in profiles | Continue to use OpenRouter and OPENROUTER_API_KEY; they now select the built-in openrouter backend. |
| Custom backends | Registration is optional. Existing profiles may keep their endpoint and credential configuration. |
| Reasoning overrides | String assignments must migrate to the new pointer field. |
RunRequest.Metadata |
Removed; delete assignments to this field. |
| OpenRouter concurrency | Now limited to 16 active generations with waiting capacity of 1024 per engine. |
| Public JSON | v0.2.0 formalizes supported JSON representations; consumers relying on v0.1.0 encodings should review the notes below. |
| Unkeyed public struct literals | May require updates because fields were added. Keyed literals are recommended. |
Upgrade
After the v0.2.0 tag is published, update the module dependency with:
go get gitea.maximumdirect.net/eric/promptkit@v0.2.0
go mod tidy
Run the consuming project's ordinary tests and race-enabled tests after the upgrade, especially if it calls one engine concurrently or persists Promptkit JSON values.
Backend Registry
Consumers may now register reusable OpenAI-compatible backend definitions with
WithBackend, then select them by ID from file-backed or in-memory profiles.
A backend can supply its endpoint, API-key environment-variable name,
request-wide extra parameters, and optional capacity policy.
Registrations are immutable and belong to one engine. Consumer registrations
can add new IDs but cannot replace Promptkit's reserved openrouter backend.
Profiles that select a backend may still override its endpoint without losing
the backend's routing or capacity identity.
An existing endpoint-only in-memory profile remains valid:
promptkit.Profile{
ID: "local",
Endpoint: "http://localhost:8000/v1",
Model: "example-model",
}
Adopting the registry is optional and can be done when several profiles should share connection or capacity settings:
engine, err := promptkit.NewEngine(
promptkit.Config{PromptDir: "prompts"},
promptkit.WithBackend(promptkit.Backend{
ID: "local",
Endpoint: "http://localhost:8000/v1",
APIKeyEnv: "LOCAL_LLM_API_KEY",
}),
promptkit.WithProfiles(promptkit.Profile{
ID: "local-summary",
BackendID: "local",
Model: "example-model",
}),
)
See the
local-endpoint consumer guide
for task-oriented usage. The
Backend and WithBackend GoDoc owns exact registration,
validation, copying, defaulting, and uniqueness semantics. The
framework format reference owns the profile backend field
and execution precedence.
Backend-Specific Concurrency
Each registered backend may now define:
- an active model-generation limit; and
- a bounded number of additional admitted
Runcalls.
Promptkit owns scheduling for both its built-in model client and an injected
LLMClient. Run remains synchronous: an admitted caller waits for its
ordinary result, while a call beyond the bounded admission capacity returns
ErrCapacityExceeded. Capacity is engine-local and keyed by backend ID.
Endpoint-only profiles and custom backends without a configured limit remain
unlimited.
The built-in OpenRouter backend now permits 16 active generations and 1024 additional admitted calls per engine. Applications that can exceed this bound should handle capacity exhaustion separately from provider and request failures:
result, err := engine.Run(ctx, request)
if errors.Is(err, promptkit.ErrCapacityExceeded) {
// Apply application-specific overload or retry policy.
}
Promptkit does not prescribe retries or map this error to an HTTP status. See
the
concurrency consumer guidance
and the Backend GoDoc for the canonical configuration
contract. Runtime behavior and public error identities belong to the
Engine.Run GoDoc.
Per-Run Session IDs
RunRequest.SessionID can now supply a consumer-managed correlation ID for one
Prepare or Run invocation. A nonblank direct value overrides the prompt's
session template and is exposed in prepared values, results, injected-client
requests, and provider observability. Session IDs should therefore be stable,
non-secret values.
result, err := engine.Run(ctx, promptkit.RunRequest{
PromptID: "meeting.summary",
SessionID: "conversation-42",
})
The built-in OpenAI-compatible client sends a nonempty effective session as the
top-level session_id request-body field, not as an x-session-id header. See
the
session and reasoning consumer guide,
the RunRequest GoDoc, and the
OpenAI-compatible request contract
for exact normalization, length, exposure, and wire behavior.
Per-Run Reasoning Effort
ExecutionTargetOverride.ReasoningEffort changed from string to *string so
one request can distinguish inheritance, replacement, and explicit clearing.
Update a v0.1.0 override like this:
// v0.1.0
Execution: &promptkit.ExecutionTargetOverride{
ReasoningEffort: "high",
}
to:
// v0.2.0
reasoning := "high"
Execution: &promptkit.ExecutionTargetOverride{
ReasoningEffort: &reasoning,
}
The three states are:
nilinherits the selected profile's value;- a pointer to a nonblank string replaces it for that invocation; and
- a pointer to an empty or whitespace-only string clears it for that invocation.
This allows consumers to consolidate profiles that differed only by reasoning
effort. The ExecutionTargetOverride GoDoc owns the exact
override contract.
Other Migration Notes
Remove RunRequest.Metadata
RunRequest.Metadata is no longer part of the public request. Remove any
assignment to that field. Use application-owned state keyed by RunResult.RunID
or a direct SessionID when correlation is needed; these identifiers have
different purposes, so choose according to the application's lifecycle.
Review Persisted JSON
v0.2.0 defines stable JSON representations for the public result, artifact,
execution, validation, and model-client values listed in the
package documentation. Consumers that treated v0.1.0
reflection-derived encodings as stable should update fixtures and stored-data
adapters.
In particular:
RunResultencodes elapsed time as integer milliseconds induration_msinstead of encodingtime.Durationunderduration;- result JSON can include the new
session_idandselected_backend_idfields; - execution-target JSON can include
backend_id; and - artifact and target-presence fields now use their documented lower-case names.
The v0.2.0 RunResult decoder reads duration_ms; it does not translate a
persisted v0.1.0 duration field. Transform old payloads before decoding
when preserving their elapsed duration matters.
Prefer Keyed Struct Literals
New fields were added to several public structs. Replace positional composite literals with keyed literals so future additive fields do not cause another source migration.
Migration Checklist
- Update the module dependency and run the consumer's tests.
- Change reasoning overrides from strings to pointers.
- Remove uses of
RunRequest.Metadata. - Review unkeyed Promptkit struct literals.
- Decide whether shared endpoints should move into registered backends.
- If using built-in OpenRouter profiles at high concurrency, handle
ErrCapacityExceededand review the new engine-local bound. - Review stored JSON, fixtures, and downstream decoders.
- Optionally replace profile-specific session or reasoning variants with per-run overrides.
For complete consumer workflows, use the package consumer guide and maintained offline execution example.