Document keyed configuration and migrated consumer workflows
This commit is contained in:
12
README.md
12
README.md
@@ -8,7 +8,8 @@ gitea.maximumdirect.net/eric/promptkit
|
|||||||
```
|
```
|
||||||
|
|
||||||
The root `promptkit` package provides the supported public engine. Consumers
|
The root `promptkit` package provides the supported public engine. Consumers
|
||||||
can configure filesystem or in-memory prompt, profile, and schema sources,
|
can configure file, embedded, or programmatic backend, profile, and prompt
|
||||||
|
definitions alongside filesystem or in-memory schemas,
|
||||||
prepare requests without generation, run requests with the built-in
|
prepare requests without generation, run requests with the built-in
|
||||||
OpenAI-compatible client, or inject their own model client and artifact reader.
|
OpenAI-compatible client, or inject their own model client and artifact reader.
|
||||||
|
|
||||||
@@ -20,9 +21,12 @@ Run the maintained offline preparation example from the repository root:
|
|||||||
go run ./examples/go-library/prepare
|
go run ./examples/go-library/prepare
|
||||||
```
|
```
|
||||||
|
|
||||||
It loads a repository-local prompt, supplies an in-memory profile and inline
|
It loads a repository-local prompt, supplies a programmatic profile and inline
|
||||||
input, and prints deterministic preparation metadata without contacting a
|
input, inspects the captured configuration, and prints deterministic
|
||||||
provider or requiring credentials. Read the
|
preparation metadata without contacting a provider or requiring credentials.
|
||||||
|
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. Read the
|
||||||
[example source](examples/go-library/prepare/main.go), the
|
[example source](examples/go-library/prepare/main.go), the
|
||||||
[Go package consumer guide](docs/consumers/pkg-promptkit.md), and the
|
[Go package consumer guide](docs/consumers/pkg-promptkit.md), and the
|
||||||
[framework format reference](docs/formats.md) to build a consumer workflow.
|
[framework format reference](docs/formats.md) to build a consumer workflow.
|
||||||
|
|||||||
@@ -78,6 +78,32 @@ explicitly selected missing or unreadable root is an error. Each helper finds
|
|||||||
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
|
||||||
empty main source, not another directory lookup.
|
empty main source, not another directory lookup.
|
||||||
|
|
||||||
|
For a programmatic document with explicit null or a prompt definition, use a
|
||||||
|
labeled mapping as an input. A mapping owns a snapshot of supported values:
|
||||||
|
|
||||||
|
```go
|
||||||
|
document := configkit.Mapping("application configuration", map[string]any{
|
||||||
|
"profiles": map[string]any{
|
||||||
|
"local-summary": map[string]any{
|
||||||
|
"backend": "local", "model": "example-model",
|
||||||
|
"temperature": nil, // Suppress an inherited provider control.
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
input := configkit.Input{Source: document}
|
||||||
|
// Add input to a later underlay, or set Sources.Main = &input.
|
||||||
|
```
|
||||||
|
|
||||||
|
`ProfileSource` and `BackendSource` are smaller typed conveniences when null
|
||||||
|
is not needed. A caller underlay can overlay catalog backend fields just as it
|
||||||
|
can overlay profiles; there is no registration-only backend namespace.
|
||||||
|
|
||||||
|
When configuration or message files change, build and validate a new engine,
|
||||||
|
then switch the application to that engine for subsequent work. Existing
|
||||||
|
engines and prepared handles retain their captured definitions; schema and
|
||||||
|
request artifact resources still follow their runtime lifecycle. Inspection
|
||||||
|
does not watch or reload sources automatically.
|
||||||
|
|
||||||
## Inspect The Captured Configuration
|
## Inspect The Captured Configuration
|
||||||
|
|
||||||
Use [`Engine.InspectConfiguration`](../../configuration_inspection.go) for an
|
Use [`Engine.InspectConfiguration`](../../configuration_inspection.go) for an
|
||||||
@@ -323,6 +349,38 @@ For programmatic profiles, use [`ProfileSource`](../../profiles.go) with keyed
|
|||||||
`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.
|
||||||
|
|
||||||
|
### Migrate From The Previous Configuration API
|
||||||
|
|
||||||
|
Replace `Config.PromptDir` and `Config.ProfileDir` with selected ConfigKit
|
||||||
|
inputs in `Config.Sources`. The removed `WithPromptFS`, `WithPromptFile`,
|
||||||
|
`WithProfileFS`, `WithProfileFile`, `WithFallbackProfileFS`, `WithProfiles`,
|
||||||
|
and `WithBackend` options have no compatibility wrappers. Use
|
||||||
|
`DirectoryInputs` or `FilesystemInputs` for a strict-composition file group,
|
||||||
|
ConfigKit file inputs for individual files, and `ProfileSource`,
|
||||||
|
`BackendSource`, or `configkit.Mapping` for programmatic values. Backend IDs
|
||||||
|
are keys in configuration, not registrations. Choose caller underlays in
|
||||||
|
fallback-to-operator-to-programmatic order; use `Sources.Main` for one final
|
||||||
|
highest-priority input.
|
||||||
|
|
||||||
|
Move embedded `id` and `version` fields into keyed `profiles` and `prompts`
|
||||||
|
maps; convert `base_profile` to ConfigKit `extends`. IDs and references are
|
||||||
|
exact literal keys, without trimming. A supplied zero, false, or empty string
|
||||||
|
is now distinguishable from omission; null can clear or suppress an inherited
|
||||||
|
field according to the [field table](../formats.md#defaults-and-overrides).
|
||||||
|
Maps merge recursively across inheritance and layers. `{}` does not clear an
|
||||||
|
inherited map: use null to clear the whole map. At request time, a literal
|
||||||
|
`extra_params["extends"]` is ordinary provider data, not an inheritance
|
||||||
|
instruction; a nonempty request ExtraParams map replaces configured params.
|
||||||
|
Changing a model or backend does not clear unrelated explicit fields, though
|
||||||
|
backend-derived defaults are applied after inheritance to the final backend.
|
||||||
|
|
||||||
|
Invalid final definitions, including unused ones, now fail `NewEngine`; only
|
||||||
|
request-dependent failures remain at preparation or execution. Prompt text
|
||||||
|
and static templates are captured at construction, not automatically reloaded
|
||||||
|
between runs. Replace the engine to pick up changed definitions or message
|
||||||
|
files. The [format reference](../formats.md) owns exact field and presence
|
||||||
|
rules; the maintained examples show complete runnable workflows.
|
||||||
|
|
||||||
### Choose A Profile Ownership Model
|
### Choose A Profile Ownership Model
|
||||||
|
|
||||||
Choose the profile source that matches the application's continuity needs:
|
Choose the profile source that matches the application's continuity needs:
|
||||||
|
|||||||
559
docs/formats.md
559
docs/formats.md
@@ -2,394 +2,309 @@
|
|||||||
|
|
||||||
## Purpose
|
## Purpose
|
||||||
|
|
||||||
This document is the canonical contract for Promptkit prompt-definition,
|
This is the canonical reference for Promptkit's backend, profile, prompt, and
|
||||||
profile, and schema files. The [Go package consumer guide](consumers/pkg-promptkit.md)
|
schema definitions. The [Go consumer guide](consumers/pkg-promptkit.md) shows
|
||||||
explains how to select these sources and invoke the engine. The
|
how to select sources and use an engine; the
|
||||||
[OpenAI-compatible integration contract](integrations/openai-compatible-chat.md)
|
[OpenAI-compatible integration contract](integrations/openai-compatible-chat.md)
|
||||||
owns the resulting outbound wire behavior.
|
owns outbound wire behavior. [ConfigKit](https://gitea.maximumdirect.net/eric/ConfigKit)
|
||||||
|
owns the generic YAML grammar, imports, layering, inheritance, and diagnostics.
|
||||||
|
This reference describes what Promptkit does with the final effective values.
|
||||||
|
|
||||||
Prompt and profile sources recursively discover files ending in `.yaml` or
|
A configuration document has keyed top-level `backends`, `profiles`, and
|
||||||
`.yml`. Each prompt-definition and profile file contains exactly one YAML
|
`prompts` mappings. Their keys are literal IDs, not filename-derived identities.
|
||||||
document; comments and trailing whitespace are allowed. YAML decoding is
|
Prompt versions are a second keyed mapping. Keys and references must be
|
||||||
strict: unknown fields are errors for the selected definition. Definitions are
|
nonblank and remain exact: Promptkit does not trim or re-key them. Old embedded
|
||||||
selected by their YAML `id`, not their file name or directory.
|
`id`, `version`, and `base_profile` fields are invalid. Unknown fields are
|
||||||
|
errors.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
backends:
|
||||||
|
local:
|
||||||
|
endpoint: http://localhost:8000/v1
|
||||||
|
concurrency_limit: 2
|
||||||
|
profiles:
|
||||||
|
local-summary:
|
||||||
|
backend: local
|
||||||
|
model: example-model
|
||||||
|
prompts:
|
||||||
|
meeting.summary:
|
||||||
|
"1.0.0":
|
||||||
|
default_profile: local-summary
|
||||||
|
messages:
|
||||||
|
- role: user
|
||||||
|
content: Summarize this note.
|
||||||
|
output:
|
||||||
|
format: text
|
||||||
|
validation_mode: none
|
||||||
|
```
|
||||||
|
|
||||||
|
Every effective backend, profile, and prompt definition is validated when
|
||||||
|
`NewEngine` constructs the engine, even if it is never selected. A profile may
|
||||||
|
be partial: an endpoint and model need only be complete after request overrides
|
||||||
|
are applied. A prompt's default profile similarly need not be runnable without
|
||||||
|
an overriding request. Missing request data, artifacts, schemas, credentials,
|
||||||
|
and provider work remain runtime concerns.
|
||||||
|
|
||||||
|
The engine captures effective definitions, referenced message-file contents,
|
||||||
|
and static template syntax at construction. It does not reread configuration or
|
||||||
|
message files on ordinary runs; construct a new engine to observe edits.
|
||||||
|
Schema and request artifact reads still happen during preparation. Use
|
||||||
|
`InspectConfiguration` for an explicit effective-configuration or provenance
|
||||||
|
report, `InspectProfile` for backend-completed profile settings, and preparation
|
||||||
|
for request-specific rendered details.
|
||||||
|
|
||||||
## Prompt Definitions
|
## Prompt Definitions
|
||||||
|
|
||||||
A prompt definition describes inputs, Go-template messages, an optional
|
The `prompts` mapping selects a literal prompt ID, then a string version key:
|
||||||
default profile, and an output contract.
|
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
id: meeting.summary
|
prompts:
|
||||||
version: "1.0.0"
|
meeting.summary:
|
||||||
default_profile: local-summary
|
"1.0.0":
|
||||||
description: Summarize a synthetic meeting note.
|
default_profile: local-summary
|
||||||
session_id: '{{.session}}'
|
description: Summarize a synthetic meeting note.
|
||||||
inputs:
|
session_id: '{{.session}}'
|
||||||
- name: note
|
inputs:
|
||||||
required: true
|
- name: note
|
||||||
content_type: text/plain
|
required: true
|
||||||
description: Meeting note to summarize.
|
content_type: text/plain
|
||||||
messages:
|
description: Meeting note to summarize.
|
||||||
- role: system
|
messages:
|
||||||
content: Return a concise summary.
|
- role: system
|
||||||
cache_control:
|
content: Return a concise summary.
|
||||||
type: ephemeral
|
cache_control:
|
||||||
ttl: 1h
|
type: ephemeral
|
||||||
- role: user
|
ttl: 1h
|
||||||
content_file: ./summary.user.md
|
- role: user
|
||||||
output:
|
content_file: ./summary.user.md
|
||||||
format: markdown
|
output:
|
||||||
validation_mode: basic
|
format: markdown
|
||||||
repair_attempts: 0
|
validation_mode: basic
|
||||||
|
repair_attempts: 0
|
||||||
```
|
```
|
||||||
|
|
||||||
| Field | Required | Meaning |
|
`messages` must be nonempty and `output` must be a valid mapping. Optional
|
||||||
| --- | --- | --- |
|
`default_profile`, `description`, `session_id`, `inputs`, and cache-control
|
||||||
| `id` | yes | Non-empty prompt identifier used by `RunRequest.PromptID`. |
|
fields may be absent or cleared with null where appropriate. A null whole
|
||||||
| `version` | yes | Non-empty version selected by an optional `RunRequest.PromptVersion`. |
|
definition, required role, output format, or validation mode is invalid.
|
||||||
| `default_profile` | no | Non-empty profile ID used when the request omits `ProfileID`. |
|
`required` and `repair_attempts` default to false and zero, respectively, and
|
||||||
| `description` | no | Human-readable description. |
|
are not nullable. A request that omits a prompt version succeeds only if that
|
||||||
| `session_id` | no | Go template rendered from request variables and input helpers. |
|
prompt ID has exactly one effective version. `InspectPrompt` selects from the
|
||||||
| `inputs` | no | Declared input metadata. |
|
same captured definitions without rendering or resolving a profile.
|
||||||
| `messages` | yes | One or more chat-message templates. |
|
|
||||||
| `output` | yes | Output format and validation settings. |
|
|
||||||
|
|
||||||
When a request omits a version, the selected prompt ID must identify exactly
|
|
||||||
one definition. When it supplies a version, the ID and version pair must be
|
|
||||||
unique.
|
|
||||||
|
|
||||||
Exact prompt inspection uses this same configured source, strict decoding,
|
|
||||||
referenced content-file resolution, and ID/version selection. It reports the
|
|
||||||
selected definition's declared metadata without changing the prompt format or
|
|
||||||
executing the definition.
|
|
||||||
|
|
||||||
### Inputs
|
### Inputs
|
||||||
|
|
||||||
Each `inputs` item has these fields:
|
Each `inputs` item may contain `name`, `required`, `content_type`, and
|
||||||
|
`description`. `name` is required, nonblank, and unique within the prompt.
|
||||||
| Field | Required | Meaning |
|
Omitted `required` means false. Null `inputs` means no declarations. Requests
|
||||||
| --- | --- | --- |
|
supply inline or file-backed `ArtifactRef` values; declared required inputs
|
||||||
| `name` | yes | Non-empty name used by the request input map and `input` template helper. Names must be unique. |
|
must be present. A template reference also needs its named input, even when
|
||||||
| `required` | no | When true, preparation fails if the request omits the input. The default is false. |
|
undeclared. Extra request inputs are allowed.
|
||||||
| `content_type` | no | Expected media-type metadata. |
|
|
||||||
| `description` | no | Human-readable input description. |
|
|
||||||
|
|
||||||
Requests supply inputs as inline or file-backed `ArtifactRef` values. Declared
|
|
||||||
required inputs must be present. A template reference also requires the named
|
|
||||||
input to exist, whether or not it was declared. Extra request inputs are
|
|
||||||
allowed.
|
|
||||||
|
|
||||||
### Messages And Templates
|
### Messages And Templates
|
||||||
|
|
||||||
Each message has a `role` that Promptkit trims and lowercases. It must then be
|
Each message needs a role and exactly one nonnull `content` or `content_file`.
|
||||||
exactly one of `developer`, `system`, `user`, or `assistant`; blank, custom,
|
An explicitly empty inline `content` is valid. Null clears either content
|
||||||
`tool`, and `function` roles are invalid. This intentionally tightens the
|
selection. Roles are trimmed and lowercased, then must be `developer`,
|
||||||
previous nonblank-string rule. Consumers migrating to the next minor release
|
`system`, `user`, or `assistant`. Static template syntax is checked during
|
||||||
must update any nonstandard prompt-definition roles before upgrading.
|
construction; missing variables and named inputs fail when rendered.
|
||||||
|
Request variables are template data (`{{.audience}}`), and
|
||||||
|
`{{input "note"}}` renders an input body.
|
||||||
|
|
||||||
Each message also has exactly one of:
|
`content_file` uses the effective field's own source context, including when
|
||||||
|
inherited or imported. Its relative path is resolved against that source's
|
||||||
|
base directory within its rooted filesystem. Absolute paths and lexical
|
||||||
|
escapes from the selected root fail. Host-file sources also prevent symlink
|
||||||
|
escapes. Promptkit preserves the path text, including meaningful whitespace,
|
||||||
|
after checking that it is not blank. A source without a unique usable resource
|
||||||
|
context must supply one explicitly or override the field. Content is captured
|
||||||
|
at construction, not reopened for each request.
|
||||||
|
|
||||||
- `content`, containing an inline Go template; or
|
Optional `session_id` uses the same template variables and input helper. Its
|
||||||
- `content_file`, naming a file whose contents are the Go template.
|
rendered value is trimmed, omitted if empty, and limited to 256 Unicode code
|
||||||
|
points. A nonblank direct request session ID bypasses the template.
|
||||||
`content_file` must be a relative path. It resolves from the directory that
|
|
||||||
contains the prompt file and must remain within the configured prompt source
|
|
||||||
root; parent components are allowed only when the resolved target remains
|
|
||||||
inside that root. Absolute paths and paths that escape the root are rejected.
|
|
||||||
Operating-system directory and single-file sources also reject symlink targets
|
|
||||||
outside the root, while injected `fs.FS` sources apply containment in that
|
|
||||||
filesystem's relative path namespace. For `WithPromptFile`, the source root is
|
|
||||||
the directory containing the selected prompt file. Promptkit uses the parsed
|
|
||||||
path text exactly after checking separately that it is not blank, so leading
|
|
||||||
and trailing whitespace can name real filesystem entries.
|
|
||||||
|
|
||||||
Request variables are the template data, so a variable named `audience` is
|
|
||||||
referenced as `{{.audience}}`. The `{{input "note"}}` helper renders the body
|
|
||||||
of a named input. Missing variables and input references are errors.
|
|
||||||
|
|
||||||
The optional `session_id` uses the same template data and input helper. Its
|
|
||||||
rendered value is trimmed, omitted when empty, and limited to 256 Unicode code
|
|
||||||
points. A nonblank direct request session ID bypasses this template completely;
|
|
||||||
a blank direct value leaves the template behavior unchanged.
|
|
||||||
|
|
||||||
### Cache Control
|
### Cache Control
|
||||||
|
|
||||||
`cache_control` is optional and has these fields:
|
Optional `cache_control` has required `type: ephemeral` and optional `ttl`,
|
||||||
|
which may be empty or `1h`. Promptkit retains this metadata on rendered
|
||||||
| Field | Required | Values |
|
messages; the integration contract defines its wire representation.
|
||||||
| --- | --- | --- |
|
|
||||||
| `type` | yes | `ephemeral` |
|
|
||||||
| `ttl` | no | Empty or `1h` |
|
|
||||||
|
|
||||||
Promptkit preserves cache-control metadata on the rendered message. The
|
|
||||||
outbound integration determines its wire representation.
|
|
||||||
|
|
||||||
### Output Contract
|
### Output Contract
|
||||||
|
|
||||||
| Field | Required | Values or behavior |
|
| Field | Required | Values or behavior |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `format` | yes | `text`, `markdown`, or `json`. |
|
| `format` | yes | `text`, `markdown`, or `json` |
|
||||||
| `validation_mode` | yes | `none`, `basic`, `json`, or `json_schema`. |
|
| `validation_mode` | yes | `none`, `basic`, `json`, or `json_schema` |
|
||||||
| `schema_path` | for `json_schema` | Path to a schema in the configured schema source. |
|
| `schema_path` | for `json_schema` | Path in the selected schema source |
|
||||||
| `repair_attempts` | no | Integer from zero through three; omitted means zero. A positive value requires `basic`, `json`, or `json_schema` validation. |
|
| `repair_attempts` | no | Integer 0–3; default 0. Positive values need `basic`, `json`, or `json_schema` |
|
||||||
|
|
||||||
The validation modes behave as follows:
|
`none` skips content validation; `basic` requires nonempty content; `json`
|
||||||
|
accepts any valid JSON value; `json_schema` checks the selected schema.
|
||||||
- `none` skips content validation;
|
`format` determines output artifact metadata. JSON Schema mode also supplies
|
||||||
- `basic` requires non-empty generated content;
|
structured-output metadata to compatible clients. Plain `json` does not
|
||||||
- `json` requires valid JSON; and
|
request a provider-native JSON-object constraint. A positive repair budget
|
||||||
- `json_schema` requires valid JSON that satisfies the selected schema.
|
counts additional generations after failed validation; exhaustion returns the
|
||||||
|
last candidate and its failed validation result. Operational errors remain
|
||||||
`format` controls output artifact metadata. JSON Schema mode also supplies the
|
errors. A request-level `OutputContract` replaces the whole configured one,
|
||||||
schema to compatible model clients as structured-output metadata. Plain `json`
|
not individual fields; an empty request format defaults to `text`.
|
||||||
validation accepts every valid JSON value and does not request a provider-native
|
|
||||||
JSON-object constraint.
|
|
||||||
|
|
||||||
`repair_attempts` counts additional generation calls after a failed validation.
|
|
||||||
Zero is single-pass. With a positive eligible budget, Promptkit stops at the
|
|
||||||
first valid candidate. If the budget is exhausted, it returns the final
|
|
||||||
candidate and its complete failed validation result; generation and operational
|
|
||||||
validation failures remain errors. `none` never permits repair.
|
|
||||||
|
|
||||||
A request-level `OutputContract` replaces the complete prompt output contract.
|
|
||||||
It does not merge individual fields. If its format is empty, Promptkit uses
|
|
||||||
`text`.
|
|
||||||
|
|
||||||
## Built-In Backends
|
## Built-In Backends
|
||||||
|
|
||||||
Every engine provides these reserved OpenAI-compatible backend IDs. Consumers
|
The selected catalog modules contribute these backend definitions as the
|
||||||
must not register either ID with `WithBackend`; exact registration and
|
earliest underlay. Their settings can be overlaid by caller sources; these IDs
|
||||||
reservation behavior belongs to the [`Backend` GoDoc](../backends.go).
|
are not reserved against configuration changes.
|
||||||
|
|
||||||
| ID | Base endpoint | API-key environment variable | Active generation limit | Default queue capacity |
|
| ID | Catalog endpoint | API-key environment name | Active generation limit |
|
||||||
| --- | --- | --- | ---: | ---: |
|
| --- | --- | --- | ---: |
|
||||||
| `openrouter` | `https://openrouter.ai/api/v1` | `OPENROUTER_API_KEY` | 16 | 1024 |
|
| `openrouter` | `https://openrouter.ai/api/v1` | `OPENROUTER_API_KEY` | 16 |
|
||||||
| `rakestrawhome` | `https://inference.ai.rakestrawhome.com/v1` | `RAKESTRAWHOME_INFERENCE_API_KEY` | 4 | 1024 |
|
| `rakestrawhome` | `https://inference.ai.rakestrawhome.com/v1` | `RAKESTRAWHOME_INFERENCE_API_KEY` | 4 |
|
||||||
|
|
||||||
|
A backend definition may have `endpoint`, `api_key_env`,
|
||||||
|
`concurrency_limit`, `queue_capacity`, and `extra_params`. The final endpoint
|
||||||
|
is required and must be an absolute HTTP(S) URL with a host, no user
|
||||||
|
information, query, or fragment. An omitted or null API-key environment name
|
||||||
|
means no lookup. Omitted/null concurrency is zero (unlimited); a supplied
|
||||||
|
negative value is invalid. For positive concurrency, omitted/null queue
|
||||||
|
capacity defaults to 1024. An explicit queue capacity, including zero,
|
||||||
|
requires positive concurrency and must be nonnegative. Unlimited concurrency
|
||||||
|
has no queue. Provider maps contain JSON-compatible values; null entries are
|
||||||
|
ordinary JSON null. Unknown fields, including a raw `api_key`, fail.
|
||||||
|
|
||||||
## Profile Definitions
|
## Profile Definitions
|
||||||
|
|
||||||
A profile supplies model execution settings:
|
Profiles are keyed by literal ID and may inherit a named parent with
|
||||||
|
`extends`:
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
id: local-summary
|
profiles:
|
||||||
backend: openrouter
|
local-summary:
|
||||||
model: example-model
|
backend: local
|
||||||
temperature: 0.2
|
model: example-model
|
||||||
max_tokens: 500
|
temperature: 0.2
|
||||||
top_p: 0.95
|
max_tokens: 500
|
||||||
timeout_seconds: 90
|
timeout_seconds: 90
|
||||||
service_tier: flex
|
extra_params:
|
||||||
reasoning_effort: medium
|
provider_option: enabled
|
||||||
extra_params:
|
local-summary-fast:
|
||||||
provider_option: enabled
|
extends: local-summary
|
||||||
|
timeout_seconds: 30
|
||||||
|
reasoning_effort: low
|
||||||
```
|
```
|
||||||
|
|
||||||
A derived profile can use a named base and override only the settings it owns:
|
Profiles may also supply `endpoint`, `top_p`, `service_tier`, `api_key_env`,
|
||||||
|
and `api_key_required`. Promptkit does not infer a backend from an endpoint or
|
||||||
```yaml
|
model. A profile with only an endpoint has no backend capacity identity.
|
||||||
id: local-summary-fast
|
Nonblank endpoints follow the backend URL rules; temperature is 0–2, top_p
|
||||||
base_profile: local-summary
|
is 0–1, max_tokens and timeout_seconds are nonnegative. Provider maps accept
|
||||||
timeout_seconds: 30
|
JSON-compatible values with nonempty keys and cannot collide with the built-in
|
||||||
reasoning_effort: low
|
client's [standard request fields](integrations/openai-compatible-chat.md#request-body).
|
||||||
```
|
Credential values do not belong in profiles: raw `api_key` is invalid.
|
||||||
|
|
||||||
| Field | Required | Meaning |
|
|
||||||
| --- | --- | --- |
|
|
||||||
| `id` | yes | Profile identifier, trimmed before selection and publication. It must be non-empty after trimming and unique within one source after normalization. |
|
|
||||||
| `base_profile` | no | One optional parent profile ID. A derived profile may inherit target fields from it. |
|
|
||||||
| `backend` | unless `endpoint` is present | Backend registry ID. It is trimmed and registry membership is checked when the profile is prepared or inspected. |
|
|
||||||
| `endpoint` | unless `backend` is present | OpenAI-compatible base URL, including an API version path when required. A nonempty value is trimmed and must be absolute HTTP or HTTPS with a host and without user information, a query, or a fragment. When both connection fields are present, this overrides the backend endpoint without changing backend identity. |
|
|
||||||
| `model` | yes | Non-empty provider model name. |
|
|
||||||
| `temperature` | no | Number from 0 through 2. |
|
|
||||||
| `max_tokens` | no | Integer zero or greater. |
|
|
||||||
| `top_p` | no | Number from 0 through 1. |
|
|
||||||
| `timeout_seconds` | no | Per-generation deadline in whole seconds; integer zero or greater. |
|
|
||||||
| `service_tier` | no | Provider-specific request tier. |
|
|
||||||
| `reasoning_effort` | no | Provider-specific reasoning setting. |
|
|
||||||
| `api_key_env` | no | Optional environment-variable lookup source for an API key. |
|
|
||||||
| `extra_params` | no | JSON-compatible provider-specific outbound fields. |
|
|
||||||
|
|
||||||
Raw `api_key` is prohibited in profile YAML. Store only an environment
|
|
||||||
variable name in `api_key_env`.
|
|
||||||
|
|
||||||
A standalone profile must provide a model and at least one of `backend` or
|
|
||||||
`endpoint`. A derived profile may omit those target fields because its selected
|
|
||||||
base chain can provide them. Local parsing still validates a derived profile's
|
|
||||||
own ID, supplied endpoint, execution-setting bounds, and `extra_params`.
|
|
||||||
|
|
||||||
Promptkit does not infer a backend from a model or endpoint. Endpoint-only
|
|
||||||
profiles remain supported and have no effective backend ID.
|
|
||||||
The engine always provides the built-in `openrouter` and `rakestrawhome` IDs.
|
|
||||||
Consumers can add engine-scoped IDs with
|
|
||||||
[`WithBackend`](../backends.go); exact registration validation belongs to its
|
|
||||||
GoDoc.
|
|
||||||
|
|
||||||
`extra_params` accepts null, booleans, finite numbers, strings, arrays, and
|
|
||||||
objects with string keys. Keys must be non-empty. With the built-in client,
|
|
||||||
they also cannot collide with the standard fields listed in the
|
|
||||||
[outbound request contract](integrations/openai-compatible-chat.md#request-body).
|
|
||||||
Excessively deep or large JSON-shaped values are rejected for safety.
|
|
||||||
|
|
||||||
### Defaults And Overrides
|
### Defaults And Overrides
|
||||||
|
|
||||||
Execution settings resolve in this order:
|
After effective profile inheritance, Promptkit applies the selected backend's
|
||||||
|
defaults once, then request `ExecutionTargetOverride` values. Backend-derived
|
||||||
|
settings are not inheritance input: changing a child profile's backend does
|
||||||
|
not carry the parent's derived endpoint or credential source into it. Changing
|
||||||
|
only a model or backend does not clear unrelated explicitly inherited fields.
|
||||||
|
|
||||||
1. the framework timeout baseline;
|
| Profile field | Absent | Explicit value | Explicit null |
|
||||||
2. the selected backend, when the profile names one;
|
| --- | --- | --- | --- |
|
||||||
3. the selected profile; and
|
| `backend` | No backend | Exact backend ID; blank means none | No backend |
|
||||||
4. request `ExecutionTargetOverride` values.
|
| `endpoint` | Selected backend endpoint | Valid nonblank URL; empty clears | Clear, without backend fallback |
|
||||||
|
| `model` | Unspecified | Nonblank model; empty clears | Unspecified |
|
||||||
|
| `temperature`, `top_p`, `max_tokens` | Unspecified | Valid value, including outbound zero | Suppress outbound control |
|
||||||
|
| `service_tier`, `reasoning_effort` | Unspecified | Normalized value; blank suppresses | Suppress outbound control |
|
||||||
|
| `timeout_seconds` | 600 seconds | Nonnegative; zero disables generation deadline | Reset to 600 seconds |
|
||||||
|
| `api_key_env` | Backend lookup name, if any | Trimmed name; blank disables | Disable backend lookup |
|
||||||
|
| `api_key_required` | False | Boolean, including false | False |
|
||||||
|
| `extra_params` | Backend defaults | Recursively overlay profile map on backend map | Suppress configured provider map |
|
||||||
|
|
||||||
The framework baseline is:
|
An empty mapping does not clear inherited map entries; null clears the whole
|
||||||
|
map. Nested maps merge recursively, while scalar and array values replace.
|
||||||
| Setting | Default |
|
Runtime nonempty `ExtraParams` overrides replace the entire configured map.
|
||||||
| --- | --- |
|
Request overrides otherwise follow the [public value GoDoc](../types.go).
|
||||||
| `temperature` | Unspecified and omitted from compatible provider requests unless a profile or runtime override selects it. |
|
For example, a runtime `extra_params["extends"]` key is ordinary provider
|
||||||
| `max_tokens` | Unspecified and omitted from compatible provider requests unless a profile or runtime override selects it. |
|
data, not a configuration inheritance instruction. An explicit zero timeout
|
||||||
| `top_p` | Unspecified and omitted from compatible provider requests unless a profile or runtime override selects it. |
|
does not disable the caller context or HTTP transport timeout.
|
||||||
| `timeout_seconds` | `600` |
|
|
||||||
|
|
||||||
Numeric zero in a file or in-memory profile does not select a numeric value.
|
|
||||||
For `temperature`, `max_tokens`, and `top_p`, it leaves the provider control
|
|
||||||
unspecified. For `timeout_seconds`, it retains the framework deadline. Numeric
|
|
||||||
request overrides use pointers, so an explicit zero is retained and sent to
|
|
||||||
compatible providers. In particular, an explicit request `timeout_seconds` of
|
|
||||||
zero disables the per-generation deadline while leaving the caller context and
|
|
||||||
transport timeout intact.
|
|
||||||
|
|
||||||
Non-empty profile strings replace backend defaults, and non-empty request
|
|
||||||
strings replace both. Request reasoning is the exception: a nil
|
|
||||||
`ReasoningEffort` pointer inherits the profile, a pointer to a nonblank string
|
|
||||||
trims and replaces it, and a pointer to a blank string clears it. Backend
|
|
||||||
identity is retained when either layer overrides the endpoint, so the override
|
|
||||||
also retains any engine-local capacity policy configured for that backend.
|
|
||||||
Capacity configuration belongs to the Go
|
|
||||||
[`Backend` API](../backends.go), not prompt or profile YAML. A non-empty
|
|
||||||
`extra_params` map at each layer replaces the entire lower-precedence map
|
|
||||||
rather than merging keys.
|
|
||||||
The [outbound integration contract](integrations/openai-compatible-chat.md)
|
|
||||||
defines how the effective settings are serialized.
|
|
||||||
|
|
||||||
### Source And Profile Precedence
|
### Source And Profile Precedence
|
||||||
|
|
||||||
An explicit request profile ID takes precedence over the prompt's
|
`NewEngine` composes catalog definitions first, Promptkit-owned definitions
|
||||||
`default_profile`. If neither is present, preparation fails. Exact profile
|
next, then caller underlays in their given order, with an optional main input
|
||||||
inspection instead takes one explicit profile ID and does not use a prompt
|
last. Later tiers overlay earlier ones. Inputs within one underlay group are
|
||||||
default.
|
strictly composed: conflicting contributions are errors, not priority
|
||||||
|
signals. The directory helpers discover `.yaml` and `.yml` files recursively
|
||||||
|
in sorted order, but that order does not give one file higher precedence.
|
||||||
|
An explicitly selected missing/unreadable root fails; an empty root contributes
|
||||||
|
nothing. Imports are disabled by these helpers unless the caller enables them
|
||||||
|
on an input. Single files can use ConfigKit inputs directly.
|
||||||
|
|
||||||
Profile sources resolve matching IDs in this order:
|
Backends, profiles, and prompts all follow these same source rules. A later
|
||||||
|
profile or backend can change individual fields of a lower definition. A
|
||||||
1. in-memory profiles supplied with `WithProfiles`;
|
request `ProfileID` takes precedence over a prompt `default_profile`; if
|
||||||
2. the ordinary configured source selected by a profile file, `fs.FS`, or
|
neither is selected, preparation fails. Exact profile inspection selects one
|
||||||
configured profile directory;
|
explicit ID and does not consult a prompt default.
|
||||||
3. application fallback profiles supplied with `WithFallbackProfileFS`; and
|
|
||||||
4. Promptkit-owned profiles; and
|
|
||||||
5. maintained external catalog profiles.
|
|
||||||
|
|
||||||
A profile source supplies a complete definition; definitions and their fields
|
|
||||||
are not merged across sources. A higher-precedence source falls back only when
|
|
||||||
the requested profile ID is absent. An invalid matching profile is an error and
|
|
||||||
does not fall back. In-memory `Profile` values follow the same ranges as YAML
|
|
||||||
profiles. They use `APIKeyRequired` for request-scoped credentials instead of
|
|
||||||
`api_key_env`. Preparation and exact profile inspection use this same source
|
|
||||||
precedence.
|
|
||||||
|
|
||||||
When a selected definition names `base_profile`, every profile ID in that
|
|
||||||
chain is looked up through this same precedence order. A higher-precedence
|
|
||||||
definition therefore shadows a lower-precedence definition of the same base
|
|
||||||
ID, including a built-in. References are not source-qualified.
|
|
||||||
|
|
||||||
### Profile Inheritance
|
### Profile Inheritance
|
||||||
|
|
||||||
Promptkit resolves one linear base chain of at most 32 profiles, including the
|
ConfigKit resolves `extends` on effective profile definitions. One profile
|
||||||
selected profile. It merges settings from the root base to the selected leaf.
|
may inherit another keyed profile; presence, explicit null, and recursively
|
||||||
The leaf's `id` remains the selected profile identity. Nonblank string fields
|
merged maps determine the final fields. References are literal IDs, including
|
||||||
(`backend`, `endpoint`, `model`, `service_tier`, `reasoning_effort`, and
|
IDs containing punctuation. There is no Promptkit-specific depth limit or
|
||||||
`api_key_env`) and nonzero numeric fields replace inherited values. A nonempty
|
second base-chain resolver. Missing references and cycles fail at construction.
|
||||||
`extra_params` map replaces the complete inherited map rather than merging
|
For generic inheritance and layer mechanics, consult
|
||||||
keys, and `APIKeyRequired: true` remains true through the chain. Backend and
|
[ConfigKit](https://gitea.maximumdirect.net/eric/ConfigKit).
|
||||||
endpoint are independent: replacing one does not clear the other.
|
|
||||||
|
|
||||||
There is no profile-level clearing syntax. Blank strings, zero numbers, false,
|
|
||||||
and empty maps remain unspecified and inherit from a base. Use existing
|
|
||||||
presence-aware request overrides where an execution needs an explicit zero or
|
|
||||||
empty reasoning setting.
|
|
||||||
|
|
||||||
An absent directly selected profile reports the ordinary not-found error. Once
|
|
||||||
the selected profile exists, a missing base, cycle, overlong chain, or
|
|
||||||
incomplete resolved target is a profile-load failure. Ordinary operations
|
|
||||||
resolve chains afresh; prepared execution retains the fully resolved target.
|
|
||||||
|
|
||||||
## Built-In Profile Catalog
|
## Built-In Profile Catalog
|
||||||
|
|
||||||
Every built-in profile selects one maintained built-in backend and inherits
|
Promptkit contributes two opt-in definitions; neither is selected by default:
|
||||||
that backend's connection and credential metadata. Profile files do not repeat
|
|
||||||
those values. A configured, application fallback, or in-memory profile with
|
|
||||||
the same profile ID takes precedence.
|
|
||||||
|
|
||||||
Promptkit owns two opt-in profiles. The following definitions are current
|
|
||||||
selections, not automatic defaults:
|
|
||||||
|
|
||||||
| ID | Current definition |
|
| ID | Current definition |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `promptkit-openrouter-standard` | Inherits `gemini-flash-latest`. |
|
| `promptkit-openrouter-standard` | Extends the selected OpenRouter catalog's `gemini-flash-latest` profile. |
|
||||||
| `promptkit-openrouter-auto` | Selects backend `openrouter` and model `openrouter/auto`. |
|
| `promptkit-openrouter-auto` | Selects backend `openrouter` and model `openrouter/auto`. |
|
||||||
|
|
||||||
Select either name through an existing request `profile_id` or prompt
|
Select one through request `ProfileID` or prompt `default_profile`.
|
||||||
`default_profile`. Consumers can replace either definition or its inherited
|
Caller layers may overlay these definitions or their catalog bases. The
|
||||||
base through the ordinary profile-source precedence above. The
|
[release policy](policy/release.md#catalog-profile-compatibility) owns their
|
||||||
[release policy](policy/release.md#catalog-profile-compatibility) defines the
|
cross-version compatibility boundary.
|
||||||
cross-version guarantee for these names.
|
|
||||||
|
|
||||||
## External Profile Inventories
|
## External Profile Inventories
|
||||||
|
|
||||||
The external profile inventory is defined by the selected catalog modules, not
|
The selected catalog modules, not this document, own their profile inventories:
|
||||||
duplicated here. Browse the exact data selected by this Promptkit version:
|
|
||||||
|
|
||||||
- [OpenRouter catalog v2.20260926.0 profiles](https://gitea.maximumdirect.net/eric/promptkit-backend-openrouter/src/tag/v2.20260926.0/catalog/profiles)
|
- [OpenRouter catalog v3.20260930.0 profiles](https://gitea.maximumdirect.net/eric/promptkit-backend-openrouter/src/tag/v3.20260930.0/catalog/profiles)
|
||||||
- [Rakestrawhome catalog v2.20260926.0 profiles](https://gitea.maximumdirect.net/eric/promptkit-backend-rakestrawhome/src/tag/v2.20260926.0/catalog/profiles)
|
- [Rakestrawhome catalog v3.20260930.0 profiles](https://gitea.maximumdirect.net/eric/promptkit-backend-rakestrawhome/src/tag/v3.20260930.0/catalog/profiles)
|
||||||
|
|
||||||
External profile entries are volatile across catalog releases. The
|
These are tested local data, not a promise of live provider availability.
|
||||||
[release policy](policy/release.md#catalog-profile-compatibility) owns the precise
|
The [release policy](policy/release.md#catalog-profile-compatibility) owns
|
||||||
compatibility boundary; a selected module version identifies tested local data,
|
the compatibility boundary.
|
||||||
not live provider availability.
|
|
||||||
|
|
||||||
## Schemas
|
## Schemas
|
||||||
|
|
||||||
Schemas are JSON documents selected by a prompt or request
|
Schemas are JSON documents selected by a prompt or request `schema_path`.
|
||||||
`schema_path`. For a directory or `fs.FS` source, paths resolve within the
|
Directory and `fs.FS` schema paths resolve within the configured root;
|
||||||
configured source root. Referenced nested schemas resolve relative to the
|
referenced nested schemas resolve relative to the owning schema document.
|
||||||
owning schema document. `WithSchemaFile` exposes one schema, addressed by its
|
`WithSchemaFile` exposes one schema under its base name. An unreadable,
|
||||||
base name.
|
invalid, or unresolvable schema causes an operational validation error.
|
||||||
|
Valid JSON that fails the schema instead yields a failed validation result.
|
||||||
An unreadable, invalid, or unresolvable schema produces an operational
|
|
||||||
validation error. Generated content that is valid JSON but does not satisfy the
|
|
||||||
schema produces a failed validation result.
|
|
||||||
|
|
||||||
## Credentials
|
## Credentials
|
||||||
|
|
||||||
Credential values belong at the request or environment boundary, never in
|
Only environment-variable names belong in backend/profile definitions, never
|
||||||
prompt, profile, schema, or example files:
|
credential values. A request may supply a direct `APIKey` or an `APIKeyEnv`
|
||||||
|
override. A direct key takes precedence, followed by a request environment
|
||||||
|
source, an explicit profile source, and an inherited backend source. A true
|
||||||
|
profile `api_key_required` suppresses the backend-derived environment source,
|
||||||
|
but an explicit profile or request environment source remains usable. False
|
||||||
|
restores ordinary optional-credential behavior. Missing or blank optional
|
||||||
|
environment values leave the built-in client's Authorization header absent;
|
||||||
|
required availability is checked at preparation and again during prepared
|
||||||
|
execution. Injected clients own their credential-resolution behavior.
|
||||||
|
|
||||||
- a backend or file profile can name an optional environment lookup source
|
Credential values are excluded from JSON results and redacted by public
|
||||||
with `APIKeyEnv` or `api_key_env`;
|
string formatters. ConfigKit inspection redacts credential-shaped dynamic
|
||||||
- an in-memory profile may set `APIKeyRequired` as an explicit local
|
provider keys, but does not make arbitrary prompt/provider content safe to
|
||||||
requirement;
|
disclose. Applications own report disclosure and secret handling.
|
||||||
- a request can provide a direct `APIKey` or override the optional `APIKeyEnv`
|
|
||||||
source; and
|
|
||||||
- a direct request key takes precedence over environment lookup.
|
|
||||||
|
|
||||||
After a direct request key, the credential-source precedence is request
|
|
||||||
`APIKeyEnv`, profile `api_key_env`, then the backend default. An in-memory
|
|
||||||
profile with `APIKeyRequired` clears an inherited backend environment name and
|
|
||||||
requires a direct key unless the request explicitly supplies `APIKeyEnv`.
|
|
||||||
Named environment sources are optional: when the selected source is absent,
|
|
||||||
empty, or whitespace-only, the built-in client omits the `Authorization`
|
|
||||||
header and handles the provider response normally. `APIKeyRequired` is the
|
|
||||||
only explicit local availability requirement. Promptkit validates required
|
|
||||||
credential availability during preparation and rechecks it when a prepared
|
|
||||||
execution runs. Injected clients receive resolved source metadata but define
|
|
||||||
their own credential-resolution behavior.
|
|
||||||
Direct keys are excluded from JSON results and redacted by public string
|
|
||||||
formatters. Environment-variable names may appear in prepared metadata, but
|
|
||||||
their values do not.
|
|
||||||
|
|||||||
@@ -543,6 +543,8 @@ The runner has no reference to the inspector or ConfigKit metadata types.
|
|||||||
|
|
||||||
## Stage 10 — Migrate Examples And Canonical Format Guidance
|
## Stage 10 — Migrate Examples And Canonical Format Guidance
|
||||||
|
|
||||||
|
**Completed:** 2026-09-30.
|
||||||
|
|
||||||
Scope: maintained examples and user-facing documentation.
|
Scope: maintained examples and user-facing documentation.
|
||||||
|
|
||||||
1. Complete the preparation, execution, and observation example migration begun
|
1. Complete the preparation, execution, and observation example migration begun
|
||||||
|
|||||||
@@ -29,6 +29,13 @@ func main() {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
exit(err)
|
exit(err)
|
||||||
}
|
}
|
||||||
|
view, err := engine.InspectConfiguration()
|
||||||
|
if err != nil {
|
||||||
|
exit(err)
|
||||||
|
}
|
||||||
|
if _, found := view.Explain(configkit.Keys("profiles", "offline-example", "model")); !found {
|
||||||
|
exit(fmt.Errorf("configured profile model was not found"))
|
||||||
|
}
|
||||||
|
|
||||||
prepared, err := engine.Prepare(context.Background(), promptkit.RunRequest{
|
prepared, err := engine.Prepare(context.Background(), promptkit.RunRequest{
|
||||||
PromptID: "example.prepare",
|
PromptID: "example.prepare",
|
||||||
|
|||||||
Reference in New Issue
Block a user