From d82bcd05817d4a7e79c38ec5ce8965f24ef3d98e Mon Sep 17 00:00:00 2001 From: Eric Rakestraw Date: Tue, 5 May 2026 10:58:22 -0500 Subject: [PATCH] Migrate repo fixtures to separated prompts/ and execution profiles/ with file-backed prompt templates --- README.md | 15 ++++++++------ internal/adapter/cli/run_test.go | 2 +- internal/usecase/integration_test.go | 20 +++++++++---------- profiles/local-fast.yaml | 7 +++++++ profiles/local-quality.yaml | 8 ++++++++ prompts/dnd.session_recap.system.md | 2 ++ prompts/dnd.session_recap.user.md | 10 ++++++++++ {profiles => prompts}/dnd.session_recap.yaml | 20 +++++-------------- prompts/generic.markdown_summary.system.md | 2 ++ prompts/generic.markdown_summary.user.md | 7 +++++++ .../generic.markdown_summary.yaml | 15 +++----------- prompts/generic.structured_events.system.md | 2 ++ prompts/generic.structured_events.user.md | 7 +++++++ .../generic.structured_events.yaml | 17 +++++----------- 14 files changed, 77 insertions(+), 57 deletions(-) create mode 100644 profiles/local-fast.yaml create mode 100644 profiles/local-quality.yaml create mode 100644 prompts/dnd.session_recap.system.md create mode 100644 prompts/dnd.session_recap.user.md rename {profiles => prompts}/dnd.session_recap.yaml (51%) create mode 100644 prompts/generic.markdown_summary.system.md create mode 100644 prompts/generic.markdown_summary.user.md rename {profiles => prompts}/generic.markdown_summary.yaml (62%) create mode 100644 prompts/generic.structured_events.system.md create mode 100644 prompts/generic.structured_events.user.md rename {profiles => prompts}/generic.structured_events.yaml (57%) diff --git a/README.md b/README.md index 2157750..f3ee700 100644 --- a/README.md +++ b/README.md @@ -51,13 +51,14 @@ go test ./... Required flags: +- `--prompt-dir` - `--profile-dir` -- `--prompt-id` +- `--prompt` - `--input` (repeatable `name=path`) Common optional flags: -- `--profile-id` (execution profile selector; falls back to prompt `default_profile`) +- `--profile` (execution profile selector; falls back to prompt `default_profile`) - `--var` (repeatable `name=value`) - `--out` - `--llm-base-url` @@ -76,9 +77,10 @@ Example: export SCRIPTORIUM_API_KEY="your-key" go run ./cmd/scriptorium run \ + --prompt-dir ./prompts \ --profile-dir ./profiles \ - --prompt-id generic.markdown_summary \ - --profile-id local-default \ + --prompt generic.markdown_summary \ + --profile local-fast \ --input transcript=./examples/fixtures/transcript.md \ --input glossary=./examples/fixtures/glossary.yml \ --llm-base-url http://localhost:8000/v1 \ @@ -99,8 +101,8 @@ Starts HTTP API. Required flags: +- `--prompt-dir` - `--profile-dir` -- `--llm-base-url` Common optional flags: @@ -267,7 +269,8 @@ Validation content failures are returned in the structured result; raw model out ## Examples -- Prompt definitions: `profiles/` +- Prompt definitions: `prompts/` +- Execution profiles: `profiles/` - Schemas: `schemas/` - Fixtures: `examples/fixtures/` - Local experimentation: `local-test/` diff --git a/internal/adapter/cli/run_test.go b/internal/adapter/cli/run_test.go index 8c22281..65c78e0 100644 --- a/internal/adapter/cli/run_test.go +++ b/internal/adapter/cli/run_test.go @@ -209,7 +209,7 @@ func TestRunCommandVarsOptional(t *testing.T) { var stderr bytes.Buffer code := runCommand([]string{ - "--prompt-dir", "./profiles", + "--prompt-dir", "./prompts", "--profile-dir", "./profiles", "--prompt", "p", "--input", "transcript=./t.md", diff --git a/internal/usecase/integration_test.go b/internal/usecase/integration_test.go index 91855d2..9249157 100644 --- a/internal/usecase/integration_test.go +++ b/internal/usecase/integration_test.go @@ -2,7 +2,6 @@ package usecase import ( "context" - "os" "path/filepath" "testing" @@ -27,24 +26,21 @@ func (f *integrationLLM) Generate(ctx context.Context, req domain.GenerateReques }, nil } -func TestRunnerIntegrationWithProfilesFixturesAndValidation(t *testing.T) { +func TestRunnerIntegrationWithPromptAndProfileFixturesAndValidation(t *testing.T) { root, err := filepath.Abs(filepath.Join("..", "..")) if err != nil { t.Fatalf("failed to resolve repo root: %v", err) } + promptsDir := filepath.Join(root, "prompts") profilesDir := filepath.Join(root, "profiles") - execProfilesDir := t.TempDir() schemasDir := filepath.Join(root, "schemas") fixturesDir := filepath.Join(root, "examples", "fixtures") - if err := os.WriteFile(filepath.Join(execProfilesDir, "local-default.yaml"), []byte( - "id: local-default\nendpoint: http://llm/v1\nmodel: test-model\n"), 0644); err != nil { - t.Fatalf("failed to write execution profile fixture: %v", err) - } + t.Setenv("SCRIPTORIUM_API_KEY", "test-key") runner := NewRunner( - promptdef.NewFilesystemRepository(profilesDir), - profile.NewFilesystemRepository(execProfilesDir), + promptdef.NewFilesystemRepository(promptsDir), + profile.NewFilesystemRepository(profilesDir), artifact.NewCompositeReader(), prompt.NewGoRenderer(), &integrationLLM{}, @@ -52,8 +48,7 @@ func TestRunnerIntegrationWithProfilesFixturesAndValidation(t *testing.T) { ) res, err := runner.Run(context.Background(), domain.RunRequest{ - PromptID: "generic.structured_events", - ProfileID: "local-default", + PromptID: "generic.structured_events", Inputs: map[string]domain.ArtifactRef{ "transcript": { Type: domain.ArtifactRefFile, @@ -72,6 +67,9 @@ func TestRunnerIntegrationWithProfilesFixturesAndValidation(t *testing.T) { if res.PromptID != "generic.structured_events" { t.Fatalf("unexpected prompt id: %q", res.PromptID) } + if res.SelectedProfileID != "local-quality" { + t.Fatalf("expected selected profile local-quality from prompt default, got %q", res.SelectedProfileID) + } if res.RunID == "" { t.Fatal("expected run id") } diff --git a/profiles/local-fast.yaml b/profiles/local-fast.yaml new file mode 100644 index 0000000..80aeb45 --- /dev/null +++ b/profiles/local-fast.yaml @@ -0,0 +1,7 @@ +id: local-fast +endpoint: http://localhost:8000/v1 +model: gpt-4o-mini +temperature: 0.2 +max_tokens: 500 +top_p: 1.0 +timeout_seconds: 90 diff --git a/profiles/local-quality.yaml b/profiles/local-quality.yaml new file mode 100644 index 0000000..d3e70ff --- /dev/null +++ b/profiles/local-quality.yaml @@ -0,0 +1,8 @@ +id: local-quality +endpoint: http://localhost:8000/v1 +model: gpt-4.1 +temperature: 0.0 +max_tokens: 1200 +top_p: 1.0 +timeout_seconds: 180 +api_key_env: SCRIPTORIUM_API_KEY diff --git a/prompts/dnd.session_recap.system.md b/prompts/dnd.session_recap.system.md new file mode 100644 index 0000000..7a9f6ab --- /dev/null +++ b/prompts/dnd.session_recap.system.md @@ -0,0 +1,2 @@ +You create concise tabletop RPG session recaps. +Stay factual and avoid inventing events. diff --git a/prompts/dnd.session_recap.user.md b/prompts/dnd.session_recap.user.md new file mode 100644 index 0000000..c2a14aa --- /dev/null +++ b/prompts/dnd.session_recap.user.md @@ -0,0 +1,10 @@ +Produce a recap with these sections: +- Session Highlights +- Open Threads +- NPC Mentions + +Transcript: +{{input "transcript"}} + +Glossary: +{{input "glossary"}} diff --git a/profiles/dnd.session_recap.yaml b/prompts/dnd.session_recap.yaml similarity index 51% rename from profiles/dnd.session_recap.yaml rename to prompts/dnd.session_recap.yaml index f0ab2ae..ede6e14 100644 --- a/profiles/dnd.session_recap.yaml +++ b/prompts/dnd.session_recap.yaml @@ -1,31 +1,21 @@ id: dnd.session_recap version: "1.0.0" -default_profile: local-default +default_profile: local-quality description: Example D&D session recap prompt definition for demonstration only. inputs: - name: transcript required: true content_type: text/markdown + description: Session source content - name: glossary required: false content_type: text/yaml + description: Optional glossary context messages: - role: system - content: | - You create concise tabletop RPG session recaps. - Stay factual and avoid inventing events. + content_file: ./dnd.session_recap.system.md - role: user - content: | - Produce a recap with these sections: - - Session Highlights - - Open Threads - - NPC Mentions - - Transcript: - {{input "transcript"}} - - Glossary: - {{input "glossary"}} + content_file: ./dnd.session_recap.user.md output: format: markdown validation_mode: basic diff --git a/prompts/generic.markdown_summary.system.md b/prompts/generic.markdown_summary.system.md new file mode 100644 index 0000000..19304ef --- /dev/null +++ b/prompts/generic.markdown_summary.system.md @@ -0,0 +1,2 @@ +You are a concise analysis assistant. +Write clear Markdown output. diff --git a/prompts/generic.markdown_summary.user.md b/prompts/generic.markdown_summary.user.md new file mode 100644 index 0000000..bba6097 --- /dev/null +++ b/prompts/generic.markdown_summary.user.md @@ -0,0 +1,7 @@ +Summarize the following source transcript: + +{{input "transcript"}} + +Reference glossary: + +{{input "glossary"}} diff --git a/profiles/generic.markdown_summary.yaml b/prompts/generic.markdown_summary.yaml similarity index 62% rename from profiles/generic.markdown_summary.yaml rename to prompts/generic.markdown_summary.yaml index 0f33bd6..be95e53 100644 --- a/profiles/generic.markdown_summary.yaml +++ b/prompts/generic.markdown_summary.yaml @@ -1,6 +1,6 @@ id: generic.markdown_summary version: "1.0.0" -default_profile: local-default +default_profile: local-fast description: Generic markdown summary from transcript and glossary. inputs: - name: transcript @@ -13,18 +13,9 @@ inputs: description: Optional glossary context messages: - role: system - content: | - You are a concise analysis assistant. - Write clear Markdown output. + content_file: ./generic.markdown_summary.system.md - role: user - content: | - Summarize the following source transcript: - - {{input "transcript"}} - - Reference glossary: - - {{input "glossary"}} + content_file: ./generic.markdown_summary.user.md output: format: markdown validation_mode: basic diff --git a/prompts/generic.structured_events.system.md b/prompts/generic.structured_events.system.md new file mode 100644 index 0000000..374c397 --- /dev/null +++ b/prompts/generic.structured_events.system.md @@ -0,0 +1,2 @@ +Return only JSON following the requested schema. +Do not include commentary. diff --git a/prompts/generic.structured_events.user.md b/prompts/generic.structured_events.user.md new file mode 100644 index 0000000..e59e119 --- /dev/null +++ b/prompts/generic.structured_events.user.md @@ -0,0 +1,7 @@ +Extract important events from the transcript and emit JSON. + +Transcript: +{{input "transcript"}} + +Glossary: +{{input "glossary"}} diff --git a/profiles/generic.structured_events.yaml b/prompts/generic.structured_events.yaml similarity index 57% rename from profiles/generic.structured_events.yaml rename to prompts/generic.structured_events.yaml index 0edb918..213c32b 100644 --- a/profiles/generic.structured_events.yaml +++ b/prompts/generic.structured_events.yaml @@ -1,28 +1,21 @@ id: generic.structured_events version: "1.0.0" -default_profile: local-default +default_profile: local-quality description: Produce structured event JSON from a transcript. inputs: - name: transcript required: true content_type: text/markdown + description: Source transcript content - name: glossary required: false content_type: text/yaml + description: Optional glossary context messages: - role: system - content: | - Return only JSON following the requested schema. - Do not include commentary. + content_file: ./generic.structured_events.system.md - role: user - content: | - Extract important events from the transcript and emit JSON. - - Transcript: - {{input "transcript"}} - - Glossary: - {{input "glossary"}} + content_file: ./generic.structured_events.user.md output: format: json validation_mode: json_schema