# 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: ```sh 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: ```go 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: ```go 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](../consumers/pkg-promptkit.md#configure-a-local-openai-compatible-endpoint) for task-oriented usage. The [`Backend` and `WithBackend` GoDoc](../../backends.go) owns exact registration, validation, copying, defaulting, and uniqueness semantics. The [framework format reference](../formats.md) 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 `Run` calls. 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: ```go 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](../consumers/pkg-promptkit.md#limit-backend-concurrency) and the [`Backend` GoDoc](../../backends.go) for the canonical configuration contract. Runtime behavior and public error identities belong to the [`Engine.Run` GoDoc](../../engine.go). ## 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. ```go 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](../consumers/pkg-promptkit.md#set-a-per-run-session-and-reasoning), the [`RunRequest` GoDoc](../../types.go), and the [OpenAI-compatible request contract](../integrations/openai-compatible-chat.md#request-body) 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: ```go // v0.1.0 Execution: &promptkit.ExecutionTargetOverride{ ReasoningEffort: "high", } ``` to: ```go // v0.2.0 reasoning := "high" Execution: &promptkit.ExecutionTargetOverride{ ReasoningEffort: &reasoning, } ``` The three states are: - `nil` inherits 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](../../types.go) 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](../../doc.go). Consumers that treated `v0.1.0` reflection-derived encodings as stable should update fixtures and stored-data adapters. In particular: - `RunResult` encodes elapsed time as integer milliseconds in `duration_ms` instead of encoding `time.Duration` under `duration`; - result JSON can include the new `session_id` and `selected_backend_id` fields; - 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 `ErrCapacityExceeded` and 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](../consumers/pkg-promptkit.md) and maintained [offline execution example](../../examples/go-library/run/main.go).