Document profile inheritance behavior
This commit is contained in:
@@ -189,6 +189,26 @@ For programmatic profiles,
|
|||||||
[`OpenAICompatibleProfile`](../../profiles.go) converts ordinary
|
[`OpenAICompatibleProfile`](../../profiles.go) converts ordinary
|
||||||
OpenAI-compatible settings into a value accepted by `WithProfiles`.
|
OpenAI-compatible settings into a value accepted by `WithProfiles`.
|
||||||
|
|
||||||
|
### Alias A Built-In Profile
|
||||||
|
|
||||||
|
Give an application-owned profile ID a built-in base when prompts should select
|
||||||
|
the application ID while inheriting the built-in target. The child can override
|
||||||
|
only the setting it owns:
|
||||||
|
|
||||||
|
```go
|
||||||
|
promptkit.WithProfiles(promptkit.Profile{
|
||||||
|
ID: "weather-light",
|
||||||
|
BaseProfileID: "deepseek-4-flash",
|
||||||
|
ReasoningEffort: "high",
|
||||||
|
})
|
||||||
|
```
|
||||||
|
|
||||||
|
Select `weather-light` in a prompt or `RunRequest.ProfileID`; it remains the
|
||||||
|
reported selected profile. See the [profile inheritance format
|
||||||
|
reference](../formats.md#profile-inheritance) and the
|
||||||
|
[`Profile` GoDoc](../../types.go) for exact lookup, merging, and validation
|
||||||
|
behavior.
|
||||||
|
|
||||||
### Use The Rakestrawhome Built-In Profile
|
### Use The Rakestrawhome Built-In Profile
|
||||||
|
|
||||||
Set `RAKESTRAWHOME_INFERENCE_API_KEY` in the application environment, then
|
Set `RAKESTRAWHOME_INFERENCE_API_KEY` in the application environment, then
|
||||||
|
|||||||
@@ -173,9 +173,19 @@ extra_params:
|
|||||||
provider_option: enabled
|
provider_option: enabled
|
||||||
```
|
```
|
||||||
|
|
||||||
|
A derived profile can use a named base and override only the settings it owns:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
id: local-summary-fast
|
||||||
|
base_profile: local-summary
|
||||||
|
timeout_seconds: 30
|
||||||
|
reasoning_effort: low
|
||||||
|
```
|
||||||
|
|
||||||
| Field | Required | Meaning |
|
| 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. |
|
| `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. |
|
| `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. |
|
| `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. |
|
| `model` | yes | Non-empty provider model name. |
|
||||||
@@ -191,6 +201,11 @@ extra_params:
|
|||||||
Raw `api_key` is prohibited in profile YAML. Store only an environment
|
Raw `api_key` is prohibited in profile YAML. Store only an environment
|
||||||
variable name in `api_key_env`.
|
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
|
Promptkit does not infer a backend from a model or endpoint. Endpoint-only
|
||||||
profiles remain supported and have no effective backend ID.
|
profiles remain supported and have no effective backend ID.
|
||||||
The engine always provides the built-in `openrouter` and `rakestrawhome` IDs.
|
The engine always provides the built-in `openrouter` and `rakestrawhome` IDs.
|
||||||
@@ -266,6 +281,32 @@ profiles. They use `APIKeyRequired` for request-scoped credentials instead of
|
|||||||
`api_key_env`. Preparation and exact profile inspection use this same source
|
`api_key_env`. Preparation and exact profile inspection use this same source
|
||||||
precedence.
|
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
|
||||||
|
|
||||||
|
Promptkit resolves one linear base chain of at most 32 profiles, including the
|
||||||
|
selected profile. It merges settings from the root base to the selected leaf.
|
||||||
|
The leaf's `id` remains the selected profile identity. Nonblank string fields
|
||||||
|
(`backend`, `endpoint`, `model`, `service_tier`, `reasoning_effort`, and
|
||||||
|
`api_key_env`) and nonzero numeric fields replace inherited values. A nonempty
|
||||||
|
`extra_params` map replaces the complete inherited map rather than merging
|
||||||
|
keys, and `APIKeyRequired: true` remains true through the chain. Backend and
|
||||||
|
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
|
Every built-in profile selects one maintained built-in backend and inherits
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ contributor workflow and validation.
|
|||||||
| `internal/filecatalog` | Provides deterministic YAML discovery and path helpers for operating-system filesystems and `fs.FS` sources. | [File catalog](../../internal/filecatalog/catalog.go) |
|
| `internal/filecatalog` | Provides deterministic YAML discovery and path helpers for operating-system filesystems and `fs.FS` sources. | [File catalog](../../internal/filecatalog/catalog.go) |
|
||||||
| `internal/jsonvalue` | Validates and deeply copies bounded JSON-compatible extra-parameter and prepared-schema trees while preserving supported concrete value types and rejecting cycles or excessive depth and work. | [JSON values](../../internal/jsonvalue/jsonvalue.go) |
|
| `internal/jsonvalue` | Validates and deeply copies bounded JSON-compatible extra-parameter and prepared-schema trees while preserving supported concrete value types and rejecting cycles or excessive depth and work. | [JSON values](../../internal/jsonvalue/jsonvalue.go) |
|
||||||
| `internal/promptdef` | Loads strictly decoded, validated prompt definitions from filesystem and `fs.FS` sources, including version selection and contained file-backed message content. | [Framework formats](../formats.md), [prompt-definition repository](../../internal/promptdef/filesystem_repository.go) |
|
| `internal/promptdef` | Loads strictly decoded, validated prompt definitions from filesystem and `fs.FS` sources, including version selection and contained file-backed message content. | [Framework formats](../formats.md), [prompt-definition repository](../../internal/promptdef/filesystem_repository.go) |
|
||||||
| `internal/profile` | Loads strictly decoded, validated execution profiles, including backend selection, from filesystem and `fs.FS` sources and composes repositories with error-preserving fallback. | [Framework formats](../formats.md), [profile repositories](../../internal/profile/filesystem_repository.go) |
|
| `internal/profile` | Loads strictly decoded, locally validated execution profiles from filesystem and `fs.FS` sources, overlays raw sources with error-preserving fallback, and resolves inherited profiles. | [Framework formats](../formats.md), [profile repositories](../../internal/profile/filesystem_repository.go), [internal sources](sources.md#profiles-and-built-ins) |
|
||||||
| `internal/profile/builtin` | Embeds the built-in profile catalog, whose entries select maintained built-in backends. | [Built-in catalog](../formats.md#built-in-profile-catalog), [repository](../../internal/profile/builtin/repository.go) |
|
| `internal/profile/builtin` | Embeds the built-in profile catalog, whose entries select maintained built-in backends. | [Built-in catalog](../formats.md#built-in-profile-catalog), [repository](../../internal/profile/builtin/repository.go) |
|
||||||
| `internal/prompt` | Renders prompt messages from Go templates with artifact, variable, session, and cache-control data. | [Go-template renderer](../../internal/prompt/go_renderer.go) |
|
| `internal/prompt` | Renders prompt messages from Go templates with artifact, variable, session, and cache-control data. | [Go-template renderer](../../internal/prompt/go_renderer.go) |
|
||||||
| `internal/artifact` | Resolves ordinary inline and unrestricted caller-selected file references into copied artifacts with metadata and hashes. | [Internal sources and validation](sources.md) |
|
| `internal/artifact` | Resolves ordinary inline and unrestricted caller-selected file references into copied artifacts with metadata and hashes. | [Internal sources and validation](sources.md) |
|
||||||
|
|||||||
@@ -39,17 +39,17 @@ duplicate detection, and source containment:
|
|||||||
|
|
||||||
## Profiles And Built-Ins
|
## Profiles And Built-Ins
|
||||||
|
|
||||||
`internal/profile` loads and validates execution profiles from an
|
`internal/profile` loads, locally validates, overlays, and resolves execution
|
||||||
operating-system filesystem or an `fs.FS`. A file contains exactly one YAML
|
profiles from an operating-system filesystem or an `fs.FS`. A file contains
|
||||||
document and its trimmed YAML `id` is its only selection identity; filenames do
|
exactly one YAML document and its trimmed YAML `id` is its only selection
|
||||||
not confer authority. Each point lookup reads discovered files once for their
|
identity; filenames do not confer authority. Each point lookup reads discovered
|
||||||
metadata and reuses the selected file's bytes for strict decoding; unrelated
|
files once for their metadata and reuses the selected file's bytes for strict
|
||||||
profiles are not fully decoded. Strict selected decoding recognizes the
|
decoding; unrelated profiles are not fully decoded. Strict selected decoding
|
||||||
optional `backend` field, trims its value, and requires a model plus at least
|
recognizes `base_profile` and the optional `backend` field, trims their values,
|
||||||
one non-blank backend or endpoint. File-backed `extra_params` values are
|
and permits inherited target fields only when a base is named. File-backed
|
||||||
validated and defensively copied through the shared bounded JSON-value owner
|
`extra_params` values are validated and defensively copied through the shared
|
||||||
before a profile is published. OpenAI-compatible reserved-field policy remains
|
bounded JSON-value owner before a profile is published. OpenAI-compatible
|
||||||
with the model-client and backend-registry owners.
|
reserved-field policy remains with the model-client and backend-registry owners.
|
||||||
|
|
||||||
The overlay repository consults the next repository only when the
|
The overlay repository consults the next repository only when the
|
||||||
higher-precedence repository reports that a profile is absent. A reliably
|
higher-precedence repository reports that a profile is absent. A reliably
|
||||||
@@ -59,14 +59,25 @@ backend registry membership because the available registry belongs to the
|
|||||||
assembled engine; the runner checks membership during preparation and exact
|
assembled engine; the runner checks membership during preparation and exact
|
||||||
profile inspection.
|
profile inspection.
|
||||||
|
|
||||||
The root engine assembles profile repositories in precedence order: in-memory
|
The root engine assembles one raw composite catalog in precedence order:
|
||||||
profiles, one ordinary configured source, an application fallback source, then
|
in-memory profiles, one ordinary configured source, an application fallback
|
||||||
the embedded built-in catalog. An explicit file or `fs.FS` profile source
|
source, then the embedded built-in catalog. An explicit file or `fs.FS` profile
|
||||||
replaces `Config.ProfileDir` within the ordinary configured-source category.
|
source replaces `Config.ProfileDir` within the ordinary configured-source
|
||||||
|
category. One outer resolving repository wraps that complete raw catalog, so
|
||||||
|
each base lookup observes the same precedence and shadowing rules.
|
||||||
|
|
||||||
Exact profile inspection performs one point-in-time lookup through those
|
The resolving repository traverses every selected chain afresh, retains no
|
||||||
profile sources and checks the resolved target without reading prompt, input,
|
cache, detects cycles, limits a chain to 32 profiles, merges root-to-leaf into a
|
||||||
|
new caller-owned value, and validates the final target before publishing it. It
|
||||||
|
does not check backend registry membership. Exact `base_profile` syntax, merge
|
||||||
|
rules, and consumer-visible failure behavior belong to the [framework format
|
||||||
|
reference](../formats.md#profile-inheritance).
|
||||||
|
|
||||||
|
Exact profile inspection performs one point-in-time resolved lookup through
|
||||||
|
those profile sources and checks the final target without reading prompt, input,
|
||||||
or schema sources. It does not retain that lookup for a later execution.
|
or schema sources. It does not retain that lookup for a later execution.
|
||||||
|
Prepared execution instead freezes the fully resolved target; a later ordinary
|
||||||
|
operation performs a fresh traversal.
|
||||||
|
|
||||||
`internal/profile/builtin` embeds the maintained built-in profile catalog.
|
`internal/profile/builtin` embeds the maintained built-in profile catalog.
|
||||||
Every embedded profile selects a maintained built-in backend and inherits that
|
Every embedded profile selects a maintained built-in backend and inherits that
|
||||||
|
|||||||
@@ -467,6 +467,8 @@ Stage 4 is complete when all focused and repository-wide checks pass and the
|
|||||||
implementation, GoDoc, format reference, internal documentation, and consumer
|
implementation, GoDoc, format reference, internal documentation, and consumer
|
||||||
guidance agree.
|
guidance agree.
|
||||||
|
|
||||||
|
**Status:** Complete.
|
||||||
|
|
||||||
## Open Questions
|
## Open Questions
|
||||||
|
|
||||||
None. Naming, supported sources, lookup precedence, merge behavior, connection
|
None. Naming, supported sources, lookup precedence, merge behavior, connection
|
||||||
|
|||||||
10
engine.go
10
engine.go
@@ -304,10 +304,12 @@ func WithFallbackProfileFS(fsys fs.FS, root string) Option {
|
|||||||
// WithProfiles configures in-memory profiles that take precedence over
|
// WithProfiles configures in-memory profiles that take precedence over
|
||||||
// ordinary configured, application fallback, and built-in profiles.
|
// ordinary configured, application fallback, and built-in profiles.
|
||||||
//
|
//
|
||||||
// NewEngine validates and copies every profile. IDs must be unique within one
|
// NewEngine locally validates and copies every profile. IDs must be unique
|
||||||
// call. An invalid profile, duplicate ID, or unsupported ExtraParams value
|
// within one call. An invalid local definition, duplicate ID, or unsupported
|
||||||
// makes construction fail with ErrInvalidConfig. Repeating WithProfiles
|
// ExtraParams value makes construction fail with ErrInvalidConfig. A derived
|
||||||
// replaces the complete earlier in-memory set rather than merging it.
|
// profile's base reference and resolved target completeness are checked when it
|
||||||
|
// is selected or inspected. Repeating WithProfiles replaces the complete
|
||||||
|
// earlier in-memory set rather than merging it.
|
||||||
func WithProfiles(profiles ...Profile) Option {
|
func WithProfiles(profiles ...Profile) Option {
|
||||||
return optionFunc(func(options *engineOptions) error {
|
return optionFunc(func(options *engineOptions) error {
|
||||||
repo, err := newMemoryProfileRepository(profiles)
|
repo, err := newMemoryProfileRepository(profiles)
|
||||||
|
|||||||
@@ -9,8 +9,9 @@ import (
|
|||||||
"gitea.maximumdirect.net/eric/promptkit/internal/profile"
|
"gitea.maximumdirect.net/eric/promptkit/internal/profile"
|
||||||
)
|
)
|
||||||
|
|
||||||
// OpenAICompatibleProfile returns an ordinary in-memory Profile for an
|
// OpenAICompatibleProfile returns an in-memory Profile for an OpenAI-compatible
|
||||||
// OpenAI-compatible chat-completions endpoint.
|
// chat-completions endpoint. A non-blank BaseProfileID permits its target
|
||||||
|
// fields to be inherited when the profile is selected or inspected.
|
||||||
//
|
//
|
||||||
// It does not register global state, maintain a model catalog, or resolve
|
// It does not register global state, maintain a model catalog, or resolve
|
||||||
// credentials. If APIKeyRequired is true, callers satisfy it with
|
// credentials. If APIKeyRequired is true, callers satisfy it with
|
||||||
|
|||||||
41
types.go
41
types.go
@@ -443,18 +443,22 @@ type ExecutionTargetOverride struct {
|
|||||||
|
|
||||||
// Profile is an in-memory execution profile for library consumers.
|
// Profile is an in-memory execution profile for library consumers.
|
||||||
//
|
//
|
||||||
// It is equivalent to a loaded profile file after validation. Raw API keys do
|
// A standalone Profile is equivalent to a loaded profile file after local
|
||||||
// not belong in profiles; use APIKeyRequired to require callers to provide a
|
// validation. A derived profile names BaseProfileID and can inherit target
|
||||||
// RunRequest.APIKey or explicit request ExecutionTargetOverride.APIKeyEnv, or
|
// fields when selected or inspected. Raw API keys do not belong in profiles;
|
||||||
// use profile YAML api_key_env with file and FS profile sources. Profile has no
|
// use APIKeyRequired to require callers to provide a RunRequest.APIKey or
|
||||||
// stable JSON representation.
|
// explicit request ExecutionTargetOverride.APIKeyEnv, or use profile YAML
|
||||||
|
// api_key_env with file and FS profile sources. Profile has no stable JSON
|
||||||
|
// representation.
|
||||||
//
|
//
|
||||||
// WithProfiles validates and copies Profile values during NewEngine. Zero
|
// WithProfiles locally validates and copies Profile values during NewEngine.
|
||||||
// Temperature, MaxTokens, and TopP values and blank ServiceTier and
|
// It checks base-reference existence and resolved target completeness when a
|
||||||
// ReasoningEffort values leave those provider controls unspecified. A zero
|
// derived profile is selected or inspected. Zero Temperature, MaxTokens, and
|
||||||
// TimeoutSeconds retains the framework deadline, while an empty ExtraParams map
|
// TopP values and blank ServiceTier and ReasoningEffort values leave those
|
||||||
// inherits backend request defaults. Use ExecutionTargetOverride pointer fields
|
// provider controls unspecified. A zero TimeoutSeconds retains the framework
|
||||||
// to request an explicit numeric zero.
|
// deadline, while an empty ExtraParams map inherits backend request defaults.
|
||||||
|
// Use ExecutionTargetOverride pointer fields to request an explicit numeric
|
||||||
|
// zero.
|
||||||
type Profile struct {
|
type Profile struct {
|
||||||
// ID is the required non-blank profile identifier. WithProfiles trims it.
|
// ID is the required non-blank profile identifier. WithProfiles trims it.
|
||||||
ID string
|
ID string
|
||||||
@@ -468,12 +472,14 @@ type Profile struct {
|
|||||||
// Backend membership is checked when a request selects the profile; an
|
// Backend membership is checked when a request selects the profile; an
|
||||||
// unknown ID makes preparation fail with ErrProfileLoad.
|
// unknown ID makes preparation fail with ErrProfileLoad.
|
||||||
BackendID string
|
BackendID string
|
||||||
// Endpoint is the model-provider base URL. It is required only when
|
// Endpoint is the model-provider base URL. A standalone Profile requires an
|
||||||
// BackendID is blank and otherwise overrides the backend endpoint when
|
// endpoint when BackendID is blank; a derived Profile may inherit either
|
||||||
|
// field. A non-blank endpoint overrides the backend endpoint when
|
||||||
// non-blank. WithProfiles trims it and requires an absolute HTTP or HTTPS URL
|
// non-blank. WithProfiles trims it and requires an absolute HTTP or HTTPS URL
|
||||||
// with a host and no user information, query, or fragment.
|
// with a host and no user information, query, or fragment.
|
||||||
Endpoint string
|
Endpoint string
|
||||||
// Model is the required non-blank provider model identifier.
|
// Model is the provider model identifier. It is required for a standalone
|
||||||
|
// Profile and may be inherited by a derived Profile.
|
||||||
Model string
|
Model string
|
||||||
// Temperature is from 0 through 2. Zero leaves the provider control
|
// Temperature is from 0 through 2. Zero leaves the provider control
|
||||||
// unspecified.
|
// unspecified.
|
||||||
@@ -505,14 +511,15 @@ type Profile struct {
|
|||||||
// profile.
|
// profile.
|
||||||
//
|
//
|
||||||
// It contains ordinary profile fields for OpenAI-compatible chat-completions
|
// It contains ordinary profile fields for OpenAI-compatible chat-completions
|
||||||
// endpoints. APIKeyRequired follows Profile.APIKeyRequired. Raw API keys do not
|
// endpoints. BaseProfileID and APIKeyRequired follow Profile. Raw API keys do
|
||||||
// belong in this config. OpenAICompatibleProfileConfig has no stable JSON
|
// not belong in this config. OpenAICompatibleProfileConfig has no stable JSON
|
||||||
// representation and is not validated until its resulting Profile is supplied
|
// representation and is not validated until its resulting Profile is supplied
|
||||||
// through WithProfiles to NewEngine.
|
// through WithProfiles to NewEngine.
|
||||||
type OpenAICompatibleProfileConfig struct {
|
type OpenAICompatibleProfileConfig struct {
|
||||||
// ID becomes Profile.ID.
|
// ID becomes Profile.ID.
|
||||||
ID string
|
ID string
|
||||||
// BaseProfileID becomes Profile.BaseProfileID.
|
// BaseProfileID becomes Profile.BaseProfileID. A non-blank value permits the
|
||||||
|
// resulting Profile to inherit target fields when it is selected or inspected.
|
||||||
BaseProfileID string
|
BaseProfileID string
|
||||||
// BackendID becomes Profile.BackendID.
|
// BackendID becomes Profile.BackendID.
|
||||||
BackendID string
|
BackendID string
|
||||||
|
|||||||
Reference in New Issue
Block a user