From 2b3d165ce281101a4cd9da58cf2bd72e11ea7cc4 Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Tue, 3 Nov 2026 15:39:04 +0000 Subject: [PATCH] Document the bundled OpenRouter configuration --- README.md | 2 + docs/consumers/configuration-migration.md | 2 +- docs/consumers/pkg-promptkit.md | 32 +++++++++++-- docs/formats.md | 55 +++++++++++++++++++++-- docs/internal/sources.md | 4 +- docs/releases/v0.18.0.md | 13 ++++-- docs/roadmap/bundled-openrouter.md | 7 +-- docs/roadmap/implementation.md | 4 ++ engine.go | 9 ++-- examples/go-library/observe/main.go | 2 +- examples/go-library/prepare/main.go | 2 +- examples/go-library/run/main.go | 2 +- 12 files changed, 114 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index a20710e..1d97536 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,8 @@ source-relative prompt content, supplies an inline input, and prepares through a scoped view. The example also demonstrates collection inventories and namespace-filtered discovery, without contacting a provider or requiring credentials. +The example disables the bundled OpenRouter configuration to keep its +inventories limited to its own offline fixtures. The [consumer guide](docs/consumers/pkg-promptkit.md) also shows a local backend, ordered file/embedded sources, programmatic mappings, and how to replace an engine when source files change. Applications adapting the prior keyed diff --git a/docs/consumers/configuration-migration.md b/docs/consumers/configuration-migration.md index 337315b..400b2b9 100644 --- a/docs/consumers/configuration-migration.md +++ b/docs/consumers/configuration-migration.md @@ -3,7 +3,7 @@ This breaking pre-v1 minor migration adopts Promptkit's vanity module path, changes the v0.16-era keyed resources to identified lists, adopts ConfigKit v1, and removes prompt-version labels. -Promptkit does not install a provider catalog; applications choose configuration +Promptkit installs a default-on bundled OpenRouter 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 automatic migration tool. The [framework format reference](../formats.md) owns diff --git a/docs/consumers/pkg-promptkit.md b/docs/consumers/pkg-promptkit.md index a7c5ea9..255ebc9 100644 --- a/docs/consumers/pkg-promptkit.md +++ b/docs/consumers/pkg-promptkit.md @@ -52,6 +52,32 @@ Create an engine with [`NewEngine`](../../engine.go). Select each directory explicitly and place its inputs in an ordered ConfigKit underlay. A group strictly composes its files; later groups can overlay earlier ones: +The bundled OpenRouter backend and profiles are installed in a lower underlay +by default. Select a profile explicitly, for example: + +```go +input := configkit.Input{Source: configkit.Mapping("application", map[string]any{ + "prompts": []any{map[string]any{ + "id": "my-prompt", + "messages": []any{map[string]any{"role": "user", "content": "Hello"}}, + "output": map[string]any{"format": "text", "validation_mode": "none"}, + }}, +})} +engine, err := promptkit.NewEngine(promptkit.Config{Sources: promptkit.ConfigurationSources{Main: &input}}) +if err != nil { return err } +result, err := engine.Run(ctx, promptkit.RunRequest{PromptID: "my-prompt", ProfileID: "gpt-luna-latest"}) +``` + +The backend looks up +`OPENROUTER_API_KEY` when available; credentials are not required at engine +construction. For the complete inventory and diagnostic defaults see the +[format reference](../formats.md#bundled-openrouter-configuration). Use +`promptkit.WithBundledOpenRouter(false)` for application-only inventories. +Caller records replace matching bundled records in full; use `extends` with a +distinct ID to inherit. Replacing `auto` also changes its cost-tier children's +inherited target, while their plugins remain. External collections remain +supported. + ```go promptInputs, err := promptkit.DirectoryInputs("prompts") if err != nil { return err } @@ -665,9 +691,9 @@ the engine to pick up changed definitions or message files. ### Choose A Profile Ownership Model Supply backend and profile definitions through the configuration sources your -application selects. PromptKit does not install provider catalogs or built-in -profile inventories; conventional backend ID constants are names only. Define -the model, endpoint, credentials lookup, and settings that your application +application selects, alongside the default-on bundled OpenRouter inventory. +Conventional backend ID constants are names only. Define or replace 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 the same root or collection list; its backend reference uses the exact configured identity. Caller-selected source layers determine the final values. The diff --git a/docs/formats.md b/docs/formats.md index ef54356..ad7f38e 100644 --- a/docs/formats.md +++ b/docs/formats.md @@ -14,8 +14,8 @@ A configuration document may contain top-level `backends`, `profiles`, and `prompts` lists, plus a `collections` mapping of namespaced resource groups. Each resource has an explicit literal `id`, not a filename-derived identity. IDs and references must be nonblank and remain exact: Promptkit does not trim or -re-key them. Unknown fields are errors. Promptkit installs no provider or -profile catalog; callers select the definitions they need. +re-key them. Unknown fields are errors. Promptkit installs a default-on bundled +OpenRouter underlay; callers still explicitly select a profile. ```yaml backends: @@ -332,9 +332,58 @@ For example, a runtime `extra_params["extends"]` key is ordinary provider data, not a configuration inheritance instruction. An explicit zero timeout does not disable the caller context or HTTP transport timeout. +### Bundled OpenRouter Configuration + +The default bundle installs root backend `openrouter`, endpoint +`https://openrouter.ai/api/v1`, optional credential environment name +`OPENROUTER_API_KEY`, and smoke metadata selecting `gpt-luna-latest` with the +`openrouter_key` authentication adapter. Existing diagnostic endpoint fallback +applies. No prompt, implicit profile selection, or tuning defaults are installed. +Disable the entire bundle with `WithBundledOpenRouter(false)`. + +The root profile IDs and their models are: + +| Profile | Model | +| --- | --- | +| `gpt-astra-latest` | `~openai/gpt-astra-latest` | +| `gpt-sol-latest` | `~openai/gpt-sol-latest` | +| `gpt-terra-latest` | `~openai/gpt-terra-latest` | +| `gpt-luna-latest` | `~openai/gpt-luna-latest` | +| `claude-fable-latest` | `~anthropic/claude-fable-latest` | +| `claude-opus-latest` | `~anthropic/claude-opus-latest` | +| `claude-sonnet-latest` | `~anthropic/claude-sonnet-latest` | +| `claude-haiku-latest` | `~anthropic/claude-haiku-latest` | +| `gemini-pro-latest` | `~google/gemini-pro-latest` | +| `gemini-flash-latest` | `~google/gemini-flash-latest` | +| `auto` | `openrouter/auto` | +| `free` | `openrouter/free` | + +The profiles `auto-low`, `auto-medium`, `auto-high`, `auto-xhigh`, and +`auto-max` extend `auto` and add an `auto-router` plugin with the corresponding +`cost_tier`. Replacing `auto` changes their inherited backend and model while +retaining their plugins. These are root IDs even when a model contains `/`. +For example, a caller can replace `auto` as a complete record and extend another +bundled profile under a new ID: + +```yaml +profiles: + - id: auto + backend: openrouter + model: openrouter/free + - id: my-luna + extends: {id: gpt-luna-latest} + timeout_seconds: 60 +``` + +See OpenRouter's [alias examples](https://openrouter.ai/~openai/gpt-luna-latest), +[auto router and cost tiers](https://openrouter.ai/docs/guides/routing/routers/auto-router), +and [free router](https://openrouter.ai/docs/guides/routing/routers/free-router) +for provider behavior and availability. + ### Source And Profile Precedence -`NewEngine` composes caller underlays in their given order, followed by an +`NewEngine` composes the bundled OpenRouter underlay first by default, then +caller underlays in their given order, followed by an optional main input. Later layers overlay earlier ones. Inputs within one underlay group are strictly composed: conflicting contributions are errors, not priority signals. The directory helpers discover `.yaml` and `.yml` files recursively diff --git a/docs/internal/sources.md b/docs/internal/sources.md index 4f66740..ead6dbf 100644 --- a/docs/internal/sources.md +++ b/docs/internal/sources.md @@ -52,7 +52,9 @@ captured values without consulting ConfigKit or copying resource definitions. The root `DirectoryInputs` and `FilesystemInputs` helpers discover sorted YAML files under an explicit root, provide resource context, and leave imports disabled. Each returned slice belongs to one strict-composition group; file -order does not confer priority. Caller underlays are composed in their given +order does not confer priority. Engine assembly prepends a dedicated embedded +OpenRouter underlay unless disabled, without modifying caller-owned slices. +Caller underlays are composed in their given order, followed by the optional main input. The [configuration tests](../../internal/configuration/load_test.go) exercise the real loader and final-value handoff. diff --git a/docs/releases/v0.18.0.md b/docs/releases/v0.18.0.md index 315a782..c8a6701 100644 --- a/docs/releases/v0.18.0.md +++ b/docs/releases/v0.18.0.md @@ -1,8 +1,9 @@ # Promptkit v0.18.0 Configuration inspection now exposes Promptkit's recorded field normalization -and derived queue-capacity defaults through ConfigKit v1.1.0. Execution behavior -is unchanged, and the minimum supported Go version remains 1.27.0. +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. ## Recorded Configuration Normalization @@ -18,7 +19,13 @@ overrides; see the [configuration inspection guide](../consumers/pkg-promptkit.m ## Compatibility And Upgrade -No application-code or configuration-format migration is required from v0.17.0. +New engines install a bundled OpenRouter backend and root profiles by default. +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). +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 representations. Request-time overrides and caller-appended messages retain diff --git a/docs/roadmap/bundled-openrouter.md b/docs/roadmap/bundled-openrouter.md index fed3755..5421352 100644 --- a/docs/roadmap/bundled-openrouter.md +++ b/docs/roadmap/bundled-openrouter.md @@ -2,7 +2,8 @@ ## Status And Purpose -Design decisions settled; implementation has not started. +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 @@ -14,10 +15,10 @@ 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. -## Current Baseline +## Historical Baseline PromptKit depends on ConfigKit v1.1.0 and records field normalization and derived -defaults during resolution. It currently installs no backend or profile +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. diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index 783a056..8a7ce03 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -298,3 +298,7 @@ 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. diff --git a/engine.go b/engine.go index eb6d794..a8e5649 100644 --- a/engine.go +++ b/engine.go @@ -101,8 +101,9 @@ type Engine struct { } // ConfigurationSources selects ordered ConfigKit underlays and an optional -// highest-priority main input. Each underlay's inputs strictly compose within -// their group; later underlays overlay earlier ones. A nil Main uses +// highest-priority main input. By default a bundled OpenRouter underlay precedes +// the caller underlays; [WithBundledOpenRouter] can disable it. Inputs within +// each underlay strictly compose; later underlays overlay earlier ones. A nil Main uses // ConfigKit's empty source. A non-nil Main is passed through unchanged and // may fail construction if invalid. type ConfigurationSources struct { @@ -222,7 +223,9 @@ func WithSchemaFile(path string) Option { // NewEngine constructs an Engine from configuration and options. // // ConfigKit composes caller-selected underlays in their given order, followed -// by the optional main input. Construction validates the final effective +// by the optional main input, after the default-on bundled OpenRouter underlay. +// The bundle adds a root backend and profiles to inventories, but no prompts +// or implicit profile selection. Construction validates the final effective // backend, profile, and prompt definitions and captures referenced prompt // content. A missing prompt collection is allowed. Schema documents and // request artifacts remain runtime resources. diff --git a/examples/go-library/observe/main.go b/examples/go-library/observe/main.go index af18f24..7362cbc 100644 --- a/examples/go-library/observe/main.go +++ b/examples/go-library/observe/main.go @@ -98,7 +98,7 @@ func run() (summary, error) { engine, err := promptkit.NewEngine(promptkit.Config{ Sources: promptkit.ConfigurationSources{Underlays: []configkit.Underlay{{Inputs: inputs}}}, HTTPClient: &http.Client{Transport: transport}, - }, promptkit.WithSchemaFS(assets, "schemas")) + }, promptkit.WithBundledOpenRouter(false), promptkit.WithSchemaFS(assets, "schemas")) // Keep the example's configuration self-contained. if err != nil { return summary{}, err } diff --git a/examples/go-library/prepare/main.go b/examples/go-library/prepare/main.go index 8410be3..fe2b979 100644 --- a/examples/go-library/prepare/main.go +++ b/examples/go-library/prepare/main.go @@ -63,7 +63,7 @@ func run(ctx context.Context, exampleDir string, out io.Writer) error { {Inputs: []configkit.Input{support, review}}, {Inputs: []configkit.Input{override}}, }, - }}) + }}, promptkit.WithBundledOpenRouter(false)) // Keep this example's inventory caller-owned. if err != nil { return err } diff --git a/examples/go-library/run/main.go b/examples/go-library/run/main.go index 6595c0c..c8dfaf9 100644 --- a/examples/go-library/run/main.go +++ b/examples/go-library/run/main.go @@ -54,7 +54,7 @@ func run(ctx context.Context, exampleDir string, out io.Writer) error { {ID: "offline-example", Endpoint: &endpoint, Model: &model}, })}}}}, Main: &configkit.Input{Source: configkit.File(filepath.Join(exampleDir, "prompt.yaml"))}, - }}, promptkit.WithLLMClient(deterministicClient{})) + }}, promptkit.WithBundledOpenRouter(false), promptkit.WithLLMClient(deterministicClient{})) // Use only this example's offline configuration. if err != nil { return err }