diff --git a/docs/config.md b/docs/config.md index 9430cccb..b5f172a3 100644 --- a/docs/config.md +++ b/docs/config.md @@ -36,7 +36,8 @@ have no effect; `NOTARIUS_CONFIG` remains a source-discovery input. - [Complete D&D configuration](../examples/dnd-complete.config.yml) uses ordered steps, all implemented D&D lanes, generated references, state settings, bounded LLM concurrency, and the maintained - [operator profile](../examples/profiles/dnd-extraction.yml). + [LLM profile](../examples/llm-profiles/dnd-extraction.yml) and imports its + pipeline from [a fragment](../examples/pipelines/dnd-session.yml). Use these complete files as starting points rather than combining the illustrative fragments in this reference. @@ -116,7 +117,7 @@ promptkit: Set at most one of **profile_dir** and **profile_file**. Every nonempty relative configured filesystem path is resolved from the canonical directory of the file that supplies it. The complete example's -`./profiles/dnd-extraction.yml` value therefore resolves beside that example. +`./llm-profiles/dnd-extraction.yml` value therefore resolves beside that example. Use absolute paths for services and containers when their deployment layout is not configuration-relative. @@ -124,7 +125,7 @@ An operator source is optional. For a requested ID, PromptKit checks the configured operator source first, then Notarius's embedded fallback profiles, then its own built-in catalog. A matching profile is complete: it replaces a lower-precedence definition rather than merging with it. The maintained -[`dnd-extraction` operator profile](../examples/profiles/dnd-extraction.yml) +[`dnd-extraction` LLM profile](../examples/llm-profiles/dnd-extraction.yml) is a secret-free deployment artifact; production, development, and local deployments can each provide a complete definition with that same workload ID. Use workload-oriented IDs for new profiles instead of model names. diff --git a/docs/operations.md b/docs/operations.md index 12014b8e..404bc98a 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -115,7 +115,7 @@ precedence rules are owned by [Configuration](config.md#promptkit-profiles). Use a profile source owned by the service account, keep it readable only by the intended operator, and supply provider credentials through the service environment—not in the Notarius configuration or profile YAML. The maintained -[operator profile](../examples/profiles/dnd-extraction.yml) is secret-free and +[LLM profile](../examples/llm-profiles/dnd-extraction.yml) is secret-free and can be copied as a format starting point. Validate a deployment without a provider call or credentials: @@ -128,7 +128,7 @@ may receive a 401 or 403 response. Configured PromptKit profile paths resolve from the file that supplies their surviving declaration. The complete example's -`./profiles/dnd-extraction.yml` path is therefore relative to that example. +`./llm-profiles/dnd-extraction.yml` path is therefore relative to that example. Use absolute paths such as `/etc/notarius/profiles/dnd-extraction.yml` for services and containers when that is clearer for the deployment. diff --git a/docs/roadmap/implementation.md b/docs/roadmap/implementation.md index 6c465a60..53cb0df5 100644 --- a/docs/roadmap/implementation.md +++ b/docs/roadmap/implementation.md @@ -607,6 +607,8 @@ have moved. ## Stage 13 — Demonstrate Imports And Development Profiles +**Status:** Completed 2026-09-13. + **Goal:** Supply two maintained operator examples covering simple and composed configuration, with a clear distinction between the two profile systems. diff --git a/examples/dnd-complete.config.yml b/examples/dnd-complete.config.yml index f0160f14..9d0ddc7e 100644 --- a/examples/dnd-complete.config.yml +++ b/examples/dnd-complete.config.yml @@ -1,6 +1,9 @@ version: 5 +configkit: + imports: + - path: pipelines/dnd-session.yml promptkit: - profile_file: ./profiles/dnd-extraction.yml + profile_file: ./llm-profiles/dnd-extraction.yml concurrency: total_llm: 2 stage_workers: @@ -16,167 +19,3 @@ cache: directory: ./notarius-cache/checkpoints debug: directory: ./notarius-debug -pipelines: - dnd-session: - llm_profile: dnd-extraction - input: - module: seriatim - # Stable campaign context is shared by every module that accepts these slots. - references: - party: - path: ./dnd-party.txt - glossary: - path: ./dnd-glossary.txt - chunk: - module: dnd/scenes - retries: 2 - output: - module: json - options: - include_chunk_map: true - evidence_context: - enabled: true - window_units: 3 - lanes: - - item-occurrences - - item-registry - - location-registry - - location-occurrences - - npc-registry - - spells - - combat-turns - - npc-occurrences - - enemy-events - steps: - # Establish session-wide reference artifacts before their consumers. - - id: describe-session - artifacts: - item-registry: - extract: - module: dnd/item-registry - retries: 2 - merge: - module: appendorder - normalize: - module: dnd/item-registry - npc-registry: - extract: - module: dnd/npc-registry - retries: 2 - merge: - module: appendorder - normalize: - module: dnd/npc-registry - retries: 2 - location-registry: - extract: - module: dnd/location-registry - retries: 2 - merge: - module: appendorder - normalize: - module: dnd/location-registry - retries: 2 - scene-descriptions: - extract: - module: dnd/scene-descriptions - retries: 2 - merge: - module: appendorder - normalize: - module: dnd/scene-descriptions - - id: extract-events - # Accepted registry artifacts and scene-description eligibility artifacts - # are supplied in memory to their compatible consumers in this step. - references: - location_registry: - artifact: - step: describe-session - lane: location-registry - npc_registry: - artifact: - step: describe-session - lane: npc-registry - scene_descriptions: - artifact: - step: describe-session - lane: scene-descriptions - item_registry: - artifact: - step: describe-session - lane: item-registry - artifacts: - item-occurrences: - extract: - module: dnd/item-occurrences - retries: 2 - merge: - module: appendorder - normalize: - module: dnd/item-occurrences - spells: - extract: - module: dnd/spells - retries: 2 - references: - spell_catalog: - path: ./dnd-spell-catalog.json - merge: - module: appendorder - # Stage-local file references are intentionally bound at each stage. - normalize: - module: dnd/spells - references: - spell_catalog: - path: ./dnd-spell-catalog.json - combat-turns: - extract: - module: dnd/combat-turns - retries: 2 - merge: - module: appendorder - normalize: - module: dnd/combat-turns - npc-occurrences: - extract: - module: dnd/npc-occurrences - retries: 2 - merge: - module: appendorder - normalize: - module: dnd/npc-occurrences - location-occurrences: - extract: - module: dnd/location-occurrences - retries: 2 - merge: - module: appendorder - normalize: - module: dnd/location-occurrences - - id: track-enemies - references: - npc_registry: - artifact: - step: describe-session - lane: npc-registry - scene_descriptions: - artifact: - step: describe-session - lane: scene-descriptions - combat_turns: - artifact: - step: extract-events - lane: combat-turns - npc_occurrences: - artifact: - step: extract-events - lane: npc-occurrences - artifacts: - enemy-events: - extract: - module: dnd/enemy-events - retries: 2 - merge: - module: appendorder - normalize: - module: dnd/enemy-events diff --git a/examples/profiles/dnd-extraction.yml b/examples/llm-profiles/dnd-extraction.yml similarity index 100% rename from examples/profiles/dnd-extraction.yml rename to examples/llm-profiles/dnd-extraction.yml diff --git a/examples/pipelines/dnd-session.yml b/examples/pipelines/dnd-session.yml new file mode 100644 index 00000000..5b82c910 --- /dev/null +++ b/examples/pipelines/dnd-session.yml @@ -0,0 +1,164 @@ +pipelines: + dnd-session: + llm_profile: dnd-extraction + input: + module: seriatim + # Stable campaign context is shared by every module that accepts these slots. + references: + party: + path: ../dnd-party.txt + glossary: + path: ../dnd-glossary.txt + chunk: + module: dnd/scenes + retries: 2 + output: + module: json + options: + include_chunk_map: true + evidence_context: + enabled: true + window_units: 3 + lanes: + - item-occurrences + - item-registry + - location-registry + - location-occurrences + - npc-registry + - spells + - combat-turns + - npc-occurrences + - enemy-events + steps: + # Establish session-wide reference artifacts before their consumers. + - id: describe-session + artifacts: + item-registry: + extract: + module: dnd/item-registry + retries: 2 + merge: + module: appendorder + normalize: + module: dnd/item-registry + npc-registry: + extract: + module: dnd/npc-registry + retries: 2 + merge: + module: appendorder + normalize: + module: dnd/npc-registry + retries: 2 + location-registry: + extract: + module: dnd/location-registry + retries: 2 + merge: + module: appendorder + normalize: + module: dnd/location-registry + retries: 2 + scene-descriptions: + extract: + module: dnd/scene-descriptions + retries: 2 + merge: + module: appendorder + normalize: + module: dnd/scene-descriptions + - id: extract-events + # Accepted registry artifacts and scene-description eligibility artifacts + # are supplied in memory to their compatible consumers in this step. + references: + location_registry: + artifact: + step: describe-session + lane: location-registry + npc_registry: + artifact: + step: describe-session + lane: npc-registry + scene_descriptions: + artifact: + step: describe-session + lane: scene-descriptions + item_registry: + artifact: + step: describe-session + lane: item-registry + artifacts: + item-occurrences: + extract: + module: dnd/item-occurrences + retries: 2 + merge: + module: appendorder + normalize: + module: dnd/item-occurrences + spells: + extract: + module: dnd/spells + retries: 2 + references: + spell_catalog: + path: ../dnd-spell-catalog.json + merge: + module: appendorder + # Stage-local file references are intentionally bound at each stage. + normalize: + module: dnd/spells + references: + spell_catalog: + path: ../dnd-spell-catalog.json + combat-turns: + extract: + module: dnd/combat-turns + retries: 2 + merge: + module: appendorder + normalize: + module: dnd/combat-turns + npc-occurrences: + extract: + module: dnd/npc-occurrences + retries: 2 + merge: + module: appendorder + normalize: + module: dnd/npc-occurrences + location-occurrences: + extract: + module: dnd/location-occurrences + retries: 2 + merge: + module: appendorder + normalize: + module: dnd/location-occurrences + - id: track-enemies + references: + npc_registry: + artifact: + step: describe-session + lane: npc-registry + scene_descriptions: + artifact: + step: describe-session + lane: scene-descriptions + combat_turns: + artifact: + step: extract-events + lane: combat-turns + npc_occurrences: + artifact: + step: extract-events + lane: npc-occurrences + artifacts: + enemy-events: + extract: + module: dnd/enemy-events + retries: 2 + merge: + module: appendorder + normalize: + module: dnd/enemy-events diff --git a/examples/profiles/development.yml b/examples/profiles/development.yml new file mode 100644 index 00000000..c218f755 --- /dev/null +++ b/examples/profiles/development.yml @@ -0,0 +1,8 @@ +# This selects operational settings only; choose a different LLM profile with +# the pipeline's llm_profile field or the run command's --llm-profile flag. +concurrency: + total_llm: 1 + stage_workers: + extract: 1 +output: + directory: ./notarius-output-development diff --git a/internal/cli/dnd_enemy_events_contract_test.go b/internal/cli/dnd_enemy_events_contract_test.go index bfe2835b..0fc3f4ae 100644 --- a/internal/cli/dnd_enemy_events_contract_test.go +++ b/internal/cli/dnd_enemy_events_contract_test.go @@ -264,14 +264,29 @@ func completeExampleConfigWithTemporaryCache(t *testing.T) string { updated := strings.Replace(string(content), "directory: ./notarius-cache/chunk-plans", fmt.Sprintf("directory: %q", filepath.Join(cacheRoot, "chunk-plans")), 1) updated = strings.Replace(updated, "directory: ./notarius-cache/checkpoints", fmt.Sprintf("directory: %q", filepath.Join(cacheRoot, "checkpoints")), 1) for relative, absolute := range map[string]string{ - "./dnd-party.txt": repositoryPath("examples", "dnd-party.txt"), - "./dnd-glossary.txt": repositoryPath("examples", "dnd-glossary.txt"), - "./dnd-spell-catalog.json": repositoryPath("examples", "dnd-spell-catalog.json"), - "./profiles/dnd-extraction.yml": repositoryPath("examples", "profiles", "dnd-extraction.yml"), + "./llm-profiles/dnd-extraction.yml": repositoryPath("examples", "llm-profiles", "dnd-extraction.yml"), } { updated = strings.ReplaceAll(updated, relative, fmt.Sprintf("%q", absolute)) } - path := filepath.Join(t.TempDir(), "dnd-complete.config.yml") + root := t.TempDir() + fragment, err := os.ReadFile(repositoryPath("examples", "pipelines", "dnd-session.yml")) + if err != nil { + t.Fatal(err) + } + for relative, absolute := range map[string]string{ + "../dnd-party.txt": repositoryPath("examples", "dnd-party.txt"), + "../dnd-glossary.txt": repositoryPath("examples", "dnd-glossary.txt"), + "../dnd-spell-catalog.json": repositoryPath("examples", "dnd-spell-catalog.json"), + } { + fragment = []byte(strings.ReplaceAll(string(fragment), relative, fmt.Sprintf("%q", absolute))) + } + if err := os.MkdirAll(filepath.Join(root, "pipelines"), 0o700); err != nil { + t.Fatal(err) + } + if err := os.WriteFile(filepath.Join(root, "pipelines", "dnd-session.yml"), fragment, 0o600); err != nil { + t.Fatal(err) + } + path := filepath.Join(root, "dnd-complete.config.yml") if err := os.WriteFile(path, []byte(updated), 0o600); err != nil { t.Fatal(err) } diff --git a/internal/cli/example_contract_test.go b/internal/cli/example_contract_test.go index a6e68a8c..eeeaa0f3 100644 --- a/internal/cli/example_contract_test.go +++ b/internal/cli/example_contract_test.go @@ -147,8 +147,15 @@ func TestMaintainedConfigurationExampleSet(t *testing.T) { } } sort.Strings(names) - if got := strings.Join(names, ","); got != "dnd-extraction.yml" { - t.Fatalf("maintained operator profiles = %q, want dnd-extraction.yml", got) + if got := strings.Join(names, ","); got != "development.yml" { + t.Fatalf("maintained configuration profiles = %q, want development.yml", got) + } + llmProfiles, err := os.ReadDir(repositoryPath("examples", "llm-profiles")) + if err != nil { + t.Fatal(err) + } + if len(llmProfiles) != 1 || llmProfiles[0].Name() != "dnd-extraction.yml" { + t.Fatalf("maintained LLM profiles = %#v, want dnd-extraction.yml", llmProfiles) } }