From acddce8e2f18d5837752ae13df43ab37141f956e Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Fri, 16 Oct 2026 19:37:59 +0000 Subject: [PATCH] Document sequence composition for consumers --- README.md | 18 +++- ...0014-sequence-placement-and-composition.md | 6 +- docs/config.md | 24 +++++- docs/consumers/README.md | 19 +++++ docs/development.md | 6 ++ docs/internal/overview.md | 15 +++- docs/policy/architecture.md | 19 +++-- docs/roadmap/future.md | 26 +++--- docs/roadmap/implementation.md | 20 ++++- docs/roadmap/sequence-composition.md | 20 ++--- examples/consumers/prompt_catalog.go | 53 ++++++++++++ examples/consumers/prompt_catalog_test.go | 82 +++++++++++++++++++ .../testdata/prompt-catalog/config.yml | 12 +++ .../testdata/prompt-catalog/invalid.yml | 4 + .../prompt-catalog/prompts/curated-id.yml | 1 + .../prompt-catalog/prompts/curated.yml | 6 ++ .../prompts/generated-weather.yml | 4 + .../prompts/generated-welcome.yml | 4 + 18 files changed, 300 insertions(+), 39 deletions(-) create mode 100644 examples/consumers/prompt_catalog.go create mode 100644 examples/consumers/prompt_catalog_test.go create mode 100644 examples/consumers/testdata/prompt-catalog/config.yml create mode 100644 examples/consumers/testdata/prompt-catalog/invalid.yml create mode 100644 examples/consumers/testdata/prompt-catalog/prompts/curated-id.yml create mode 100644 examples/consumers/testdata/prompt-catalog/prompts/curated.yml create mode 100644 examples/consumers/testdata/prompt-catalog/prompts/generated-weather.yml create mode 100644 examples/consumers/testdata/prompt-catalog/prompts/generated-welcome.yml diff --git a/README.md b/README.md index d6ed883..4235e7e 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,13 @@ the [configuration contract](docs/config.md#effective-configuration-diffs) and [consumer guide](docs/consumers/README.md#effective-configuration-diffs) describe 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 type Config struct { 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 and above typed defaults; a selected overlay and explicit CLI overrides sit 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 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, including [input destinations](docs/config.md#input-destinations). The [consumer adoption guide](docs/consumers/README.md) provides maintained simple, -layered, and mounted-collection examples alongside the migration shapes. The -accepted placement decision is recorded in [ADR 0011](docs/adr/0011-input-destinations.md). +layered, mounted-collection, and identified-prompt examples alongside the +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 the [release procedure](docs/release.md) for maintainer-only candidate and publication steps. diff --git a/docs/adr/0014-sequence-placement-and-composition.md b/docs/adr/0014-sequence-placement-and-composition.md index 8ecfcec..25991cf 100644 --- a/docs/adr/0014-sequence-placement-and-composition.md +++ b/docs/adr/0014-sequence-placement-and-composition.md @@ -2,8 +2,10 @@ ## Status -Accepted. Implementation status and sequencing are tracked in the -[sequence composition implementation plan](../roadmap/implementation.md). +Accepted and implemented. The [configuration contract](../config.md#strict-document-composition) +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 diff --git a/docs/config.md b/docs/config.md index d398a3a..f4fb16b 100644 --- a/docs/config.md +++ b/docs/config.md @@ -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 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.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 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 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 @@ -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, 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). +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 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 or infer identity fields. Repeated sequences still conflict unless their path is 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 imports compose within that record. An omitted helper destination or diff --git a/docs/consumers/README.md b/docs/consumers/README.md index dae7a86..60e95b5 100644 --- a/docs/consumers/README.md +++ b/docs/consumers/README.md @@ -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 | | 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 | +| 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 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, 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 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- diff --git a/docs/development.md b/docs/development.md index 0f1771a..103dc46 100644 --- a/docs/development.md +++ b/docs/development.md @@ -131,6 +131,12 @@ Current behavior belongs to the configuration contract's [input destinations](config.md#input-destinations), [imports](config.md#explicit-imports), and [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). Install the Go version required by `go.mod` or a compatible newer toolchain. diff --git a/docs/internal/overview.md b/docs/internal/overview.md index 1019f3d..60347a2 100644 --- a/docs/internal/overview.md +++ b/docs/internal/overview.md @@ -9,9 +9,12 @@ Implemented component owners: - `internal/engine` owns host and native-filesystem source acquisition, grouped strict composition, recursive precedence assembly, per-input mapping - placement and immediate-parent-relative import placement within that - assembly, destination-local sibling inheritance before typed decoding, and - shared source-version checking with sanitized declaration evidence. + and sequence-item placement, definition-registered distinct-ID sequence + composition within strict tiers, and immediate-parent-relative import + 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 identity and owns schema 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), [shared source-version checks](../config.md#shared-source-version-checks), and [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 [architecture policy](../policy/architecture.md) owns contributor 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) records the relative-import extension; [ADR 0013](../adr/0013-shared-source-version-checks.md) records the source-version decision. +[ADR 0014](../adr/0014-sequence-placement-and-composition.md) records explicit +sequence placement and composition. diff --git a/docs/policy/architecture.md b/docs/policy/architecture.md index 9122342..1d7bd34 100644 --- a/docs/policy/architecture.md +++ b/docs/policy/architecture.md @@ -163,19 +163,22 @@ framework on this library. Within a configuration tier, independent contributions use strict composition: shared mappings combine recursively, while overlapping non-mapping definitions -are conflicts, including equal values. Between precedence tiers, intentional -overlay combines mappings recursively, retains omitted lower-priority children, +are conflicts, including equal values, except that sequences at explicitly +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. Tier precedence is explicit; traversal order within a tier establishes stable reporting, not permission to override. The distinction and its rationale are recorded in [ADR 0001](../adr/0001-separate-composition-and-overlay.md). -At definition-registered sequence paths, strict composition appends mapping -records with distinct present string identities and rejects duplicates. -Placement and registration are explicit source and definition controls; they do -not change precedence replacement. The [configuration contract](../config.md#strict-document-composition) -defines the behavior, and [ADR 0014](../adr/0014-sequence-placement-and-composition.md) -records the decision. +Sequence-item placement and sequence registration are explicit source and +definition controls; registration does not change precedence replacement. The +[configuration contract](../config.md#strict-document-composition) defines the +behavior, [ADR 0014](../adr/0014-sequence-placement-and-composition.md) records +the decision, and the [consumer guide](../consumers/README.md#identified-prompt-sequences) +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 underlay groups compose strictly within each group, then combine recursively diff --git a/docs/roadmap/future.md b/docs/roadmap/future.md index 6469dfd..870495d 100644 --- a/docs/roadmap/future.md +++ b/docs/roadmap/future.md @@ -15,11 +15,12 @@ PromptKit repository at PromptKit selected mounted mappings instead; this feature is not a dependency of that design or a request to restore multiple installed prompt versions. -A narrower [sequence placement and composition roadmap](sequence-composition.md) -now covers placing source mappings as sequence items, single-field identities, -duplicate rejection during strict composition, and whole-sequence replacement -between precedence layers. The additional capabilities below remain deferred -and are not requirements of that roadmap. +A narrower [sequence placement and composition feature](../config.md#strict-document-composition) +is implemented: consumers can place imported mappings as sequence items and +register a single literal string identity field for duplicate-rejecting strict +composition. Precedence still replaces sequences as whole values. This entry +tracks broader identified-record behavior that remains deferred and is not part +of that implemented contract. ### 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 and effective YAML. This could make composite identities and independently authored catalogs more convenient than encoding identity in nested mapping keys. -Current [composition](../config.md#strict-document-composition) and -[overlay](../config.md#selected-overlays) treat sequences atomically. +Current [composition](../config.md#strict-document-composition) appends distinct +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: -an exact effective sequence path after input/import placement, plus an ordered, -nonempty set of distinct direct string-field names. For example, records at -`profiles` could be identified by `(namespace, id)`. Records `(provider, brief)` +The proposed broader opt-in registration would extend the current reusable +application definition from one identity field to a composite identity made of +an ordered, nonempty set of distinct direct string-field names. For example, +records at `profiles` could be identified by `(namespace, id)`. Records +`(provider, brief)` and `(application, brief)` would coexist, and a later layer could update the provider record's temperature while retaining its backend and model. diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index a60d67a..7f0b585 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -1,6 +1,6 @@ # 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 @@ -756,6 +756,24 @@ Validation: executable example/consumer tests, local documentation-link tests, whitespace review, and `./scripts/check.sh`. 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 - Read the complete implementation diff against `2051177` and the feature diff --git a/docs/roadmap/sequence-composition.md b/docs/roadmap/sequence-composition.md index 5df3335..05b060c 100644 --- a/docs/roadmap/sequence-composition.md +++ b/docs/roadmap/sequence-composition.md @@ -1,8 +1,9 @@ # Sequence-Item Placement and Identity-Based Composition -Status: design decisions settled; not implemented. This roadmap owns the target -state and accepted behavior. The [implementation plan](implementation.md) owns -concrete API/syntax choices, execution order, validation, and progress. +Status: implemented. This roadmap records the target state and accepted behavior. +The [configuration contract](../config.md#strict-document-composition) defines +the current behavior, and the [implementation plan](implementation.md) records +delivery sequencing and validation. ## 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 complementary operations, with explicit consumer opt-in. -Current [input destinations](../config.md#input-destinations) place source -mappings beneath mapping-key paths. Imports support immediate-parent-relative -destinations. Current [strict composition](../config.md#strict-document-composition) -combines mappings recursively and rejects other overlaps, while -[precedence assembly](../config.md#layered-loading) and -[selected overlays](../config.md#selected-overlays) replace sequences wholesale. -Neither sequence-item placement nor sequence-composition registration exists today. +Sources can explicitly place mappings as sequence items at non-root destinations, +and definitions can register literal sequence paths with one literal string +identity field for duplicate-rejecting strict composition. Ordinary unregistered +sequences retain strict conflict behavior. [Precedence assembly](../config.md#layered-loading) +and [selected overlays](../config.md#selected-overlays) continue to replace +sequences wholesale. The canonical contract documents the exact rules and limits. This roadmap covers a narrower feature than the [identified record sequences candidate](future.md#1-identified-record-sequences). diff --git a/examples/consumers/prompt_catalog.go b/examples/consumers/prompt_catalog.go new file mode 100644 index 0000000..ac60d59 --- /dev/null +++ b/examples/consumers/prompt_catalog.go @@ -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") + } +} diff --git a/examples/consumers/prompt_catalog_test.go b/examples/consumers/prompt_catalog_test.go new file mode 100644 index 0000000..06e2c66 --- /dev/null +++ b/examples/consumers/prompt_catalog_test.go @@ -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] +} + +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) + } +} diff --git a/examples/consumers/testdata/prompt-catalog/config.yml b/examples/consumers/testdata/prompt-catalog/config.yml new file mode 100644 index 0000000..0b786e0 --- /dev/null +++ b/examples/consumers/testdata/prompt-catalog/config.yml @@ -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.] diff --git a/examples/consumers/testdata/prompt-catalog/invalid.yml b/examples/consumers/testdata/prompt-catalog/invalid.yml new file mode 100644 index 0000000..a916db6 --- /dev/null +++ b/examples/consumers/testdata/prompt-catalog/invalid.yml @@ -0,0 +1,4 @@ +prompts: + - id: invalid + name: Invalid prompt + messages: [] diff --git a/examples/consumers/testdata/prompt-catalog/prompts/curated-id.yml b/examples/consumers/testdata/prompt-catalog/prompts/curated-id.yml new file mode 100644 index 0000000..2ac7243 --- /dev/null +++ b/examples/consumers/testdata/prompt-catalog/prompts/curated-id.yml @@ -0,0 +1 @@ +id: curated diff --git a/examples/consumers/testdata/prompt-catalog/prompts/curated.yml b/examples/consumers/testdata/prompt-catalog/prompts/curated.yml new file mode 100644 index 0000000..e554c31 --- /dev/null +++ b/examples/consumers/testdata/prompt-catalog/prompts/curated.yml @@ -0,0 +1,6 @@ +configkit: + imports: + - path: curated-id.yml +name: Curated summary +messages: + - Summarize the supplied content. diff --git a/examples/consumers/testdata/prompt-catalog/prompts/generated-weather.yml b/examples/consumers/testdata/prompt-catalog/prompts/generated-weather.yml new file mode 100644 index 0000000..0e52ce8 --- /dev/null +++ b/examples/consumers/testdata/prompt-catalog/prompts/generated-weather.yml @@ -0,0 +1,4 @@ +id: weather +name: Weather forecast +messages: + - Describe today's forecast. diff --git a/examples/consumers/testdata/prompt-catalog/prompts/generated-welcome.yml b/examples/consumers/testdata/prompt-catalog/prompts/generated-welcome.yml new file mode 100644 index 0000000..c6d0851 --- /dev/null +++ b/examples/consumers/testdata/prompt-catalog/prompts/generated-welcome.yml @@ -0,0 +1,4 @@ +id: welcome +name: Welcome +messages: + - Welcome the user.