Migrate repo fixtures to separated prompts/ and execution profiles/ with file-backed prompt templates

This commit is contained in:
2026-05-05 10:58:22 -05:00
parent 6142bd88ee
commit d82bcd0581
14 changed files with 77 additions and 57 deletions

View File

@@ -51,13 +51,14 @@ go test ./...
Required flags: Required flags:
- `--prompt-dir`
- `--profile-dir` - `--profile-dir`
- `--prompt-id` - `--prompt`
- `--input` (repeatable `name=path`) - `--input` (repeatable `name=path`)
Common optional flags: 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`) - `--var` (repeatable `name=value`)
- `--out` - `--out`
- `--llm-base-url` - `--llm-base-url`
@@ -76,9 +77,10 @@ Example:
export SCRIPTORIUM_API_KEY="your-key" export SCRIPTORIUM_API_KEY="your-key"
go run ./cmd/scriptorium run \ go run ./cmd/scriptorium run \
--prompt-dir ./prompts \
--profile-dir ./profiles \ --profile-dir ./profiles \
--prompt-id generic.markdown_summary \ --prompt generic.markdown_summary \
--profile-id local-default \ --profile local-fast \
--input transcript=./examples/fixtures/transcript.md \ --input transcript=./examples/fixtures/transcript.md \
--input glossary=./examples/fixtures/glossary.yml \ --input glossary=./examples/fixtures/glossary.yml \
--llm-base-url http://localhost:8000/v1 \ --llm-base-url http://localhost:8000/v1 \
@@ -99,8 +101,8 @@ Starts HTTP API.
Required flags: Required flags:
- `--prompt-dir`
- `--profile-dir` - `--profile-dir`
- `--llm-base-url`
Common optional flags: Common optional flags:
@@ -267,7 +269,8 @@ Validation content failures are returned in the structured result; raw model out
## Examples ## Examples
- Prompt definitions: `profiles/` - Prompt definitions: `prompts/`
- Execution profiles: `profiles/`
- Schemas: `schemas/` - Schemas: `schemas/`
- Fixtures: `examples/fixtures/` - Fixtures: `examples/fixtures/`
- Local experimentation: `local-test/` - Local experimentation: `local-test/`

View File

@@ -209,7 +209,7 @@ func TestRunCommandVarsOptional(t *testing.T) {
var stderr bytes.Buffer var stderr bytes.Buffer
code := runCommand([]string{ code := runCommand([]string{
"--prompt-dir", "./profiles", "--prompt-dir", "./prompts",
"--profile-dir", "./profiles", "--profile-dir", "./profiles",
"--prompt", "p", "--prompt", "p",
"--input", "transcript=./t.md", "--input", "transcript=./t.md",

View File

@@ -2,7 +2,6 @@ package usecase
import ( import (
"context" "context"
"os"
"path/filepath" "path/filepath"
"testing" "testing"
@@ -27,24 +26,21 @@ func (f *integrationLLM) Generate(ctx context.Context, req domain.GenerateReques
}, nil }, nil
} }
func TestRunnerIntegrationWithProfilesFixturesAndValidation(t *testing.T) { func TestRunnerIntegrationWithPromptAndProfileFixturesAndValidation(t *testing.T) {
root, err := filepath.Abs(filepath.Join("..", "..")) root, err := filepath.Abs(filepath.Join("..", ".."))
if err != nil { if err != nil {
t.Fatalf("failed to resolve repo root: %v", err) t.Fatalf("failed to resolve repo root: %v", err)
} }
promptsDir := filepath.Join(root, "prompts")
profilesDir := filepath.Join(root, "profiles") profilesDir := filepath.Join(root, "profiles")
execProfilesDir := t.TempDir()
schemasDir := filepath.Join(root, "schemas") schemasDir := filepath.Join(root, "schemas")
fixturesDir := filepath.Join(root, "examples", "fixtures") fixturesDir := filepath.Join(root, "examples", "fixtures")
if err := os.WriteFile(filepath.Join(execProfilesDir, "local-default.yaml"), []byte( t.Setenv("SCRIPTORIUM_API_KEY", "test-key")
"id: local-default\nendpoint: http://llm/v1\nmodel: test-model\n"), 0644); err != nil {
t.Fatalf("failed to write execution profile fixture: %v", err)
}
runner := NewRunner( runner := NewRunner(
promptdef.NewFilesystemRepository(profilesDir), promptdef.NewFilesystemRepository(promptsDir),
profile.NewFilesystemRepository(execProfilesDir), profile.NewFilesystemRepository(profilesDir),
artifact.NewCompositeReader(), artifact.NewCompositeReader(),
prompt.NewGoRenderer(), prompt.NewGoRenderer(),
&integrationLLM{}, &integrationLLM{},
@@ -52,8 +48,7 @@ func TestRunnerIntegrationWithProfilesFixturesAndValidation(t *testing.T) {
) )
res, err := runner.Run(context.Background(), domain.RunRequest{ res, err := runner.Run(context.Background(), domain.RunRequest{
PromptID: "generic.structured_events", PromptID: "generic.structured_events",
ProfileID: "local-default",
Inputs: map[string]domain.ArtifactRef{ Inputs: map[string]domain.ArtifactRef{
"transcript": { "transcript": {
Type: domain.ArtifactRefFile, Type: domain.ArtifactRefFile,
@@ -72,6 +67,9 @@ func TestRunnerIntegrationWithProfilesFixturesAndValidation(t *testing.T) {
if res.PromptID != "generic.structured_events" { if res.PromptID != "generic.structured_events" {
t.Fatalf("unexpected prompt id: %q", res.PromptID) 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 == "" { if res.RunID == "" {
t.Fatal("expected run id") t.Fatal("expected run id")
} }

7
profiles/local-fast.yaml Normal file
View File

@@ -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

View File

@@ -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

View File

@@ -0,0 +1,2 @@
You create concise tabletop RPG session recaps.
Stay factual and avoid inventing events.

View File

@@ -0,0 +1,10 @@
Produce a recap with these sections:
- Session Highlights
- Open Threads
- NPC Mentions
Transcript:
{{input "transcript"}}
Glossary:
{{input "glossary"}}

View File

@@ -1,31 +1,21 @@
id: dnd.session_recap id: dnd.session_recap
version: "1.0.0" version: "1.0.0"
default_profile: local-default default_profile: local-quality
description: Example D&D session recap prompt definition for demonstration only. description: Example D&D session recap prompt definition for demonstration only.
inputs: inputs:
- name: transcript - name: transcript
required: true required: true
content_type: text/markdown content_type: text/markdown
description: Session source content
- name: glossary - name: glossary
required: false required: false
content_type: text/yaml content_type: text/yaml
description: Optional glossary context
messages: messages:
- role: system - role: system
content: | content_file: ./dnd.session_recap.system.md
You create concise tabletop RPG session recaps.
Stay factual and avoid inventing events.
- role: user - role: user
content: | content_file: ./dnd.session_recap.user.md
Produce a recap with these sections:
- Session Highlights
- Open Threads
- NPC Mentions
Transcript:
{{input "transcript"}}
Glossary:
{{input "glossary"}}
output: output:
format: markdown format: markdown
validation_mode: basic validation_mode: basic

View File

@@ -0,0 +1,2 @@
You are a concise analysis assistant.
Write clear Markdown output.

View File

@@ -0,0 +1,7 @@
Summarize the following source transcript:
{{input "transcript"}}
Reference glossary:
{{input "glossary"}}

View File

@@ -1,6 +1,6 @@
id: generic.markdown_summary id: generic.markdown_summary
version: "1.0.0" version: "1.0.0"
default_profile: local-default default_profile: local-fast
description: Generic markdown summary from transcript and glossary. description: Generic markdown summary from transcript and glossary.
inputs: inputs:
- name: transcript - name: transcript
@@ -13,18 +13,9 @@ inputs:
description: Optional glossary context description: Optional glossary context
messages: messages:
- role: system - role: system
content: | content_file: ./generic.markdown_summary.system.md
You are a concise analysis assistant.
Write clear Markdown output.
- role: user - role: user
content: | content_file: ./generic.markdown_summary.user.md
Summarize the following source transcript:
{{input "transcript"}}
Reference glossary:
{{input "glossary"}}
output: output:
format: markdown format: markdown
validation_mode: basic validation_mode: basic

View File

@@ -0,0 +1,2 @@
Return only JSON following the requested schema.
Do not include commentary.

View File

@@ -0,0 +1,7 @@
Extract important events from the transcript and emit JSON.
Transcript:
{{input "transcript"}}
Glossary:
{{input "glossary"}}

View File

@@ -1,28 +1,21 @@
id: generic.structured_events id: generic.structured_events
version: "1.0.0" version: "1.0.0"
default_profile: local-default default_profile: local-quality
description: Produce structured event JSON from a transcript. description: Produce structured event JSON from a transcript.
inputs: inputs:
- name: transcript - name: transcript
required: true required: true
content_type: text/markdown content_type: text/markdown
description: Source transcript content
- name: glossary - name: glossary
required: false required: false
content_type: text/yaml content_type: text/yaml
description: Optional glossary context
messages: messages:
- role: system - role: system
content: | content_file: ./generic.structured_events.system.md
Return only JSON following the requested schema.
Do not include commentary.
- role: user - role: user
content: | content_file: ./generic.structured_events.user.md
Extract important events from the transcript and emit JSON.
Transcript:
{{input "transcript"}}
Glossary:
{{input "glossary"}}
output: output:
format: json format: json
validation_mode: json_schema validation_mode: json_schema