Files
promptkit/docs/roadmap/bundled-openrouter.md

247 lines
12 KiB
Markdown

# 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.