diff --git a/README.md b/README.md index 1d97536..0306e74 100644 --- a/README.md +++ b/README.md @@ -45,9 +45,10 @@ boundary and constraints that framework work must preserve. ## Release Guidance -The [v0.18.0 release notes](docs/releases/v0.18.0.md) cover recorded field -normalization, derived defaults in configuration inspection, and ConfigKit v1.1. -Execution behavior and the Go 1.27 minimum remain unchanged. +The [v0.18.0 release notes](docs/releases/v0.18.0.md) cover the default-on +OpenRouter backend and profiles, recorded configuration normalization, and +ConfigKit v1.1. The notes explain inventory changes and the bundle opt-out; +the Go 1.27 minimum remains unchanged. The [v0.17.0 release notes](docs/releases/v0.17.0.md) cover the vanity module path, ConfigKit v1, identified resource lists, removal of prompt-version diff --git a/docs/releases/v0.18.0.md b/docs/releases/v0.18.0.md index c8a6701..e44e560 100644 --- a/docs/releases/v0.18.0.md +++ b/docs/releases/v0.18.0.md @@ -5,6 +5,29 @@ and derived queue-capacity defaults through ConfigKit v1.1.0. Engines also include a default-on OpenRouter configuration. The minimum supported Go version remains 1.27.0. +## Bundled OpenRouter Backend And Profiles + +New engines include an embedded OpenRouter backend and seventeen root profiles: +ten latest-family aliases, the auto and free routers, and five auto-router +cost-tier variants. Select a profile explicitly in a prompt or request; the +bundle does not supply an implicit execution profile or contact providers +during construction. The backend uses `OPENROUTER_API_KEY` when available under +the existing optional-credential rules. + +The bundle is the lowest-priority underlay. Applications can replace its records +or derive named variants through ordinary configuration, and external collections +remain supported. Cost-tier variants inherit the effective `auto` profile, so +replacing that parent changes their inherited target while retaining plugins. +The [bundle reference](../formats.md#bundled-openrouter-configuration) owns the +inventory and composition details. + +Explicit smoke diagnostics now have OpenRouter authentication metadata and an +inference fallback profile. They remain opt-in and may incur provider costs. +Latest aliases and routers can change upstream; configured slugs do not pin +the concrete model, pricing, or availability. See the +[consumer guide](../consumers/pkg-promptkit.md#construct-an-engine) for selection +and opt-out examples. + ## Recorded Configuration Normalization Inspection shows normalized backend and profile settings, prompt metadata, and @@ -24,7 +47,7 @@ Inventory listings and inspection sources therefore change, and references to bundled IDs that previously failed may now resolve. Pass `promptkit.WithBundledOpenRouter(false)` to retain application-only behavior. Caller records can replace bundled definitions through ordinary composition; -see the [bundle inventory and precedence](../formats.md#bundled-openrouter-configuration). +same-ID replacements replace complete records rather than merging selected fields. No configuration-format migration is required from v0.17.0. Consumers that display or compare configuration inspection results should account for normalized values and derived defaults replacing their earlier authored diff --git a/docs/roadmap/bundled-openrouter.md b/docs/roadmap/bundled-openrouter.md deleted file mode 100644 index 5421352..0000000 --- a/docs/roadmap/bundled-openrouter.md +++ /dev/null @@ -1,246 +0,0 @@ -# Bundled OpenRouter Backend And Profiles - -## Status And Purpose - -Implemented: engine construction installs the embedded OpenRouter underlay by -default, with an option to disable it and ordinary caller composition. - -Ship a small OpenRouter configuration bundle with PromptKit so consumers -can begin using named profiles without installing a separate catalog. Include -the backend definition those profiles require. Keep separately maintained -operator collections fully supported through the existing configuration path. - -The bundle should favor provider-maintained latest aliases and routers, reducing -the need for PromptKit releases just to refresh individual model versions. -This is a convenience catalog, not an exhaustive model inventory or a promise -of stable upstream model behavior. - -## Historical Baseline - -PromptKit depends on ConfigKit v1.1.0 and records field normalization and derived -defaults during resolution. At that baseline it installed no backend or profile -definitions. Consumers supply configuration inputs, which ConfigKit composes -before PromptKit validates and materializes effective resources. - -The existing [configuration format](../formats.md) supports root and namespaced -resource lists, explicit IDs, sibling inheritance, and ordered underlays. -A higher-layer same-ID resource replaces the lower record in full. Inputs in -the same underlay group are strictly composed; file order is not precedence. -The bundle can use these mechanisms without introducing another catalog loader -or restoring the former dependency on provider-specific Go modules. - -ConfigKit v1.1.0's normalization and inspection support will apply to bundled -configuration just as it does to caller configuration. Layering itself predates -that release; no further upstream enhancement is required for this feature. - -## Target Behavior - -### Ordinary Embedded Configuration - -Embed a small YAML bundle in PromptKit and load it through the existing -ConfigKit adapter. Place it in its own lowest-priority underlay, before every -caller underlay and the main input. Preserve the existing order and grouping -of caller inputs. - -Enable the bundle by default, with `WithBundledOpenRouter(bool)` to disable or -enable it explicitly. -This follows the agreed convenience-oriented direction while preserving the -ability to supply an application's complete catalog. - -Bundling a profile makes it available for explicit selection by a prompt or -request. It does not establish an implicit execution profile, change profile -selection precedence, or send a network request during engine construction. -Credentials remain runtime inputs under the existing credential rules. - -Use ordinary configuration identities and expose the bundle through existing -listing and inspection APIs. Source explanations should identify embedded -configuration meaningfully. There is no need for a parallel built-in catalog -API or special provenance model. - -### Root Resource Layout - -Use root entries for both the backend and all built-in profiles. The backend -ID is `openrouter`; each bundled profile supplies or inherits -`backend: openrouter` and is selected using its unqualified ID. No built-in `openrouter` collection is -created, so an externally supplied collection can expose names such as -`openrouter/gpt-sol-latest` alongside the root `gpt-sol-latest` profile. - -Built-ins at the root and external libraries under `collections` is a -convention, not an enforced distinction. Applications may supply root entries, -override built-ins, and organize external configuration using either form. -Root names favor convenient selection; their backend remains explicit in the -definition and inspection even though it is absent from the profile ID. - -### OpenRouter Backend - -Include the root `openrouter` backend with OpenRouter's API base endpoint, -`https://openrouter.ai/api/v1`, and the conventional environment-variable name -`OPENROUTER_API_KEY`. Store the name only; no credential value belongs in the -bundle. Reuse the existing OpenAI-compatible client and credential resolution. - -Keep the backend minimal. Leave concurrency limits, queue policy, and provider -request parameters to existing defaults or application configuration. - -### Smoke-Test Defaults - -Include the following metadata on the root `openrouter` backend: - -```yaml -smoke_tests: - default_profile: gpt-luna-latest - authentication: - kind: openrouter_key -``` - -Omit the reachability endpoint to use the existing backend-endpoint fallback. -Omit the authentication endpoint to use the adapter's backend-relative `/key` -destination. OpenRouter documents the authenticated -[current-key endpoint](https://openrouter.ai/docs/api/api-reference/api-keys/get-current-api-key). - -Use `gpt-luna-latest` as the inference diagnostic default when the caller supplies -neither a prompt nor a profile. Explicit prompt/profile selection continues to -follow existing smoke-test selection rules. The default names the effective -root profile, so an application replacement of that profile also affects this -fallback. Applications can change the backend metadata through ordinary -configuration composition. - -These defaults make explicit diagnostics usable without additional setup; they -do not run tests automatically or establish a default for ordinary prompt -execution. Results describe the selected diagnostic path, not backend-wide -readiness. The inference smoke test makes a small request with potentially -non-zero cost; no fixed cost or model-availability guarantee is introduced. - -### Small Profile Set - -The initial set contains seventeen root profiles: - -| Profile ID | Intended model selection | -| --- | --- | -| `gpt-astra-latest` | OpenAI GPT Astra latest-family alias through OpenRouter. | -| `gpt-sol-latest` | OpenAI GPT Sol latest-family alias (`~openai/gpt-sol-latest`). | -| `gpt-terra-latest` | OpenAI GPT Terra latest-family alias through OpenRouter. | -| `gpt-luna-latest` | OpenAI GPT Luna latest-family alias through OpenRouter. | -| `claude-fable-latest` | Anthropic Claude Fable latest-family alias through OpenRouter. | -| `claude-opus-latest` | Anthropic Claude Opus latest-family alias through OpenRouter. | -| `claude-sonnet-latest` | Anthropic Claude Sonnet latest-family alias through OpenRouter. | -| `claude-haiku-latest` | Anthropic Claude Haiku latest-family alias through OpenRouter. | -| `gemini-pro-latest` | Google Gemini Pro latest-family alias through OpenRouter. | -| `gemini-flash-latest` | Google Gemini Flash latest-family alias through OpenRouter. | -| `auto` | OpenRouter auto router (`openrouter/auto`). | -| `auto-low` | Inherits `auto`; sets cost tier `low`. | -| `auto-medium` | Inherits `auto`; sets cost tier `medium`. | -| `auto-high` | Inherits `auto`; sets cost tier `high`. | -| `auto-xhigh` | Inherits `auto`; sets cost tier `xhigh`. | -| `auto-max` | Inherits `auto`; sets cost tier `max`. | -| `free` | OpenRouter free-model router (`openrouter/free`). | - -These profile IDs are selected. The companion [implementation plan](implementation.md) -records the exact provider `model` slugs checked against the public alias pages. -Keep those mappings explicit rather than deriving them mechanically from IDs. -If a requested alias becomes unavailable, surface that mismatch -instead of silently substituting a pinned model or dropping the profile. -The tilde and slash in a provider model slug remain part of that value; they -do not change the root placement of the PromptKit profile. - -Define each cost-tier profile using `extends: {id: auto}` and the matching -`cost_tier` inside an `auto-router` plugin entry under `extra_params.plugins`: - -```yaml -profiles: - - id: auto - backend: openrouter - model: openrouter/auto - - id: auto-medium - extends: {id: auto} - extra_params: - plugins: - - id: auto-router - cost_tier: medium -``` - -Keep the base `auto` profile without an explicit cost tier. Link to -[OpenRouter's cost-tier documentation](https://openrouter.ai/docs/guides/routing/routers/auto-router#cost-tier) -for routing semantics rather than duplicating that explanation here. - -Each profile should primarily specify or inherit its backend and model. Avoid -baking in temperature, reasoning, token-budget, timeout, or capability assumptions merely -to make profiles appear more complete. Operator profiles remain the place for -application-specific tuning and fixed model versions. - -OpenRouter documents the -[GPT Sol latest alias](https://openrouter.ai/~openai/gpt-sol-latest), -[auto router](https://openrouter.ai/docs/guides/routing/routers/auto-router), and -[free router](https://openrouter.ai/docs/guides/routing/routers/free-router). -Stable selectors reduce maintenance but do not freeze model selection, price, -availability, supported parameters, or output behavior. Describe the free router -as the provider's offering rather than adding PromptKit guarantees about future -pricing or availability. - -### Application Control And Compatibility - -Applications may replace bundled records through higher configuration layers or -disable the bundle and supply their own definitions. No namespace is reserved -against operator use. A same-ID replacement is a complete replacement, so an -application supplying only a new model value does not inherit the replaced -profile's backend. A distinct sibling using `extends` remains the ordinary way -to create a variant while retaining base fields. - -These replacement semantics describe ordinary identified-list upsert behavior. -Honor explicit ConfigKit sequence modes as well: `append` rejects duplicate -identities, while `replace` replaces the complete lower list. The bundle adds no -special conflict handling or exception to those composition rules. - -Loading definitions by default changes inventory and inspection results, and -previously unresolved references matching bundled IDs may become resolvable. -Document these effects. Higher-layer application records take precedence under -the applicable ConfigKit composition mode. Changing a bundled backend may -also affect surviving bundled profiles that reference it; that is ordinary -backend completion, not a special override exception. - -The five cost-tier profiles inherit from the effective `auto` profile. An -application replacement of `auto` can therefore change their inherited backend -or model while their OpenRouter plugin settings remain present. Cover this -interaction in a focused test and a short example note; it does not require a -new restriction on replacing the parent. - -Bundled profile and backend IDs are consumer-facing names. Review future removal -or repurposing through the ordinary compatibility process, since application -configuration may reference them. This does not introduce a separate catalog -lifecycle or a guarantee that upstream aliases retain fixed behavior. - -The embedded data ships with the PromptKit release. No catalog download or -automatic refresh mechanism is planned. Provider aliases and routers may change -their targets independently of that release; the inspected configured slug -does not identify or pin the concrete model selected upstream. - -## Acceptance And Documentation - -The companion implementation plan owns the staged work. The integrated result -should demonstrate: - -- Default availability and full disabling through the ordinary configuration - lifecycle, without construction-time provider or credential access. -- Caller precedence, whole-record replacement, inherited variants, explicit - append/replace modes, and coexistence with an external OpenRouter collection. -- All five cost-tier profiles inheriting the effective `auto` backend/model, - retaining their plugin settings even after parent replacement, and producing - the expected top-level `plugins` array through the built-in HTTP client. -- Listing and inspection of effective definitions with meaningful source evidence. -- Explicit smoke diagnostics using backend endpoint fallbacks, authentication, - inference defaults, explicit selection precedence, and effective application - replacements of the default profile or backend metadata. - -Offline HTTP tests establish payload construction, not provider acceptance. -Credential-dependent live checks are not recurring test requirements. Existing -credential behavior remains authoritative; coverage should focus on new -integration risks rather than duplicate that suite. - -The format reference, consumer guide, relevant GoDoc, and maintained examples -should explain disabling, replacement, and inheritance. Release notes should -identify inventory and inspection changes. Provider latest aliases and routers -remain distinct from fixed models and carry no PromptKit upstream guarantees. - -Keep current-state documentation unchanged until implementation lands. Retire -this roadmap after the implemented behavior reaches its durable owners. No new -configuration syntax or collection specification version is needed solely to -distribute this data. diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md deleted file mode 100644 index 8a7ce03..0000000 --- a/docs/roadmap/implementation.md +++ /dev/null @@ -1,304 +0,0 @@ -# Bundled OpenRouter Implementation Plan - -Implement [bundled-openrouter.md](bundled-openrouter.md) in the sequential stages -below. Each stage is one Luna-sized assignment. The feature roadmap owns scope -and consumer policy; this document owns the implementation sequence and choices. - -## Baseline And Working Rules - -The baseline is `9e05c3a`: Go 1.27.0, ConfigKit v1.1.0, recorded field -normalization, and no installed backend/profile catalog. The facade in -`engine.go` applies options; `internal/engine.New` passes caller configuration -to `internal/configuration.Load` before assembling execution collaborators. - -Read `docs/development.md` and applicable agent, architecture, testing, -documentation, OSS, and release policies. Follow -[ADR 0001](../adr/0001-configuration-boundary.md). Reuse current source-loading, -generation, and smoke-diagnostic contracts. Preserve unrelated changes. - -This is one end-to-end sprint: intermediate stages need not compile or form a -deployable state. Do not introduce compatibility scaffolding or intermediate -human-review/publication gates. Record incomplete checks honestly and reuse -successful checks for unchanged content. Do not publish a release or make paid -provider requests. No dependency upgrade, configuration-version change, or -provider-specific catalog module is required. - -## Implementation Choices - -- Add `internal/configuration/bundled/openrouter.yaml` and embed it from a small - `bundled.go` in that package. Provide an internal exported - `BundledOpenRouterUnderlay() configkit.Underlay` for engine assembly. It returns - one input created through `configkit.NewFilesystem` and its `File` method, - with a meaningful label such as `Promptkit bundled OpenRouter`. -- Use the existing source loader once. Do not independently parse, validate, - normalize, or cache a separate bundle registry before final composition. - Tests inspect the assembled effective configuration, not raw-source validity. -- Prepend the bundle as its own underlay in `internal/engine.New`. Allocate a - new outer slice and copy caller groups so spare slice capacity cannot let - assembly mutate caller-owned input. Preserve every caller group's contents, - order, main input, imports, and source context. -- Add `WithBundledOpenRouter(enabled bool) Option` in the facade. Add - `disableBundledOpenRouter bool` to internal engine options and a setter - `SetBundledOpenRouter(bool)` following existing setter style. The zero internal - options value enables the bundle; the setter stores `!enabled`. Apply options - in the existing order, so the last supplied bundle option wins. The facade - only delegates; embedding and composition stay internal. -- Disabled means no bundle source or definitions are installed. It does not - reserve names, remove caller definitions, or disable the OpenAI-compatible - client. Scoped views share the engine's captured configuration; they do not - reload the bundle. -- Keep the root backend and profiles described below. No built-in collection, - prompts, implicit execution profile, tuning defaults, catalog download, or - constructor-time provider/credential access is added. - -## Exact Data To Install - -The root backend is `openrouter`, with endpoint `https://openrouter.ai/api/v1`, -`api_key_env: OPENROUTER_API_KEY`, and: - -```yaml -smoke_tests: - default_profile: gpt-luna-latest - authentication: - kind: openrouter_key -``` - -Leave concurrency, queue, provider parameters, and diagnostic endpoint overrides -unset. Existing reachability and authentication endpoint fallback applies. - -Use these exact root profile IDs and model values. Each non-cost-tier profile -sets `backend: openrouter`. The ten family mappings were checked against the -linked provider pages on 2026-11-03; this is authoring evidence, not a guarantee -of future availability or a recurring release check. - -| Profile ID | Model | Provider reference | -| --- | --- | --- | -| `gpt-astra-latest` | `~openai/gpt-astra-latest` | [Alias](https://openrouter.ai/~openai/gpt-astra-latest) | -| `gpt-sol-latest` | `~openai/gpt-sol-latest` | [Alias](https://openrouter.ai/~openai/gpt-sol-latest) | -| `gpt-terra-latest` | `~openai/gpt-terra-latest` | [Alias](https://openrouter.ai/~openai/gpt-terra-latest) | -| `gpt-luna-latest` | `~openai/gpt-luna-latest` | [Alias](https://openrouter.ai/~openai/gpt-luna-latest) | -| `claude-fable-latest` | `~anthropic/claude-fable-latest` | [Alias](https://openrouter.ai/~anthropic/claude-fable-latest) | -| `claude-opus-latest` | `~anthropic/claude-opus-latest` | [Alias](https://openrouter.ai/~anthropic/claude-opus-latest) | -| `claude-sonnet-latest` | `~anthropic/claude-sonnet-latest` | [Alias](https://openrouter.ai/~anthropic/claude-sonnet-latest) | -| `claude-haiku-latest` | `~anthropic/claude-haiku-latest` | [Alias](https://openrouter.ai/~anthropic/claude-haiku-latest) | -| `gemini-pro-latest` | `~google/gemini-pro-latest` | [Alias](https://openrouter.ai/~google/gemini-pro-latest) | -| `gemini-flash-latest` | `~google/gemini-flash-latest` | [Alias](https://openrouter.ai/~google/gemini-flash-latest) | -| `auto` | `openrouter/auto` | [Router](https://openrouter.ai/docs/guides/routing/routers/auto-router) | -| `free` | `openrouter/free` | [Router](https://openrouter.ai/docs/guides/routing/routers/free-router) | - -The five remaining profiles are `auto-low`, `auto-medium`, `auto-high`, -`auto-xhigh`, and `auto-max`. Each uses `extends: {id: auto}` and only adds -`extra_params.plugins: [{id: auto-router, cost_tier: TIER}]`, where TIER is its -suffix. Do not duplicate backend/model in these children: they inherit the -effective parent, including an application replacement. Base `auto` sets no -cost tier. OpenRouter documents these five values and plugin spelling in its -[cost-tier contract](https://openrouter.ai/docs/guides/routing/routers/auto-router#cost-tier). -The [current-key endpoint](https://openrouter.ai/docs/api/api-reference/api-keys/get-current-api-key) -documents the existing authentication adapter's destination. - -Preserve `~` and `/` in model values; neither makes the profile namespaced. -Do not add sampling, reasoning, timeout, token, or capability settings. If -contradictory provider evidence appears, report it rather than silently selecting -a fixed model or dropping a requested profile. A credentialed generation probe -is not needed to implement this data-backed plan. - -## Stage 1: Add The Embedded Configuration Source - -Scope: new YAML and small helper in `internal/configuration`. - -1. Define one root backend and seventeen root profiles exactly as above. Use - ordinary identified lists and ConfigKit sibling inheritance for the five - cost-tier children. No collection wrapper or prompt definitions are needed. -2. Embed the file with `embed.FS`; expose only the internal underlay helper. - Use a fresh public ConfigKit source/context for loading, without mutable - package-level decoded data or filesystem discovery. -3. Add a focused loader-level test composing that underlay through `Load`. - Check the effective backend, the selected profile/model mapping, cost-tier - inheritance, smoke metadata, and meaningful source evidence. These assertions - protect the chosen catalog contents, not upstream model availability. -4. Do not create raw-YAML validation or live-provider tests. No public catalog - export, custom parser, catalog dependency, or parallel registry is needed. - -Validation: `go test ./internal/configuration` after the helper is wired. - -Completion: the embedded OpenRouter underlay and loader-level catalog test are -in place; the focused configuration suite passed with Go 1.27.0. - -## Stage 2: Enable The Bundle Through Engine Construction - -Scope: facade/internal options, assembly, and default/disabled contract tests. - -1. Implement the option and default-on internal flag as specified. Prepend the - underlay only when enabled, using a new outer slice. Keep schema/client/ - artifact options and main-source handling unchanged. -2. Add external-package facade tests showing `NewEngine(Config{})` exposes the - root backend and all seventeen profiles, but creates no prompts or synthetic - `openrouter` collection. Exercise representative `InspectProfile` values and - `InspectConfiguration` source explanations. -3. Test false disables installation, true retains it, and option ordering follows - ordinary last-option behavior. With false, caller-owned `openrouter` records - remain available. Construction succeeds with the API-key variable unset and - an HTTP transport that rejects unexpected calls. -4. Verify assembly leaves caller underlay slice/backing-array contents unchanged. -5. Adapt preexisting tests whose intended fixture is an application-only or empty - catalog by explicitly disabling the bundle in their local helpers. Update - default-inventory expectations where that is the behavior under test. Do not - globally hide default-on behavior or weaken not-found/validation assertions. - Internal direct configuration-loader tests do not need to install the bundle. - -Validation: focused construction/listing/inspection tests, then -`go test ./internal/engine ./...` when intermediate wiring is coherent. - -Completion: engine construction installs the bundle by default, with an -ordered opt-out option and a copied underlay slice. Facade contracts and the -full Go suite pass with Go 1.27.0. - -## Stage 3: Protect Composition And Application Control - -Scope: focused real-loader integration tests through the facade. - -1. Verify a caller underlay and then the main input can replace a bundled ID in - order, and caller strict groups remain strict. Demonstrate complete record - replacement: a model-only replacement does not recover the old backend. - Preserve partial-profile support rather than demanding construction readiness. -2. Verify a distinct profile extending a bundled profile retains inherited - fields and applies selected overrides. Add an application-provided OpenRouter - collection with qualified references; root and collection profiles coexist. -3. Replace root backend `openrouter` with a complete local endpoint definition. - Confirm surviving bundled profiles use the replacement backend's settings. - No reserved-ID checks or special merge semantics are added. -4. Replace root `auto` with a profile selecting a different caller backend and - model. All five cost-tier children must inherit that target and retain their - plugin entries. Do not reject this customization or strip plugin settings. -5. Exercise explicit sequence modes using ConfigKit's existing controls: - `config.sequences: [{destination: [profiles], mode: append}]` with a duplicate - bundled ID fails normally; `mode: replace` with an application profile list - replaces all lower profiles. Include a nonconflicting append case. Keep - backend/profile references valid where testing successful replacement. -6. Show that clearing/replacing backend definitions without maintaining surviving - profile references follows existing validation, not a hidden fallback. - Disabling the bundle remains the simple application-only configuration path. - -Validation: targeted new composition tests plus existing source, inheritance, -namespace, and profile-completion tests. Avoid reproducing ConfigKit's generic -sequence implementation suite. - -Completion: facade integration tests cover caller precedence, whole-record -replacement, inheritance, scoped resources, sequence modes, strict conflicts, -and missing backend rejection. Targeted tests pass on Go 1.27.0. - -## Stage 4: Verify Preparation And HTTP Request Construction - -Scope: bundled-profile execution integration with existing runner/client paths. - -1. With a minimal caller prompt and an injected deterministic client, prepare - and run using an explicit bundled profile. Check selected profile/backend, - model slug, and ordinary defaults/overrides. A prompt with no default and - no request profile must still produce the existing profile-required error. -2. For every cost tier, use the built-in HTTP client and an offline recording - RoundTripper or local server to inspect the outbound JSON. Assert the model - is `openrouter/auto` and `plugins` is a top-level array with the matching - `auto-router`/`cost_tier` entry, not nested under an `extra_params` member. -3. Verify base `auto` sends no explicit cost-tier plugin and `free` preserves - `openrouter/free`. Check at least one `~`-prefixed model reaches the request - unchanged. Return a minimal valid synthetic chat response. -4. Reuse existing runtime credential tests and override tests. Add only missing - bundle integration assertions, such as selecting `OPENROUTER_API_KEY` from - the installed backend. No real credentials, calls, provider capability - assumptions, hardcoded prices, or changes to optional-key behavior are needed. - -Validation: new request cases and existing generation/profile/override tests. -Offline HTTP assertions prove payload construction, not provider acceptance. - -Completion: offline preparation, injected-client execution, and HTTP payload -tests verify profile selection, overrides, credentials, router plugins, and model -slugs. Focused execution tests pass on Go 1.27.0. - -## Stage 5: Verify Bundled Smoke-Test Defaults - -Scope: facade-level smoke integration with a synthetic HTTP boundary. - -1. On a default engine, explicitly request reachability with - `BackendID: openrouter`. Verify the existing backend-endpoint fallback. - Authentication should select the `openrouter_key` adapter and - `https://openrouter.ai/api/v1/key`, using an isolated synthetic key and a - recording transport. Return the existing adapter's minimal success fixture. -2. For text and structured inference, specify the backend without prompt/profile. - Assert fallback to `gpt-luna-latest` and its exact model slug. Return suitable - private-case responses using the existing smoke-test fixtures. Preserve - factual reports and nil-error concluded-failure semantics. -3. Show explicit profile selection wins over prompt default and backend metadata, - and a prompt default wins over backend metadata when no profile is supplied. - Smoke tests must still use their private cases, not execute caller prompt - content or output contracts. -4. Replace `gpt-luna-latest` through application configuration and verify fallback - uses the effective replacement. Replace backend smoke metadata to select a - different caller profile and confirm the ordinary selection path follows it. -5. Verify listing/inspection are not modified by diagnostics. Keep the existing - rule that diagnostics run only on explicit invocation; no new constructor, - ordinary-run, CI, or release probe is introduced. - -Validation: targeted bundled smoke tests and existing smoke contract/integration -tests. Reuse existing endpoint/auth fixtures instead of adding an adapter or -duplicating the full diagnostic suite. - -Completion: offline smoke tests verify reachability, authentication, both -inference cases, fallback and override selection, replacement behavior, and -unchanged inspection. Targeted smoke tests pass on Go 1.27.0. - -## Stage 6: Update Documentation And Verify The Sprint - -Scope: public GoDoc, current guidance/examples, and end-to-end verification. - -1. Update `ConfigurationSources`, `Config`/`NewEngine`, and new-option GoDoc to - describe the dedicated lower underlay, default-on behavior, disabling, and - changed inventories. Keep exact option semantics in GoDoc. -2. Update `docs/formats.md` and `docs/consumers/pkg-promptkit.md` with the bundle, - root layout, explicit selection, optional credentials, smoke fallback, and - disabling/whole-record replacement/inherited-variant examples. Make one - canonical bundle inventory in the format reference; link rather than repeat - it throughout guidance. Link provider docs for alias/router behavior. -3. Remove stale claims of no installed catalogs from current migration guidance - and internal source/assembly documentation. Explain that an external - collection is still supported, and replacing `auto` changes inherited child - targets while retaining plugins. Do not add a rule that external catalogs - must be namespaced or upstream aliases must have fixed capabilities. -4. Keep the three maintained examples offline. Where their caller-only inventories - are intentional, pass `WithBundledOpenRouter(false)` and explain that choice; - retain useful fixture assertions rather than expanding them with unrelated - default inventory. Add a short consumer-guide bundled-profile example instead - of another live example program. Recheck README quickstart claims. -5. Add the feature and compatibility effects to the currently untagged - `docs/releases/v0.18.0.md`, including how to retain application-only behavior. - Explain that previously unresolved references matching bundled IDs can now - resolve, alongside the changed default inventories and inspection sources. - If that release has been published by implementation time, use the next - unreleased minor note instead; preserve published notes/tags. Follow the - release procedure for the note/footer. No release operation is part of this - sprint. -6. Format changes, prepare dependency caches, and run with the compatible local - Go toolchain: - - ```sh - go test -race -vet=off ./... - go vet ./... - go run ./examples/go-library/prepare - go run ./examples/go-library/run - go run ./examples/go-library/observe - git diff --check - ``` - -7. Review the complete diff for unexpected API changes, caller mutation, new - source/history validation, implicit selection, network access, credential - values, and stale links. Confirm only intended documentation and inventories - changed. Follow the focused commit policy and record completion in the - feature roadmap; retire completed plans during release preparation. - -Completion requires default availability, full disabling, ordinary caller -composition and provenance, correct cost-tier payloads and explicit diagnostic -fallbacks, and current documentation. There are no unresolved product choices, -external publication prerequisites, or new recurring release gates. - -Completion: public guidance, GoDoc, offline examples, and the unreleased v0.18.0 -note describe the bundle and opt-out. The race-enabled suite, vet, three example -commands, and diff checks passed on Go 1.27.0; no release was published.