Document the consumer migration to identified resources

This commit is contained in:
2026-11-02 12:58:39 +00:00
parent 2ccbee3758
commit b0bfe857fe
5 changed files with 118 additions and 60 deletions

View File

@@ -45,8 +45,8 @@ boundary and constraints that framework work must preserve.
The [v0.16.0 release notes](docs/releases/v0.16.0.md) cover explicit smoke The [v0.16.0 release notes](docs/releases/v0.16.0.md) cover explicit smoke
diagnostics, configuration collections, scoped engine views, and discovery. diagnostics, configuration collections, scoped engine views, and discovery.
Upgrading consumers should review the breaking changes to bundled configuration Upgrading consumers should also review the current identified-resource and
and prompt version selection and follow the linked migration guide. ConfigKit v1 changes in the [migration guide](docs/consumers/configuration-migration.md).
The [v0.15.0 release notes](docs/releases/v0.15.0.md) cover error-only The [v0.15.0 release notes](docs/releases/v0.15.0.md) cover error-only
validation of concrete requests with `Engine.ValidateRequest`. validation of concrete requests with `Engine.ValidateRequest`.

View File

@@ -1,8 +1,9 @@
# Configuration And API Migration # Configuration And API Migration
Promptkit no longer installs a provider catalog or selects prompt definitions This breaking pre-v1 minor migration changes the v0.16-era keyed resources to
by descriptive version labels. Applications now choose configuration inputs identified lists, adopts ConfigKit v1, and removes prompt-version labels.
explicitly, and execution selects one prompt by its exact ID. This guide Promptkit does not install a provider catalog; applications choose configuration
inputs explicitly, and execution selects one prompt by its exact ID. This guide
explains the shape changes and decisions an application must make; it is not an explains the shape changes and decisions an application must make; it is not an
automatic migration tool. The [framework format reference](../formats.md) owns automatic migration tool. The [framework format reference](../formats.md) owns
the current configuration contract, and the root package GoDoc owns exact API the current configuration contract, and the root package GoDoc owns exact API
@@ -30,21 +31,19 @@ engine, err := promptkit.NewEngine(promptkit.Config{
}) })
``` ```
Collection resource keys are local keys, while their runtime identities are Collection resource IDs are local IDs, while their runtime identities are
qualified. For example, `collections.openrouter.profiles.gemini-flash-latest` qualified. For example, a profile with `id: gemini-flash-latest` in collection
is selected as `openrouter/gemini-flash-latest`. Stored backend, prompt-default, `openrouter` is selected as `openrouter/gemini-flash-latest`. Stored backend,
and other resource references must use their exact intended IDs; Promptkit does prompt-default, and other resource references must use their exact intended IDs;
not rewrite references when a source is mounted. Profile `extends` remains a Promptkit does not rewrite references when a source is mounted. `extends`
sibling local key in the same collection, not a cross-collection reference. selects a sibling ID in the same list, not a cross-collection reference.
Review collisions and all references when moving resources into collections. Review collisions and all references when moving resources into collections.
The root `version` is an optional ConfigKit source header. A collection's The optional source-root `version` header now accepts `2` or `"2"`; headerless
`release_version` and a prompt's `version` are optional descriptive labels; sources remain valid. A collection's `release_version` remains an optional
neither selects a resource or changes execution. Preserve a label only when it label. Prompt-version labels have been removed: choose one definition per ID
is useful to your application. A formerly version-keyed prompt mapping must be and store any application-specific release label outside Promptkit. In a
reduced to one deliberately chosen definition per prompt ID, with its old label standalone imported prompt item, root `version` is a source header, not a label.
retained as prompt metadata if desired. Promptkit cannot choose a winner from a
consumer's version history.
For example, change a version-keyed definition: For example, change a version-keyed definition:
@@ -60,12 +59,11 @@ prompts:
validation_mode: none validation_mode: none
``` ```
to one direct definition. Its optional `version` is only a label: to one identified definition:
```yaml ```yaml
prompts: prompts:
report: - id: report
version: "2.0"
messages: messages:
- role: user - role: user
content: Review this report. content: Review this report.
@@ -74,6 +72,51 @@ prompts:
validation_mode: none validation_mode: none
``` ```
The same conversion applies to backends and profiles. Sibling inheritance uses
identity references, and a later same-ID record replaces the whole lower record:
```yaml
profiles:
- id: base
endpoint: https://example.invalid/v1
model: example-model
- id: fast
extends: {id: base}
timeout_seconds: 30
```
To customize a lower resource's fields, add a distinct inherited variant as
above; when replacing the same ID, supply the complete intended record. Generic
append, replace, imports, and inheritance are described by the
[ConfigKit v1 configuration contract](https://forge.maximumdirect.net/base-layer/configkit/src/tag/v1.0.0/docs/config.md).
Source-root controls are now `config:`, not `configkit:`. Imports are optional
unless the selected import declares `required: true`.
Update ConfigKit imports to `go.maximumdirect.net/configkit` at v1.0.0: its Go
types are incompatible with the old module path. Promptkit now requires Go
1.27.0 or newer. Source builders take ordered slices with explicit IDs:
```go
endpoint, model := "https://example.invalid/v1", "example-model"
base := "base"
source := promptkit.ProfileSource("application", []promptkit.ProfileConfig{
{ID: "base", Endpoint: &endpoint, Model: &model},
{ID: "fast", Extends: &base},
})
```
Replace former maps passed to `BackendSource` in the same way, setting each
`BackendConfig.ID`. Duplicates are retained for loading to reject. Resource
inspection paths now address list indexes, for example
`configkit.Keys("profiles").Index(0).Key("model")`. Configuration inspection
and diffs expose composed values and provenance, while `InspectProfile` and
other interpreted views expose Promptkit normalization and defaults; the views
are not promised to be identical.
Remove `PromptVersion` and `PromptIdentity.Version` uses and the corresponding
`prompt_version` JSON members. Prompt hashes are opaque equality values and may
change when the removed field no longer participates in hashing.
## Identity Mapping ## Identity Mapping
The reviewed catalog identities have slash-free profile keys. Their documented The reviewed catalog identities have slash-free profile keys. Their documented
@@ -100,8 +143,8 @@ Gemini profile in the same `openrouter` collection:
collections: collections:
openrouter: openrouter:
profiles: profiles:
standard: - id: standard
extends: gemini-flash-latest extends: {id: gemini-flash-latest}
``` ```
An optional auto profile may instead select the exact backend and model values: An optional auto profile may instead select the exact backend and model values:
@@ -110,7 +153,7 @@ An optional auto profile may instead select the exact backend and model values:
collections: collections:
openrouter: openrouter:
profiles: profiles:
auto: - id: auto
backend: openrouter/default backend: openrouter/default
model: openrouter/auto model: openrouter/auto
``` ```
@@ -142,10 +185,8 @@ if err != nil {
``` ```
If the former format contained multiple versions under one ID, choose the one If the former format contained multiple versions under one ID, choose the one
definition the application should install, and optionally keep its label in definition the application should install. Promptkit no longer retains or
the prompt's `version` field. That label remains descriptive metadata and is returns its former descriptive label.
reported by inspection or results where applicable; it never chooses the
definition.
The public inventory APIs can help an operator inspect a captured effective The public inventory APIs can help an operator inspect a captured effective
configuration: `ListProfiles`, `ListPrompts`, and `ListBackends` return exact configuration: `ListProfiles`, `ListPrompts`, and `ListBackends` return exact

View File

@@ -15,6 +15,9 @@ Import the package as:
import "gitea.maximumdirect.net/eric/promptkit" import "gitea.maximumdirect.net/eric/promptkit"
``` ```
Configuration APIs use `go.maximumdirect.net/configkit` v1.0.0. Its types are
not interchangeable with the old ConfigKit module path.
The maintained [offline preparation example](../../examples/go-library/prepare/main.go) The maintained [offline preparation example](../../examples/go-library/prepare/main.go)
demonstrates explicit collection composition and inventory. Applications demonstrates explicit collection composition and inventory. Applications
adapting older provider or versioned-prompt configuration can use the adapting older provider or versioned-prompt configuration can use the
@@ -28,7 +31,8 @@ programs.
## Go Compatibility ## Go Compatibility
The `go` directive in the selected release's [module metadata](../../go.mod) The `go` directive in the selected release's [module metadata](../../go.mod)
declares its minimum supported consumer Go version. Maintainers build and declares its minimum supported consumer Go version, currently Go 1.27.0.
Maintainers build and
validate releases with the locally selected Go patch release; the minimum validate releases with the locally selected Go patch release; the minimum
does not simply track that patch version. does not simply track that patch version.
@@ -108,8 +112,8 @@ defaults, err := promptkit.FilesystemInputs("embedded defaults", applicationFS,
if err != nil { return err } if err != nil { return err }
operator, err := promptkit.DirectoryInputs(operatorDirectory) operator, err := promptkit.DirectoryInputs(operatorDirectory)
if err != nil { return err } if err != nil { return err }
profile := promptkit.ProfileSource("application choices", map[string]promptkit.ProfileConfig{ profile := promptkit.ProfileSource("application choices", []promptkit.ProfileConfig{
"summary": {Model: &selectedModel}, {ID: "summary", Endpoint: &selectedEndpoint, Model: &selectedModel},
}) })
engine, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.ConfigurationSources{ engine, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.ConfigurationSources{
Underlays: []configkit.Underlay{ Underlays: []configkit.Underlay{
@@ -120,7 +124,9 @@ engine, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.Configura
}}) }})
``` ```
Only add the operator group when the application selects that directory; an Each later same-ID resource replaces the complete earlier record; use a distinct
inherited sibling for field-level customization. Only add the operator group
when the application selects that directory; an
explicitly selected missing or unreadable root is an error. Each helper finds explicitly selected missing or unreadable root is an error. Each helper finds
`.yaml` and `.yml` files recursively and disables imports by default. The `.yaml` and `.yml` files recursively and disables imports by default. The
caller may enable imports on individual inputs. A nil `Sources.Main` is an caller may enable imports on individual inputs. A nil `Sources.Main` is an
@@ -131,8 +137,8 @@ labeled mapping as an input. A mapping owns a snapshot of supported values:
```go ```go
document := configkit.Mapping("application configuration", map[string]any{ document := configkit.Mapping("application configuration", map[string]any{
"profiles": map[string]any{ "profiles": []any{
"local-summary": map[string]any{ map[string]any{"id": "local-summary",
"backend": "local", "model": "example-model", "backend": "local", "model": "example-model",
"temperature": nil, // Suppress an inherited provider control. "temperature": nil, // Suppress an inherited provider control.
}, },
@@ -202,15 +208,15 @@ sensitive application data.
## Inspect The Captured Configuration ## Inspect The Captured Configuration
Use [`Engine.InspectConfiguration`](../../configuration_inspection.go) for an Use [`Engine.InspectConfiguration`](../../configuration_inspection.go) for an
operator-selected report of effective configuration, source descriptions, operator-selected report of composed configuration, source descriptions,
diagnostics, and path history. Configuration inspection uses the collection's diagnostics, and path history. Configuration inspection uses list indexes in
nested configuration path rather than its qualified runtime ID. For profile the collection's nested path rather than qualified runtime IDs. For a profile
`team/summary`, construct the semantic path with `configkit.Keys`: at index `i` in collection `team`, construct the path with `configkit.Keys`:
```go ```go
view, err := engine.InspectConfiguration() view, err := engine.InspectConfiguration()
if err != nil { return err } if err != nil { return err }
path := configkit.Keys("collections", "team", "profiles", "summary", "model") path := configkit.Keys("collections", "team", "profiles").Index(i).Key("model")
explanation, found := view.Explain(path) explanation, found := view.Explain(path)
if found && explanation.Effective.Redacted { if found && explanation.Effective.Redacted {
// Apply the application's disclosure policy before sharing the report. // Apply the application's disclosure policy before sharing the report.
@@ -221,8 +227,9 @@ if found && explanation.Effective.Redacted {
the application decides whether those reports may be disclosed. Credential- the application decides whether those reports may be disclosed. Credential-
shaped provider keys are redacted, but arbitrary prompt and provider content shaped provider keys are redacted, but arbitrary prompt and provider content
is not necessarily safe to share. Inspection uses the engine's captured result is not necessarily safe to share. Inspection uses the engine's captured result
and does not reopen sources or resolve credentials. `InspectProfile` instead and does not reopen sources or resolve credentials. It retains composed values
shows backend-completed execution settings for one profile, and `Prepare` or and provenance rather than Promptkit's normalized/defaulted interpretation.
`InspectProfile` instead shows backend-completed execution settings for one profile, and `Prepare` or
`PreparedExecution.Details` shows request-specific rendered messages, inputs, `PreparedExecution.Details` shows request-specific rendered messages, inputs,
and validation resources. None of those views is a substitute for the others. and validation resources. None of those views is a substitute for the others.
@@ -253,7 +260,7 @@ for _, difference := range differences {
``` ```
See the [`ConfigurationInspection.Diff` GoDoc](../../configuration_inspection.go) See the [`ConfigurationInspection.Diff` GoDoc](../../configuration_inspection.go)
and ConfigKit's [v0.8.0 effective-configuration diff guidance](https://gitea.maximumdirect.net/eric/ConfigKit/src/tag/v0.8.0/docs/config.md#effective-configuration-diffs) and ConfigKit's [v1.0.0 effective-configuration diff guidance](https://forge.maximumdirect.net/base-layer/configkit/src/tag/v1.0.0/docs/config.md#effective-configuration-diffs)
for the exact comparison contract. The operation compares only frozen effective for the exact comparison contract. The operation compares only frozen effective
configuration values: it does not reread external files or compare their configuration values: it does not reread external files or compare their
contents, resolved credential contents, later execution preparation, or contents, resolved credential contents, later execution preparation, or
@@ -621,7 +628,7 @@ copy, and credential behavior. The
interact with prompt definitions, layered profiles, built-ins, schemas, and interact with prompt definitions, layered profiles, built-ins, schemas, and
framework defaults. framework defaults.
For programmatic profiles, use [`ProfileSource`](../../profiles.go) with keyed For programmatic profiles, use [`ProfileSource`](../../profiles.go) with identified
`ProfileConfig` values. Nil fields are omitted; pointers preserve explicit `ProfileConfig` values. Nil fields are omitted; pointers preserve explicit
zero, false, and blank values. Raw `configkit.Mapping` expresses explicit null. zero, false, and blank values. Raw `configkit.Mapping` expresses explicit null.
@@ -634,13 +641,13 @@ and `WithBackend` options have no compatibility wrappers. Use
`DirectoryInputs` or `FilesystemInputs` for a strict-composition file group, `DirectoryInputs` or `FilesystemInputs` for a strict-composition file group,
ConfigKit file inputs for individual files, and `ProfileSource`, ConfigKit file inputs for individual files, and `ProfileSource`,
`BackendSource`, or `configkit.Mapping` for programmatic values. Backend IDs `BackendSource`, or `configkit.Mapping` for programmatic values. Backend IDs
are keys in configuration, not registrations. Choose caller underlays in are fields in configuration, not registrations. Choose caller underlays in
fallback-to-operator-to-programmatic order; use `Sources.Main` for one final fallback-to-operator-to-programmatic order; use `Sources.Main` for one final
highest-priority input. highest-priority input.
Move embedded IDs into keyed `profiles` and `prompts` maps; each prompt ID now Move resource IDs into identified `backends`, `profiles`, and `prompts` lists;
contains one installed definition, with any descriptive `version` label inside each prompt ID identifies one installed definition without a version label.
that definition. Convert `base_profile` to ConfigKit `extends`. For the current Convert `base_profile` to ConfigKit `extends: {id: parent}`. For the current
collection identity mapping, ID-only prompt selection, and required collection identity mapping, ID-only prompt selection, and required
caller-owned choices, see the caller-owned choices, see the
[configuration migration guide](configuration-migration.md). Exact current [configuration migration guide](configuration-migration.md). Exact current
@@ -656,7 +663,7 @@ application selects. PromptKit does not install provider catalogs or built-in
profile inventories; conventional backend ID constants are names only. Define profile inventories; conventional backend ID constants are names only. Define
the model, endpoint, credentials lookup, and settings that your application the model, endpoint, credentials lookup, and settings that your application
intends to support. A profile may inherit a sibling profile by its local key in intends to support. A profile may inherit a sibling profile by its local key in
the same root or collection mapping; its backend reference uses the exact the same root or collection list; its backend reference uses the exact
configured identity. Caller-selected source layers determine the final values. The configured identity. Caller-selected source layers determine the final values. The
[format reference](../formats.md) describes the definition fields and [format reference](../formats.md) describes the definition fields and
composition rules. composition rules.
@@ -729,8 +736,8 @@ it and shared backend identity or capacity policy is unnecessary:
```go ```go
endpoint, model := "http://localhost:8000/v1", "example-model" endpoint, model := "http://localhost:8000/v1", "example-model"
profile := promptkit.ProfileSource("local profile", map[string]promptkit.ProfileConfig{ profile := promptkit.ProfileSource("local profile", []promptkit.ProfileConfig{
"local-summary": {Endpoint: &endpoint, Model: &model}, {ID: "local-summary", Endpoint: &endpoint, Model: &model},
}) })
// Add configkit.Input{Source: profile} to a caller underlay. // Add configkit.Input{Source: profile} to a caller underlay.
``` ```
@@ -745,11 +752,13 @@ identity, endpoint, and concurrency limit:
```go ```go
backendID, model := promptkit.BackendLocal, "example-model" backendID, model := promptkit.BackendLocal, "example-model"
backend := promptkit.BackendSource("local backend", map[string]promptkit.BackendConfig{ localBackend := promptkit.LocalBackend("http://localhost:8000/v1", 2)
backendID: promptkit.LocalBackend("http://localhost:8000/v1", 2), localBackend.ID = backendID
backend := promptkit.BackendSource("local backend", []promptkit.BackendConfig{
localBackend,
}) })
profile := promptkit.ProfileSource("local profile", map[string]promptkit.ProfileConfig{ profile := promptkit.ProfileSource("local profile", []promptkit.ProfileConfig{
"local-summary": {Backend: &backendID, Model: &model}, {ID: "local-summary", Backend: &backendID, Model: &model},
}) })
// Add both sources as inputs in a caller underlay. // Add both sources as inputs in a caller underlay.
``` ```
@@ -760,13 +769,14 @@ capacity of 1024.
#### Configure A Complete Backend #### Configure A Complete Backend
Use a keyed `BackendConfig` value for authentication, extra request parameters, an Use an identified `BackendConfig` value for authentication, extra request parameters, an
explicit queue capacity, a custom ID, or multiple local endpoints: explicit queue capacity, a custom ID, or multiple local endpoints:
```go ```go
endpoint, keyName, limit, noWaiting := "http://gpu-host:8000/v1", "LOCAL_GPU_API_KEY", 2, 0 endpoint, keyName, limit, noWaiting := "http://gpu-host:8000/v1", "LOCAL_GPU_API_KEY", 2, 0
backend := promptkit.BackendSource("GPU backend", map[string]promptkit.BackendConfig{ backend := promptkit.BackendSource("GPU backend", []promptkit.BackendConfig{
"local-gpu": { {
ID: "local-gpu",
Endpoint: &endpoint, APIKeyEnv: &keyName, Endpoint: &endpoint, APIKeyEnv: &keyName,
ConcurrencyLimit: &limit, QueueCapacity: &noWaiting, ConcurrencyLimit: &limit, QueueCapacity: &noWaiting,
ExtraParams: map[string]any{"provider_option": "enabled"}, ExtraParams: map[string]any{"provider_option": "enabled"},
@@ -775,7 +785,7 @@ backend := promptkit.BackendSource("GPU backend", map[string]promptkit.BackendCo
``` ```
Place `backend` in a caller underlay and select `"local-gpu"` from a Place `backend` in a caller underlay and select `"local-gpu"` from a
`ProfileConfig.Backend` pointer or a keyed file profile. All backend `ProfileConfig.Backend` pointer or an identified file profile. All backend
contributions use the same ConfigKit layering rules, including overlays of contributions use the same ConfigKit layering rules, including overlays of
maintained definitions. The [`BackendConfig` and `LocalBackend` GoDoc](../../backends.go) maintained definitions. The [`BackendConfig` and `LocalBackend` GoDoc](../../backends.go)
defines exact omission and construction behavior. defines exact omission and construction behavior.
@@ -805,7 +815,7 @@ backend := promptkit.BackendConfig{
} }
``` ```
The pointer distinguishes an explicit zero from omission. Use keyed The pointer distinguishes an explicit zero from omission. Use identified
`BackendConfig` literals inside `BackendSource` for programmatic definitions. `BackendConfig` literals inside `BackendSource` for programmatic definitions.
Capacity belongs to one engine and the selected backend ID; endpoint-only Capacity belongs to one engine and the selected backend ID; endpoint-only
profiles and custom backends without a configured limit remain unrestricted. profiles and custom backends without a configured limit remain unrestricted.

View File

@@ -29,7 +29,7 @@ release_go_series=${release_go_series%.*}
go mod edit "-go=${release_go_series}.0" go mod edit "-go=${release_go_series}.0"
``` ```
For example, Go 1.26.8 normally results in `go 1.26.0`. Keep a higher patch For example, Go 1.27.1 normally results in `go 1.27.0`. Keep a higher patch
minimum if a dependency or identified correctness fix requires it. For a patch minimum if a dependency or identified correctness fix requires it. For a patch
release, leave the consumer minimum unchanged; using a newer validation release, leave the consumer minimum unchanged; using a newer validation
toolchain does not itself raise that minimum. If the candidate needs a higher toolchain does not itself raise that minimum. If the candidate needs a higher

View File

@@ -869,6 +869,13 @@ Validation: render/read affected GoDoc; check local document links and snippets
against implemented APIs. Keep current documentation free of obsolete contracts; against implemented APIs. Keep current documentation free of obsolete contracts;
old syntax may remain explicitly labeled in migration explanations and history. old syntax may remain explicitly labeled in migration explanations and history.
Completion: the consumer migration guide covers the breaking identified-list,
ConfigKit v1, Go 1.27, source-control, builder, inspection, and prompt-label
changes while retaining earlier deployment guidance. Updated consumer examples,
README, and release-toolchain guidance. Reviewed builder GoDoc and snippets,
checked local link targets and `git diff --check`; release selection and
publication remain separate.
## Stage 22: Verify The Integrated Sprint And Record Completion ## Stage 22: Verify The Integrated Sprint And Record Completion
Scope: acceptance review and residual corrections, not another feature stage. Scope: acceptance review and residual corrections, not another feature stage.