Document sequence composition for consumers

This commit is contained in:
2026-10-16 19:37:59 +00:00
parent 77c5d9482a
commit acddce8e2f
18 changed files with 300 additions and 39 deletions

View File

@@ -26,6 +26,13 @@ the [configuration contract](docs/config.md#effective-configuration-diffs) and
[consumer guide](docs/consumers/README.md#effective-configuration-diffs) describe [consumer guide](docs/consumers/README.md#effective-configuration-diffs) describe
its safe changed-region records and maintained workflows. its safe changed-region records and maintained workflows.
Sources can also be explicitly placed as sequence items, and definitions can
register selected sequences to append records with distinct string IDs during
strict composition. Higher-priority sequences still replace lower-priority
sequences as whole values. See the [sequence contract](docs/config.md#strict-document-composition),
[maintained prompt example](docs/consumers/README.md#identified-prompt-sequences),
and [ADR 0014](docs/adr/0014-sequence-placement-and-composition.md).
```go ```go
type Config struct { type Config struct {
Enabled bool `yaml:"enabled"` Enabled bool `yaml:"enabled"`
@@ -62,7 +69,10 @@ children; other values replace lower-priority values. The main document and its
imports form one strictly composed tier. Explicit underlay groups sit below it imports form one strictly composed tier. Explicit underlay groups sit below it
and above typed defaults; a selected overlay and explicit CLI overrides sit and above typed defaults; a selected overlay and explicit CLI overrides sit
above it. The [configuration contract](docs/config.md#strict-document-composition) above it. The [configuration contract](docs/config.md#strict-document-composition)
owns the detailed combination rules and input-specific constraints. owns the detailed combination rules and input-specific constraints. At
definition-registered paths only, strict composition can append records with
distinct explicit IDs; ordinary and unregistered sequences keep their conflict
or whole-value replacement behavior.
The [architecture goals](docs/policy/architecture.md#success-criteria) explain The [architecture goals](docs/policy/architecture.md#success-criteria) explain
these priorities and how genuine new needs can justify extending the shared these priorities and how genuine new needs can justify extending the shared
@@ -72,8 +82,10 @@ consideration in future releases.
The [configuration contract](docs/config.md) describes implemented behavior, The [configuration contract](docs/config.md) describes implemented behavior,
including [input destinations](docs/config.md#input-destinations). The including [input destinations](docs/config.md#input-destinations). The
[consumer adoption guide](docs/consumers/README.md) provides maintained simple, [consumer adoption guide](docs/consumers/README.md) provides maintained simple,
layered, and mounted-collection examples alongside the migration shapes. The layered, mounted-collection, and identified-prompt examples alongside the
accepted placement decision is recorded in [ADR 0011](docs/adr/0011-input-destinations.md). migration shapes. Input placement decisions are recorded in
[ADR 0011](docs/adr/0011-input-destinations.md) and sequence placement and
composition in [ADR 0014](docs/adr/0014-sequence-placement-and-composition.md).
See the [development guide](docs/development.md) for repository orientation and See the [development guide](docs/development.md) for repository orientation and
the [release procedure](docs/release.md) for maintainer-only candidate and the [release procedure](docs/release.md) for maintainer-only candidate and
publication steps. publication steps.

View File

@@ -2,8 +2,10 @@
## Status ## Status
Accepted. Implementation status and sequencing are tracked in the Accepted and implemented. The [configuration contract](../config.md#strict-document-composition)
[sequence composition implementation plan](../roadmap/implementation.md). defines current behavior, and the [consumer guide](../consumers/README.md#identified-prompt-sequences)
shows the maintained example. Implementation status and delivery sequencing
are tracked in the [implementation plan](../roadmap/implementation.md).
## Date ## Date

View File

@@ -154,6 +154,11 @@ have index zero. Explicit empty groups and `NoSource` consume no source ID.
Byte, source, node, and glob-entry budgets are shared across the load, while Byte, source, node, and glob-entry budgets are shared across the load, while
the existing per-source and import-depth bounds still apply. the existing per-source and import-depth bounds still apply.
When a source mapping is explicitly placed as an item, its effective destination
is the sequence container. After assembly assigns an index, nested source
destinations are projected through that item. Physical source locations and
resource contexts continue to identify the declaring source.
#### Input destinations #### Input destinations
`Input.Destination` places the source's application mapping beneath a path `Input.Destination` places the source's application mapping beneath a path
@@ -411,6 +416,11 @@ the descendant can therefore retain history after `Lookup` stops reporting it as
effective. Equal-valued input is still an explicit base definition, while a derived effective. Equal-valued input is still an explicit base definition, while a derived
value for absent input remains non-explicit. value for absent input remains non-explicit.
Appending registered records during strict composition assigns each contribution
its assembled sequence index in history. A later precedence tier that supplies a
sequence records replacement at the sequence path; history does not imply
identity-based merging across tiers.
A mapping assembled from the selected file and imports has one composite base origin A mapping assembled from the selected file and imports has one composite base origin
whose locations retain source traversal order. A mapping also visited by an overlay whose locations retain source traversal order. A mapping also visited by an overlay
has an overlay-layer composite origin with the lower contributing locations followed has an overlay-layer composite origin with the lower contributing locations followed
@@ -790,6 +800,14 @@ a present higher-priority sequence replaces the lower sequence as one value,
including at a registered path. Overlays, CLI overrides, defaults, inheritance, including at a registered path. Overlays, CLI overrides, defaults, inheritance,
and application resolution do not run the registered identity check. The accepted and application resolution do not run the registered identity check. The accepted
rationale is recorded in [ADR 0014](adr/0014-sequence-placement-and-composition.md). rationale is recorded in [ADR 0014](adr/0014-sequence-placement-and-composition.md).
The [maintained prompt catalog](consumers/README.md#identified-prompt-sequences)
shows item path and glob imports, helper-supplied identity, and main-tier
replacement of a lower-priority sequence.
When an enabled source-version mode is selected, declarations are checked in each
source's own coordinates before placement and composition. Accepted non-main
headers are consumed before strict composition and cannot supply a registered
record identity. Final typed decoding and application validation still run on the
completed configuration.
An empty mapping contributes no child definitions. Two empty mappings compose, and An empty mapping contributes no child definitions. Two empty mappings compose, and
an empty mapping neither clears nor conflicts with another mapping's children. an empty mapping neither clears nor conflicts with another mapping's children.
@@ -932,7 +950,11 @@ placement requires a nonempty effective destination and wraps the imported
mapping as one element of a sequence there. It does not split source sequences mapping as one element of a sequence there. It does not split source sequences
or infer identity fields. Repeated sequences still conflict unless their path is or infer identity fields. Repeated sequences still conflict unless their path is
registered through `Definition.SequenceCompositions`; registration does not registered through `Definition.SequenceCompositions`; registration does not
change placement or precedence behavior. change placement or precedence behavior. Sequence records retain source
locations through placement and history; indexes describe their assembled
positions while source coordinates continue to identify the declaring files.
Header/version policy and final application validation retain their existing
owners and timing; sequence registration is a strict-composition rule only.
An item import first opens a local mapping scope. Its body and ordinary helper An item import first opens a local mapping scope. Its body and ordinary helper
imports compose within that record. An omitted helper destination or imports compose within that record. An omitted helper destination or

View File

@@ -21,6 +21,7 @@ sanitized shapes using only ConfigKit and the Go standard library:
| Named presets | One-load sibling inheritance, explicit false, nested destination resolution, and source/derivation inspection | Choosing and executing a preset | | Named presets | One-load sibling inheritance, explicit false, nested destination resolution, and source/derivation inspection | Choosing and executing a preset |
| Effective configuration diff | Same-type frozen effective comparisons for two selected files or base-versus-overlay impact | Source/options selection and consumer-owned safe presentation | | Effective configuration diff | Same-type frozen effective comparisons for two selected files or base-versus-overlay impact | Source/options selection and consumer-owned safe presentation |
| Shared source-version checks | One `Definition.Version` policy for accepted declarations across participating source documents, with optional or required declarations and sanitized evidence | Choosing which declarations the application accepts; final assembled schema and domain validation | | Shared source-version checks | One `Definition.Version` policy for accepted declarations across participating source documents, with optional or required declarations and sanitized evidence | Choosing which declarations the application accepts; final assembled schema and domain validation |
| Identified prompt sequences | Explicit item path/glob imports, helper-supplied IDs, reusable single-field registration, and main-tier replacement of a lower-priority collection | Prompt meaning and final domain validation |
The YAML under [`testdata`](../../examples/consumers/testdata) is loaded by the The YAML under [`testdata`](../../examples/consumers/testdata) is loaded by the
executable examples and ordinary tests. It contains no private application data, executable examples and ordinary tests. It contains no private application data,
@@ -163,6 +164,24 @@ relative resources, and strict peer conflicts. The
[configuration contract](../config.md#input-destinations) owns shared placement, [configuration contract](../config.md#input-destinations) owns shared placement,
import, source-location, and ownership behavior. import, source-location, and ownership behavior.
## Identified prompt sequences
[`LoadPromptCatalog`](../../examples/consumers/prompt_catalog.go) uses one
definition registration for the literal `prompts` path and `id` field. Its main
file imports one prompt by path and others by glob, placing each source as an
item. A nested ordinary helper import supplies an item's ID. The main tier
strictly appends the distinct records in contribution order; its completed
sequence replaces the lower-priority default collection as one value.
The example's `validatePromptCatalog` remains application-owned. It checks that
prompt names and message lists satisfy this consumer's requirements after
ConfigKit has composed, projected, and decoded the configuration. It does not
add recursive record merging, identity-based overlay, or final uniqueness checks
after defaults and resolution. See the [strict composition contract](../config.md#strict-document-composition),
[import syntax](../config.md#explicit-imports), and
[ADR 0014](../adr/0014-sequence-placement-and-composition.md) for the exact
boundaries.
Known module catalogs should use canonical object entries with a module identifier Known module catalogs should use canonical object entries with a module identifier
and typed options. A small union struct is sufficient when the available option and typed options. A small union struct is sufficient when the available option
fields are known; validation selects which fields apply to each module. Runtime- fields are known; validation selects which fields apply to each module. Runtime-

View File

@@ -131,6 +131,12 @@ Current behavior belongs to the configuration contract's
[input destinations](config.md#input-destinations), [input destinations](config.md#input-destinations),
[imports](config.md#explicit-imports), and [imports](config.md#explicit-imports), and
[shared source-version checks](config.md#shared-source-version-checks) sections. [shared source-version checks](config.md#shared-source-version-checks) sections.
Explicit sequence-item placement and registered strict composition are owned by
the [strict composition](config.md#strict-document-composition) and
[imports](config.md#explicit-imports) sections. The
[maintained prompt catalog](consumers/README.md#identified-prompt-sequences)
shows the current consumer boundary, and [ADR 0014](adr/0014-sequence-placement-and-composition.md)
records the decision.
Potential enhancements are tracked in [future features](roadmap/future.md). Potential enhancements are tracked in [future features](roadmap/future.md).
Install the Go version required by `go.mod` or a compatible newer toolchain. Install the Go version required by `go.mod` or a compatible newer toolchain.

View File

@@ -9,9 +9,12 @@ Implemented component owners:
- `internal/engine` owns host and native-filesystem source acquisition, - `internal/engine` owns host and native-filesystem source acquisition,
grouped strict composition, recursive precedence assembly, per-input mapping grouped strict composition, recursive precedence assembly, per-input mapping
placement and immediate-parent-relative import placement within that and sequence-item placement, definition-registered distinct-ID sequence
assembly, destination-local sibling inheritance before typed decoding, and composition within strict tiers, and immediate-parent-relative import
shared source-version checking with sanitized declaration evidence. placement within that assembly. Higher-priority sequences replace lower
sequences as whole values. The engine also owns destination-local sibling
inheritance before typed decoding, plus shared source-version checking with
sanitized declaration evidence.
It retains each source's effective placement alongside physical source It retains each source's effective placement alongside physical source
identity and owns schema identity and owns schema
inspection, lifecycle coordination, callback auditing, inspection, lifecycle coordination, callback auditing,
@@ -48,6 +51,10 @@ The [configuration contract](../config.md) owns implemented YAML and lifecycle
semantics, including [input destinations](../config.md#input-destinations), semantics, including [input destinations](../config.md#input-destinations),
[shared source-version checks](../config.md#shared-source-version-checks), and [shared source-version checks](../config.md#shared-source-version-checks), and
[effective configuration diffs](../config.md#effective-configuration-diffs). [effective configuration diffs](../config.md#effective-configuration-diffs).
The [strict composition contract](../config.md#strict-document-composition)
owns sequence placement, registration, replacement, and history behavior; the
[consumer guide](../consumers/README.md#identified-prompt-sequences) shows the
maintained example.
The [consumer adoption guide](../consumers/README.md) owns application guidance. The [consumer adoption guide](../consumers/README.md) owns application guidance.
The [architecture policy](../policy/architecture.md) owns contributor The [architecture policy](../policy/architecture.md) owns contributor
boundaries; [ADR 0006](../adr/0006-public-facade.md) records the facade decision boundaries; [ADR 0006](../adr/0006-public-facade.md) records the facade decision
@@ -59,3 +66,5 @@ and [release procedure](../release.md) for source-candidate gates. [ADR
post-assembly structural operation. [ADR 0012](../adr/0012-relative-import-destinations.md) post-assembly structural operation. [ADR 0012](../adr/0012-relative-import-destinations.md)
records the relative-import extension; [ADR 0013](../adr/0013-shared-source-version-checks.md) records the relative-import extension; [ADR 0013](../adr/0013-shared-source-version-checks.md)
records the source-version decision. records the source-version decision.
[ADR 0014](../adr/0014-sequence-placement-and-composition.md) records explicit
sequence placement and composition.

View File

@@ -163,19 +163,22 @@ framework on this library.
Within a configuration tier, independent contributions use strict composition: Within a configuration tier, independent contributions use strict composition:
shared mappings combine recursively, while overlapping non-mapping definitions shared mappings combine recursively, while overlapping non-mapping definitions
are conflicts, including equal values. Between precedence tiers, intentional are conflicts, including equal values, except that sequences at explicitly
overlay combines mappings recursively, retains omitted lower-priority children, registered paths append records with distinct present string identities. Between
precedence tiers, intentional overlay combines mappings recursively, retains
omitted lower-priority children,
and replaces other present values according to the existing overlay rules. and replaces other present values according to the existing overlay rules.
Tier precedence is explicit; traversal order within a tier establishes stable Tier precedence is explicit; traversal order within a tier establishes stable
reporting, not permission to override. The distinction and its rationale are reporting, not permission to override. The distinction and its rationale are
recorded in [ADR 0001](../adr/0001-separate-composition-and-overlay.md). recorded in [ADR 0001](../adr/0001-separate-composition-and-overlay.md).
At definition-registered sequence paths, strict composition appends mapping Sequence-item placement and sequence registration are explicit source and
records with distinct present string identities and rejects duplicates. definition controls; registration does not change precedence replacement. The
Placement and registration are explicit source and definition controls; they do [configuration contract](../config.md#strict-document-composition) defines the
not change precedence replacement. The [configuration contract](../config.md#strict-document-composition) behavior, [ADR 0014](../adr/0014-sequence-placement-and-composition.md) records
defines the behavior, and [ADR 0014](../adr/0014-sequence-placement-and-composition.md) the decision, and the [consumer guide](../consumers/README.md#identified-prompt-sequences)
records the decision. shows the implemented subset. This feature does not authorize arbitrary
configurable merge strategies.
The main document and its imports form a strictly composed tier. Explicit The main document and its imports form a strictly composed tier. Explicit
underlay groups compose strictly within each group, then combine recursively underlay groups compose strictly within each group, then combine recursively

View File

@@ -15,11 +15,12 @@ PromptKit repository at
PromptKit selected mounted mappings instead; this feature is not a dependency PromptKit selected mounted mappings instead; this feature is not a dependency
of that design or a request to restore multiple installed prompt versions. of that design or a request to restore multiple installed prompt versions.
A narrower [sequence placement and composition roadmap](sequence-composition.md) A narrower [sequence placement and composition feature](../config.md#strict-document-composition)
now covers placing source mappings as sequence items, single-field identities, is implemented: consumers can place imported mappings as sequence items and
duplicate rejection during strict composition, and whole-sequence replacement register a single literal string identity field for duplicate-rejecting strict
between precedence layers. The additional capabilities below remain deferred composition. Precedence still replaces sequences as whole values. This entry
and are not requirements of that roadmap. tracks broader identified-record behavior that remains deferred and is not part
of that implemented contract.
### Motivation and proposed behavior ### Motivation and proposed behavior
@@ -27,13 +28,16 @@ Allow applications to declare that selected sequences contain records identified
by explicit fields, while retaining sequence-shaped output for slice decoding by explicit fields, while retaining sequence-shaped output for slice decoding
and effective YAML. This could make composite identities and independently and effective YAML. This could make composite identities and independently
authored catalogs more convenient than encoding identity in nested mapping keys. authored catalogs more convenient than encoding identity in nested mapping keys.
Current [composition](../config.md#strict-document-composition) and Current [composition](../config.md#strict-document-composition) appends distinct
[overlay](../config.md#selected-overlays) treat sequences atomically. records only at explicitly registered paths; other sequences remain atomic.
Selected [overlays](../config.md#selected-overlays) always treat sequences
atomically.
The proposed opt-in registration belongs in the reusable application definition: The proposed broader opt-in registration would extend the current reusable
an exact effective sequence path after input/import placement, plus an ordered, application definition from one identity field to a composite identity made of
nonempty set of distinct direct string-field names. For example, records at an ordered, nonempty set of distinct direct string-field names. For example,
`profiles` could be identified by `(namespace, id)`. Records `(provider, brief)` records at `profiles` could be identified by `(namespace, id)`. Records
`(provider, brief)`
and `(application, brief)` would coexist, and a later layer could update the and `(application, brief)` would coexist, and a later layer could update the
provider record's temperature while retaining its backend and model. provider record's temperature while retaining its backend and model.

View File

@@ -1,6 +1,6 @@
# Implementation Plan: Sequence Placement and Composition # Implementation Plan: Sequence Placement and Composition
Status: implementation in progress; stages 1–12 completed. Status: implementation in progress; stages 1–13 completed.
## Purpose and authority ## Purpose and authority
@@ -756,6 +756,24 @@ Validation: executable example/consumer tests, local documentation-link tests,
whitespace review, and `./scripts/check.sh`. whitespace review, and `./scripts/check.sh`.
Completion: current docs and tested public examples describe what actually lands. Completion: current docs and tested public examples describe what actually lands.
Completion evidence: the canonical configuration contract and architecture
policy now describe placement, registered strict composition, version/header
boundaries, source containers, history, and unchanged precedence. README,
consumer, development, and internal guides link to those contracts and the
maintained prompt-catalog example. The example uses disposable in-repository
fixtures to demonstrate path/glob item imports, a helper-supplied identity,
strict composition, whole-sequence replacement of defaults, and consumer-owned
validation. The feature roadmap and ADR status point to the implemented contract
and delivery record; broader composite-identity behavior remains deferred.
These checks passed with Go `go1.26.9 linux/amd64`:
- `GOTOOLCHAIN=local GOPROXY=off go test ./examples/consumers`
- `GOTOOLCHAIN=local GOPROXY=off go test -race ./...`
- `GOTOOLCHAIN=local GOPROXY=off ./scripts/check.sh`
- `git diff --check`
No environmental limitation affected validation; checks ran on Linux/amd64.
## Stage 14 — Review the completed unit and hand off ## Stage 14 — Review the completed unit and hand off
- Read the complete implementation diff against `2051177` and the feature - Read the complete implementation diff against `2051177` and the feature

View File

@@ -1,8 +1,9 @@
# Sequence-Item Placement and Identity-Based Composition # Sequence-Item Placement and Identity-Based Composition
Status: design decisions settled; not implemented. This roadmap owns the target Status: implemented. This roadmap records the target state and accepted behavior.
state and accepted behavior. The [implementation plan](implementation.md) owns The [configuration contract](../config.md#strict-document-composition) defines
concrete API/syntax choices, execution order, validation, and progress. the current behavior, and the [implementation plan](implementation.md) records
delivery sequencing and validation.
## Goal and current baseline ## Goal and current baseline
@@ -11,13 +12,12 @@ files. Placement makes a source mapping one sequence item; identity-based strict
composition combines distinct items and rejects repeated identities. These are composition combines distinct items and rejects repeated identities. These are
complementary operations, with explicit consumer opt-in. complementary operations, with explicit consumer opt-in.
Current [input destinations](../config.md#input-destinations) place source Sources can explicitly place mappings as sequence items at non-root destinations,
mappings beneath mapping-key paths. Imports support immediate-parent-relative and definitions can register literal sequence paths with one literal string
destinations. Current [strict composition](../config.md#strict-document-composition) identity field for duplicate-rejecting strict composition. Ordinary unregistered
combines mappings recursively and rejects other overlaps, while sequences retain strict conflict behavior. [Precedence assembly](../config.md#layered-loading)
[precedence assembly](../config.md#layered-loading) and and [selected overlays](../config.md#selected-overlays) continue to replace
[selected overlays](../config.md#selected-overlays) replace sequences wholesale. sequences wholesale. The canonical contract documents the exact rules and limits.
Neither sequence-item placement nor sequence-composition registration exists today.
This roadmap covers a narrower feature than the This roadmap covers a narrower feature than the
[identified record sequences candidate](future.md#1-identified-record-sequences). [identified record sequences candidate](future.md#1-identified-record-sequences).

View File

@@ -0,0 +1,53 @@
package consumers
import (
"strings"
configkit "gitea.maximumdirect.net/eric/ConfigKit"
)
// PromptCatalogConfig is an application-owned prompt collection shape.
type PromptCatalogConfig struct {
Prompts []PromptRecord `yaml:"prompts"`
}
// PromptRecord keeps its identity and message meaning in the consumer.
type PromptRecord struct {
ID string `yaml:"id"`
Name string `yaml:"name"`
Messages []string `yaml:"messages"`
}
// LoadPromptCatalog composes explicitly registered prompt records in the main
// tier and replaces the lower-priority default collection as a whole.
func LoadPromptCatalog(mainPath string) (*configkit.Result[PromptCatalogConfig], error) {
return configkit.LoadLayered(configkit.Input{
Source: configkit.File(mainPath),
Imports: true,
}, configkit.LayeredOptions[PromptCatalogConfig]{
Underlays: []configkit.Underlay{{Inputs: []configkit.Input{{
Source: configkit.Bytes("default prompts", []byte("prompts:\n - id: default\n name: Default prompt\n messages: [Default message]\n")),
}}}},
Definition: configkit.Definition[PromptCatalogConfig]{
SequenceCompositions: []configkit.SequenceComposition{{
Path: configkit.Keys("prompts"),
IdentityField: "id",
}},
Validate: validatePromptCatalog,
},
})
}
func validatePromptCatalog(configuration *PromptCatalogConfig, validation *configkit.Validation) {
for index, prompt := range configuration.Prompts {
if strings.TrimSpace(prompt.Name) == "" {
validation.Error(configkit.Keys("prompts").Index(index).Key("name"), "must not be empty")
}
if len(prompt.Messages) == 0 {
validation.Error(configkit.Keys("prompts").Index(index).Key("messages"), "must contain at least one message")
}
}
if len(configuration.Prompts) == 0 {
validation.Error(configkit.Keys("prompts"), "must contain at least one prompt")
}
}

View File

@@ -0,0 +1,82 @@
package consumers_test
import (
"errors"
"fmt"
"path/filepath"
"testing"
configkit "gitea.maximumdirect.net/eric/ConfigKit"
"gitea.maximumdirect.net/eric/ConfigKit/examples/consumers"
)
func Example_identifiedPromptCatalog() {
result, err := consumers.LoadPromptCatalog(fixture("prompt-catalog", "config.yml"))
if err != nil {
fmt.Println(err)
return
}
ids := make([]string, 0, len(result.Config.Prompts))
for _, prompt := range result.Config.Prompts {
ids = append(ids, prompt.ID)
}
fmt.Println(ids, err)
// Output: [main curated weather welcome] <nil>
}
func TestPromptCatalogImportsRegisteredItemsAndReplacesDefaults(t *testing.T) {
result, err := consumers.LoadPromptCatalog(fixture("prompt-catalog", "config.yml"))
if err != nil {
var loadError *configkit.LoadError
if errors.As(err, &loadError) {
t.Fatalf("load prompt catalog: %v (%#v)", err, loadError.Diagnostics())
}
t.Fatal(err)
}
if len(result.Config.Prompts) != 4 {
t.Fatalf("prompt records = %#v", result.Config.Prompts)
}
ids := []string{"main", "curated", "weather", "welcome"}
for index, id := range ids {
if result.Config.Prompts[index].ID != id {
t.Fatalf("prompt %d ID = %q, want %q", index, result.Config.Prompts[index].ID, id)
}
}
for _, prompt := range result.Config.Prompts {
if prompt.ID == "default" {
t.Fatalf("lower-priority default survived main sequence replacement: %#v", result.Config.Prompts)
}
}
var itemImports, helperImports int
for _, source := range result.Sources() {
switch filepath.Base(source.Path) {
case "curated.yml", "generated-weather.yml", "generated-welcome.yml":
if source.PlacementMode != configkit.PlacementModeSequenceItem || source.Destination.String() != "/prompts" {
t.Fatalf("item source placement = %#v", source)
}
itemImports++
case "curated-id.yml":
if source.PlacementMode != configkit.PlacementModeMapping || source.ImportedFrom == nil {
t.Fatalf("helper source = %#v", source)
}
helperImports++
}
}
if itemImports != 3 || helperImports != 1 {
t.Fatalf("item imports = %d, helper imports = %d, sources = %#v", itemImports, helperImports, result.Sources())
}
if result.Config.Prompts[1].ID != "curated" {
t.Fatalf("helper did not provide prompt ID: %#v", result.Config.Prompts[1])
}
}
func TestPromptCatalogLeavesDomainValidationWithConsumer(t *testing.T) {
_, err := consumers.LoadPromptCatalog(fixture("prompt-catalog", "invalid.yml"))
var loadError *configkit.LoadError
if !errors.As(err, &loadError) || len(loadError.Diagnostics()) != 1 ||
loadError.Diagnostics()[0].Code != configkit.CodeValidateError ||
loadError.Diagnostics()[0].Path.String() != "/prompts/0/messages" {
t.Fatalf("consumer domain validation error = %v", err)
}
}

View File

@@ -0,0 +1,12 @@
configkit:
imports:
- path: prompts/curated.yml
destination: [prompts]
placement: sequence-item
- glob: prompts/generated-*.yml
destination: [prompts]
placement: sequence-item
prompts:
- id: main
name: Main authored prompt
messages: [Use the main prompt.]

View File

@@ -0,0 +1,4 @@
prompts:
- id: invalid
name: Invalid prompt
messages: []

View File

@@ -0,0 +1 @@
id: curated

View File

@@ -0,0 +1,6 @@
configkit:
imports:
- path: curated-id.yml
name: Curated summary
messages:
- Summarize the supplied content.

View File

@@ -0,0 +1,4 @@
id: weather
name: Weather forecast
messages:
- Describe today's forecast.

View File

@@ -0,0 +1,4 @@
id: welcome
name: Welcome
messages:
- Welcome the user.