Compare commits
4 Commits
5edb24a9c1
...
8703793b0c
| Author | SHA1 | Date | |
|---|---|---|---|
| 8703793b0c | |||
| 4cb4943a57 | |||
| c6c747e94d | |||
| 2bbf13e739 |
@@ -2,7 +2,8 @@
|
||||
|
||||
## Status
|
||||
|
||||
Ready for implementation. No implementation work described here has started.
|
||||
Completed on 2026-07-27. The framework characterization baseline is complete,
|
||||
and Migration Step 4 is the next planned work.
|
||||
|
||||
## Objective
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
## Status
|
||||
|
||||
Accepted plan. Steps 1 and 2 are complete. Steps 3 through 9 remain proposed
|
||||
and are not yet implemented.
|
||||
Accepted plan. Steps 1 through 3 are complete. Steps 4 through 9 remain
|
||||
proposed and are not yet implemented.
|
||||
|
||||
## Objective
|
||||
|
||||
@@ -145,6 +145,11 @@ Preserve coverage of:
|
||||
**Gate:** Current framework and adapter contracts are represented by passing
|
||||
tests sufficient to detect behavioral regressions during the split.
|
||||
|
||||
**Gate status:** Complete as of 2026-07-27. The framework contract corpus,
|
||||
public `Engine` characterization, ownership audit, full test and vet suites,
|
||||
temporary executable build, and maintained offline examples passed. Step 4 is
|
||||
next.
|
||||
|
||||
### Step 4: Make Scriptorium Adapters Consume The Public Facade
|
||||
|
||||
Within the current repository, refactor the CLI and HTTP adapters to use the
|
||||
|
||||
@@ -2,8 +2,9 @@
|
||||
|
||||
## Status
|
||||
|
||||
Accepted scope. Implementation has not started. The ordered execution plan is
|
||||
in [implementation.md](implementation.md).
|
||||
Completed on 2026-07-27. The target state below is characterized by the
|
||||
passing baseline; its ordered implementation record is in
|
||||
[implementation.md](implementation.md).
|
||||
|
||||
## Purpose
|
||||
|
||||
@@ -38,7 +39,7 @@ injected-client behavior, and reserved provider parameters.
|
||||
|
||||
## Target State
|
||||
|
||||
At completion:
|
||||
The completed baseline provides:
|
||||
|
||||
- tests destined for Promptkit use only Promptkit-destined testdata or
|
||||
fixtures generated within the test;
|
||||
@@ -165,13 +166,13 @@ Step 3 is complete when:
|
||||
- the full roadmap behavior list has a clear, non-duplicative test owner;
|
||||
- tests that require Step 4 rewrites are explicitly identified;
|
||||
- no production behavior or public API changed;
|
||||
- all validation in Stage 5 passes; and
|
||||
- all required validation passes; and
|
||||
- the main migration roadmap records the Step 3 gate as complete.
|
||||
|
||||
Migration Step 4 must not begin until these criteria are satisfied.
|
||||
|
||||
## Lifecycle
|
||||
|
||||
This is a temporary implementation roadmap. Once Step 3 is complete and its
|
||||
gate status is recorded in the main migration roadmap, this file may be removed;
|
||||
repository history retains the detailed implementation record.
|
||||
This completed implementation roadmap remains the concise characterization
|
||||
record for the migration. Repository history retains the detailed implementation
|
||||
record.
|
||||
|
||||
760
engine_test.go
760
engine_test.go
File diff suppressed because it is too large
Load Diff
@@ -1,127 +0,0 @@
|
||||
package usecase
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
|
||||
"gitea.maximumdirect.net/eric/scriptorium/internal/artifact"
|
||||
"gitea.maximumdirect.net/eric/scriptorium/internal/domain"
|
||||
"gitea.maximumdirect.net/eric/scriptorium/internal/profile"
|
||||
"gitea.maximumdirect.net/eric/scriptorium/internal/prompt"
|
||||
"gitea.maximumdirect.net/eric/scriptorium/internal/promptdef"
|
||||
"gitea.maximumdirect.net/eric/scriptorium/internal/validate"
|
||||
)
|
||||
|
||||
type integrationLLM struct{}
|
||||
|
||||
func (f *integrationLLM) Generate(ctx context.Context, req domain.GenerateRequest) (*domain.GenerateResponse, error) {
|
||||
lastIntegrationRequest = req
|
||||
return &domain.GenerateResponse{
|
||||
Content: `{"summary":"Party discovered a captive scout beneath the tower.","events":[{"title":"Scout found in cellar","type":"discovery","notes":"Scout requested rescue from goblin raiders."}]}`,
|
||||
Usage: domain.TokenUsage{
|
||||
PromptTokens: 42,
|
||||
CompletionTokens: 36,
|
||||
TotalTokens: 78,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
var lastIntegrationRequest domain.GenerateRequest
|
||||
|
||||
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, "examples", "prompts")
|
||||
profilesDir := filepath.Join(root, "examples", "profiles")
|
||||
schemasDir := filepath.Join(root, "examples", "schemas")
|
||||
fixturesDir := filepath.Join(root, "examples", "fixtures")
|
||||
t.Setenv("SCRIPTORIUM_API_KEY", "test-key")
|
||||
|
||||
runner := NewRunner(
|
||||
promptdef.NewFilesystemRepository(promptsDir),
|
||||
profile.NewFilesystemRepository(profilesDir),
|
||||
artifact.NewCompositeReader(),
|
||||
prompt.NewGoRenderer(),
|
||||
&integrationLLM{},
|
||||
validate.NewStandardValidator(schemasDir),
|
||||
)
|
||||
|
||||
res, err := runner.Run(context.Background(), domain.RunRequest{
|
||||
PromptID: "generic.structured_events",
|
||||
Inputs: map[string]domain.ArtifactRef{
|
||||
"transcript": {
|
||||
Type: domain.ArtifactRefFile,
|
||||
URI: filepath.Join(fixturesDir, "transcript.md"),
|
||||
},
|
||||
"glossary": {
|
||||
Type: domain.ArtifactRefFile,
|
||||
URI: filepath.Join(fixturesDir, "glossary.yml"),
|
||||
},
|
||||
},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("expected no error, got %v", err)
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
if res.PromptHash == "" {
|
||||
t.Fatal("expected prompt hash")
|
||||
}
|
||||
if res.PromptVersion != "1.0.0" {
|
||||
t.Fatalf("unexpected prompt version: %q", res.PromptVersion)
|
||||
}
|
||||
if res.Validation.Status != domain.ValidationPassed {
|
||||
t.Fatalf("expected passed validation, got %q", res.Validation.Status)
|
||||
}
|
||||
if res.Validation.Mode != domain.ValidationJSONSchema {
|
||||
t.Fatalf("expected json_schema mode, got %q", res.Validation.Mode)
|
||||
}
|
||||
if lastIntegrationRequest.StructuredOutput == nil {
|
||||
t.Fatal("expected provider-level structured output request for json_schema prompt")
|
||||
}
|
||||
if lastIntegrationRequest.StructuredOutput.Type != domain.StructuredOutputJSONSchema {
|
||||
t.Fatalf("expected structured output type json_schema, got %q", lastIntegrationRequest.StructuredOutput.Type)
|
||||
}
|
||||
if lastIntegrationRequest.StructuredOutput.JSONSchema == nil || lastIntegrationRequest.StructuredOutput.JSONSchema.Schema == nil {
|
||||
t.Fatalf("expected structured output json_schema payload, got %+v", lastIntegrationRequest.StructuredOutput.JSONSchema)
|
||||
}
|
||||
if res.Artifact.ContentType != "application/json" {
|
||||
t.Fatalf("expected application/json output, got %q", res.Artifact.ContentType)
|
||||
}
|
||||
if len(res.RawOutput) == 0 {
|
||||
t.Fatal("expected raw output to be preserved")
|
||||
}
|
||||
if res.PromptHash == "" {
|
||||
t.Fatal("expected non-empty prompt hash")
|
||||
}
|
||||
if len(res.InputHashes) != 2 {
|
||||
t.Fatalf("expected two input hashes, got %d", len(res.InputHashes))
|
||||
}
|
||||
if res.InputHashes["transcript"] == "" || res.InputHashes["glossary"] == "" {
|
||||
t.Fatalf("expected both input hashes to be set, got %#v", res.InputHashes)
|
||||
}
|
||||
if res.Usage.TotalTokens != 78 {
|
||||
t.Fatalf("expected usage from fake llm, got %+v", res.Usage)
|
||||
}
|
||||
if res.StartTime.IsZero() || res.EndTime.IsZero() {
|
||||
t.Fatal("expected start/end timestamps")
|
||||
}
|
||||
if res.EndTime.Before(res.StartTime) {
|
||||
t.Fatalf("expected end >= start, got start=%v end=%v", res.StartTime, res.EndTime)
|
||||
}
|
||||
if res.Duration < 0 {
|
||||
t.Fatalf("expected non-negative duration, got %s", res.Duration)
|
||||
}
|
||||
}
|
||||
2
testdata/framework/fixtures/glossary.yml
vendored
Normal file
2
testdata/framework/fixtures/glossary.yml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
archive: A catalogued collection of written records.
|
||||
marker: A small label used to classify an entry.
|
||||
2
testdata/framework/fixtures/transcript.md
vendored
Normal file
2
testdata/framework/fixtures/transcript.md
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
Nia labels the archive.
|
||||
The archive receives a blue marker.
|
||||
7
testdata/framework/profiles/contract-fast.yaml
vendored
Normal file
7
testdata/framework/profiles/contract-fast.yaml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
id: contract-fast
|
||||
endpoint: http://localhost:8000/v1
|
||||
model: contract-fast-model
|
||||
temperature: 0.2
|
||||
max_tokens: 500
|
||||
top_p: 1
|
||||
timeout_seconds: 90
|
||||
7
testdata/framework/profiles/contract-quality.yaml
vendored
Normal file
7
testdata/framework/profiles/contract-quality.yaml
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
id: contract-quality
|
||||
endpoint: http://localhost:8000/v1
|
||||
model: contract-quality-model
|
||||
temperature: 0.1
|
||||
max_tokens: 1000
|
||||
top_p: 0.9
|
||||
timeout_seconds: 120
|
||||
1
testdata/framework/prompts/contract.markdown_summary.system.md
vendored
Normal file
1
testdata/framework/prompts/contract.markdown_summary.system.md
vendored
Normal file
@@ -0,0 +1 @@
|
||||
You summarize synthetic archive notes in clear Markdown.
|
||||
7
testdata/framework/prompts/contract.markdown_summary.user.md
vendored
Normal file
7
testdata/framework/prompts/contract.markdown_summary.user.md
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
Summarize this transcript:
|
||||
|
||||
{{input "transcript"}}
|
||||
|
||||
Optional glossary:
|
||||
|
||||
{{input "glossary"}}
|
||||
20
testdata/framework/prompts/contract.markdown_summary.yaml
vendored
Normal file
20
testdata/framework/prompts/contract.markdown_summary.yaml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
id: contract.markdown_summary
|
||||
version: "1.0.0"
|
||||
default_profile: contract-fast
|
||||
description: Summarize a synthetic transcript in Markdown.
|
||||
inputs:
|
||||
- name: transcript
|
||||
required: true
|
||||
content_type: text/markdown
|
||||
- name: glossary
|
||||
required: false
|
||||
content_type: text/yaml
|
||||
messages:
|
||||
- role: system
|
||||
content_file: ./contract.markdown_summary.system.md
|
||||
- role: user
|
||||
content_file: ./contract.markdown_summary.user.md
|
||||
output:
|
||||
format: markdown
|
||||
validation_mode: basic
|
||||
repair_attempts: 0
|
||||
1
testdata/framework/prompts/contract.structured_events.system.md
vendored
Normal file
1
testdata/framework/prompts/contract.structured_events.system.md
vendored
Normal file
@@ -0,0 +1 @@
|
||||
Return only JSON that satisfies the requested event schema.
|
||||
7
testdata/framework/prompts/contract.structured_events.user.md
vendored
Normal file
7
testdata/framework/prompts/contract.structured_events.user.md
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
Extract events from this transcript:
|
||||
|
||||
{{input "transcript"}}
|
||||
|
||||
Optional glossary:
|
||||
|
||||
{{input "glossary"}}
|
||||
21
testdata/framework/prompts/contract.structured_events.yaml
vendored
Normal file
21
testdata/framework/prompts/contract.structured_events.yaml
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
id: contract.structured_events
|
||||
version: "1.0.0"
|
||||
default_profile: contract-quality
|
||||
description: Extract synthetic events as structured JSON.
|
||||
inputs:
|
||||
- name: transcript
|
||||
required: true
|
||||
content_type: text/markdown
|
||||
- name: glossary
|
||||
required: false
|
||||
content_type: text/yaml
|
||||
messages:
|
||||
- role: system
|
||||
content_file: ./contract.structured_events.system.md
|
||||
- role: user
|
||||
content_file: ./contract.structured_events.user.md
|
||||
output:
|
||||
format: json
|
||||
validation_mode: json_schema
|
||||
schema_path: structured_events.schema.json
|
||||
repair_attempts: 0
|
||||
19
testdata/framework/schemas/structured_events.schema.json
vendored
Normal file
19
testdata/framework/schemas/structured_events.schema.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"$schema": "https://json-schema.org/draft/2020-12/schema",
|
||||
"type": "object",
|
||||
"required": ["events"],
|
||||
"properties": {
|
||||
"events": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "object",
|
||||
"required": ["title"],
|
||||
"properties": {
|
||||
"title": {"type": "string"}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
}
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
Reference in New Issue
Block a user