Move framework tests to contract fixtures
This commit is contained in:
322
engine_test.go
322
engine_test.go
@@ -36,14 +36,14 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestNewEngineRejectsMissingPromptDir(t *testing.T) {
|
func TestNewEngineRejectsMissingPromptDir(t *testing.T) {
|
||||||
_, err := scriptorium.NewEngine(scriptorium.Config{ProfileDir: "./examples/profiles"})
|
_, err := scriptorium.NewEngine(scriptorium.Config{ProfileDir: frameworkProfileDir})
|
||||||
if !errors.Is(err, scriptorium.ErrInvalidConfig) {
|
if !errors.Is(err, scriptorium.ErrInvalidConfig) {
|
||||||
t.Fatalf("expected ErrInvalidConfig, got %v", err)
|
t.Fatalf("expected ErrInvalidConfig, got %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewEngineAcceptsMissingProfileDir(t *testing.T) {
|
func TestNewEngineAcceptsMissingProfileDir(t *testing.T) {
|
||||||
_, err := scriptorium.NewEngine(scriptorium.Config{PromptDir: "./examples/prompts"})
|
_, err := scriptorium.NewEngine(scriptorium.Config{PromptDir: frameworkPromptDir})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected missing profile dir to use built-ins, got %v", err)
|
t.Fatalf("expected missing profile dir to use built-ins, got %v", err)
|
||||||
}
|
}
|
||||||
@@ -135,10 +135,10 @@ func TestPrepareWorksWithFrameworkContractCorpus(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPrepareWorksWithInlineInputs(t *testing.T) {
|
func TestPrepareWorksWithInlineInputs(t *testing.T) {
|
||||||
engine := newExampleEngine(t)
|
engine := newContractEngine(t)
|
||||||
|
|
||||||
prepared, err := engine.Prepare(context.Background(), scriptorium.RunRequest{
|
prepared, err := engine.Prepare(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin scouts the tower.\nKara lights a lantern."),
|
"transcript": scriptorium.Inline("Rin scouts the tower.\nKara lights a lantern."),
|
||||||
"glossary": scriptorium.InlineWithURI("memory://glossary.yml", "party:\n - Rin\n - Kara\n"),
|
"glossary": scriptorium.InlineWithURI("memory://glossary.yml", "party:\n - Rin\n - Kara\n"),
|
||||||
@@ -161,12 +161,22 @@ func TestPreparedRunJSONDoesNotExposeSecretOrTargetPresence(t *testing.T) {
|
|||||||
const secret = "public-api-test-secret"
|
const secret = "public-api-test-secret"
|
||||||
t.Setenv(envName, secret)
|
t.Setenv(envName, secret)
|
||||||
|
|
||||||
engine := newExampleEngine(t)
|
profileDir := t.TempDir()
|
||||||
|
writePublicProfileFileWithAPIKeyEnv(t, profileDir, "prepared-secret", "http://localhost:8000/v1", "prepared-secret-model", envName)
|
||||||
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
|
PromptDir: frameworkPromptDir,
|
||||||
|
ProfileDir: profileDir,
|
||||||
|
SchemaDir: frameworkSchemaDir,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected engine construction to succeed, got %v", err)
|
||||||
|
}
|
||||||
prepared, err := engine.Prepare(context.Background(), scriptorium.RunRequest{
|
prepared, err := engine.Prepare(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.structured_events",
|
PromptID: frameworkStructuredEventsPromptID,
|
||||||
|
ProfileID: "prepared-secret",
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.File("./examples/fixtures/transcript.md"),
|
"transcript": scriptorium.File(frameworkTranscriptPath),
|
||||||
"glossary": scriptorium.File("./examples/fixtures/glossary.yml"),
|
"glossary": scriptorium.File(frameworkGlossaryPath),
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -194,8 +204,8 @@ func TestPreparedRunJSONDoesNotExposeSecretOrTargetPresence(t *testing.T) {
|
|||||||
func TestRunRequestFormattingRedactsDirectAPIKey(t *testing.T) {
|
func TestRunRequestFormattingRedactsDirectAPIKey(t *testing.T) {
|
||||||
const secret = "run-request-secret"
|
const secret = "run-request-secret"
|
||||||
req := scriptorium.RunRequest{
|
req := scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
ProfileID: "local-fast",
|
ProfileID: frameworkFastProfileID,
|
||||||
APIKey: secret,
|
APIKey: secret,
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
@@ -265,15 +275,15 @@ func TestGenerateRequestFormattingRedactsDirectAPIKey(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestPreparePreservesExplicitZeroExecutionOverrides(t *testing.T) {
|
func TestPreparePreservesExplicitZeroExecutionOverrides(t *testing.T) {
|
||||||
engine := newExampleEngine(t)
|
engine := newContractEngine(t)
|
||||||
zeroFloat := 0.0
|
zeroFloat := 0.0
|
||||||
zeroInt := 0
|
zeroInt := 0
|
||||||
|
|
||||||
prepared, err := engine.Prepare(context.Background(), scriptorium.RunRequest{
|
prepared, err := engine.Prepare(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.File("./examples/fixtures/transcript.md"),
|
"transcript": scriptorium.File(frameworkTranscriptPath),
|
||||||
"glossary": scriptorium.File("./examples/fixtures/glossary.yml"),
|
"glossary": scriptorium.File(frameworkGlossaryPath),
|
||||||
},
|
},
|
||||||
Execution: &scriptorium.ExecutionTargetOverride{
|
Execution: &scriptorium.ExecutionTargetOverride{
|
||||||
Temperature: &zeroFloat,
|
Temperature: &zeroFloat,
|
||||||
@@ -308,10 +318,10 @@ func TestRunSucceedsWithInjectedLLMClient(t *testing.T) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
engine := newExampleEngineWithOptions(t, "./examples/schemas", scriptorium.WithLLMClient(fake))
|
engine := newContractEngineWithOptions(t, frameworkSchemaDir, scriptorium.WithLLMClient(fake))
|
||||||
|
|
||||||
result, err := engine.Run(context.Background(), scriptorium.RunRequest{
|
result, err := engine.Run(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
"glossary": scriptorium.Inline("gate: A guarded passage."),
|
"glossary": scriptorium.Inline("gate: A guarded passage."),
|
||||||
@@ -338,7 +348,7 @@ func TestRunSucceedsWithInjectedLLMClient(t *testing.T) {
|
|||||||
if result.Validation.Status != scriptorium.ValidationPassed || !result.Validation.IsValid {
|
if result.Validation.Status != scriptorium.ValidationPassed || !result.Validation.IsValid {
|
||||||
t.Fatalf("expected passed validation, got %+v", result.Validation)
|
t.Fatalf("expected passed validation, got %+v", result.Validation)
|
||||||
}
|
}
|
||||||
if result.PromptID != "generic.markdown_summary" || result.SelectedProfileID != "local-fast" || result.ModelName != "gpt-4o-mini" {
|
if result.PromptID != frameworkMarkdownSummaryPromptID || result.SelectedProfileID != frameworkFastProfileID || result.ModelName != "contract-fast-model" {
|
||||||
t.Fatalf("unexpected run metadata: %+v", result)
|
t.Fatalf("unexpected run metadata: %+v", result)
|
||||||
}
|
}
|
||||||
if result.Usage.TotalTokens != 15 || result.Usage.CachedTokens != 3 || result.Usage.CacheWriteTokens != 2 {
|
if result.Usage.TotalTokens != 15 || result.Usage.CachedTokens != 3 || result.Usage.CacheWriteTokens != 2 {
|
||||||
@@ -354,17 +364,69 @@ func TestRunSucceedsWithInjectedLLMClient(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestEngineRunWithDirectorySourcesAndFileInputs(t *testing.T) {
|
||||||
|
fake := &fakeLLMClient{
|
||||||
|
response: &scriptorium.GenerateResponse{
|
||||||
|
Content: `{"events":[{"title":"Archive labelled"}]}`,
|
||||||
|
Usage: scriptorium.TokenUsage{
|
||||||
|
PromptTokens: 42,
|
||||||
|
CompletionTokens: 36,
|
||||||
|
TotalTokens: 78,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
engine := newContractEngineWithOptions(t, frameworkSchemaDir, scriptorium.WithLLMClient(fake))
|
||||||
|
|
||||||
|
result, err := engine.Run(context.Background(), scriptorium.RunRequest{
|
||||||
|
PromptID: frameworkStructuredEventsPromptID,
|
||||||
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
|
"transcript": scriptorium.File(frameworkTranscriptPath),
|
||||||
|
"glossary": scriptorium.File(frameworkGlossaryPath),
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected run to succeed, got %v", err)
|
||||||
|
}
|
||||||
|
if result.PromptID != frameworkStructuredEventsPromptID || result.SelectedProfileID != frameworkQualityProfileID {
|
||||||
|
t.Fatalf("unexpected run metadata: %+v", result)
|
||||||
|
}
|
||||||
|
if result.RunID == "" || result.PromptHash == "" || result.RenderedPromptHash == "" {
|
||||||
|
t.Fatalf("expected run and prompt hashes, got %+v", result)
|
||||||
|
}
|
||||||
|
if result.InputHashes["transcript"] == "" || result.InputHashes["glossary"] == "" {
|
||||||
|
t.Fatalf("expected both input hashes, got %#v", result.InputHashes)
|
||||||
|
}
|
||||||
|
if len(fake.requests) != 1 || fake.requests[0].StructuredOutput == nil ||
|
||||||
|
fake.requests[0].StructuredOutput.Type != scriptorium.StructuredOutputJSONSchema ||
|
||||||
|
fake.requests[0].StructuredOutput.JSONSchema == nil ||
|
||||||
|
fake.requests[0].StructuredOutput.JSONSchema.Schema == nil {
|
||||||
|
t.Fatalf("expected provider JSON Schema structured output, got %+v", fake.requests)
|
||||||
|
}
|
||||||
|
if result.Validation.Status != scriptorium.ValidationPassed || !result.Validation.IsValid || result.Validation.Mode != scriptorium.ValidationJSONSchema {
|
||||||
|
t.Fatalf("expected passed JSON Schema validation, got %+v", result.Validation)
|
||||||
|
}
|
||||||
|
if result.Artifact.ContentType != "application/json" {
|
||||||
|
t.Fatalf("expected JSON artifact, got %q", result.Artifact.ContentType)
|
||||||
|
}
|
||||||
|
if result.RawOutput != fake.response.Content || result.Usage != fake.response.Usage {
|
||||||
|
t.Fatalf("expected preserved output and usage, got output=%q usage=%+v", result.RawOutput, result.Usage)
|
||||||
|
}
|
||||||
|
if result.StartTime.IsZero() || result.EndTime.IsZero() || result.EndTime.Before(result.StartTime) || result.Duration < 0 {
|
||||||
|
t.Fatalf("expected ordered non-zero timestamps and non-negative duration, got start=%v end=%v duration=%v", result.StartTime, result.EndTime, result.Duration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestRunPassesPreparedRequestToInjectedLLMClient(t *testing.T) {
|
func TestRunPassesPreparedRequestToInjectedLLMClient(t *testing.T) {
|
||||||
const directKey = "direct-injected-key"
|
const directKey = "direct-injected-key"
|
||||||
fake := &fakeLLMClient{
|
fake := &fakeLLMClient{
|
||||||
response: &scriptorium.GenerateResponse{Content: "ok"},
|
response: &scriptorium.GenerateResponse{Content: "ok"},
|
||||||
}
|
}
|
||||||
engine := newExampleEngineWithOptions(t, "./examples/schemas", scriptorium.WithLLMClient(fake))
|
engine := newContractEngineWithOptions(t, frameworkSchemaDir, scriptorium.WithLLMClient(fake))
|
||||||
zeroFloat := 0.0
|
zeroFloat := 0.0
|
||||||
zeroInt := 0
|
zeroInt := 0
|
||||||
|
|
||||||
_, err := engine.Run(context.Background(), scriptorium.RunRequest{
|
_, err := engine.Run(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
APIKey: directKey,
|
APIKey: directKey,
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
@@ -387,7 +449,7 @@ func TestRunPassesPreparedRequestToInjectedLLMClient(t *testing.T) {
|
|||||||
if len(req.Prompt.Messages) != 2 || !strings.Contains(req.Prompt.Messages[1].Content, "Rin opens the gate.") {
|
if len(req.Prompt.Messages) != 2 || !strings.Contains(req.Prompt.Messages[1].Content, "Rin opens the gate.") {
|
||||||
t.Fatalf("expected rendered prompt in generate request, got %+v", req.Prompt)
|
t.Fatalf("expected rendered prompt in generate request, got %+v", req.Prompt)
|
||||||
}
|
}
|
||||||
if req.Target.Model != "gpt-4o-mini" || req.Target.Temperature != 0 || req.Target.MaxTokens != 0 || req.Target.TopP != 0 || req.Target.TimeoutSeconds != 0 {
|
if req.Target.Model != "contract-fast-model" || req.Target.Temperature != 0 || req.Target.MaxTokens != 0 || req.Target.TopP != 0 || req.Target.TimeoutSeconds != 0 {
|
||||||
t.Fatalf("unexpected effective target: %+v", req.Target)
|
t.Fatalf("unexpected effective target: %+v", req.Target)
|
||||||
}
|
}
|
||||||
if !req.TargetPresence.Temperature || !req.TargetPresence.MaxTokens || !req.TargetPresence.TopP || !req.TargetPresence.TimeoutSeconds {
|
if !req.TargetPresence.Temperature || !req.TargetPresence.MaxTokens || !req.TargetPresence.TopP || !req.TargetPresence.TimeoutSeconds {
|
||||||
@@ -430,16 +492,16 @@ func TestRunUsesDirectAPIKeyWithDefaultLLMClient(t *testing.T) {
|
|||||||
profileDir := t.TempDir()
|
profileDir := t.TempDir()
|
||||||
writePublicProfileFileWithAPIKeyEnv(t, profileDir, "direct-auth", server.URL+"/v1", "test-model", missingEnv)
|
writePublicProfileFileWithAPIKeyEnv(t, profileDir, "direct-auth", server.URL+"/v1", "test-model", missingEnv)
|
||||||
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
PromptDir: "./examples/prompts",
|
PromptDir: frameworkPromptDir,
|
||||||
ProfileDir: profileDir,
|
ProfileDir: profileDir,
|
||||||
SchemaDir: "./examples/schemas",
|
SchemaDir: frameworkSchemaDir,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected engine construction to succeed, got %v", err)
|
t.Fatalf("expected engine construction to succeed, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
result, err := engine.Run(context.Background(), scriptorium.RunRequest{
|
result, err := engine.Run(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
ProfileID: "direct-auth",
|
ProfileID: "direct-auth",
|
||||||
APIKey: directKey,
|
APIKey: directKey,
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
@@ -475,16 +537,16 @@ func TestPrepareDirectAPIKeyBypassesMissingEnvWithoutLeakingOrHashing(t *testing
|
|||||||
profileDir := t.TempDir()
|
profileDir := t.TempDir()
|
||||||
writePublicProfileFileWithAPIKeyEnv(t, profileDir, "direct-prepare", "http://localhost:8000/v1", "test-model", missingEnv)
|
writePublicProfileFileWithAPIKeyEnv(t, profileDir, "direct-prepare", "http://localhost:8000/v1", "test-model", missingEnv)
|
||||||
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
PromptDir: "./examples/prompts",
|
PromptDir: frameworkPromptDir,
|
||||||
ProfileDir: profileDir,
|
ProfileDir: profileDir,
|
||||||
SchemaDir: "./examples/schemas",
|
SchemaDir: frameworkSchemaDir,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected engine construction to succeed, got %v", err)
|
t.Fatalf("expected engine construction to succeed, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
baseReq := scriptorium.RunRequest{
|
baseReq := scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
ProfileID: "direct-prepare",
|
ProfileID: "direct-prepare",
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
@@ -527,16 +589,16 @@ func TestMissingCredentialsFailClearlyWhenProfileRequiresAuth(t *testing.T) {
|
|||||||
profileDir := t.TempDir()
|
profileDir := t.TempDir()
|
||||||
writePublicProfileFileWithAPIKeyEnv(t, profileDir, "requires-auth", "http://localhost:8000/v1", "test-model", missingEnv)
|
writePublicProfileFileWithAPIKeyEnv(t, profileDir, "requires-auth", "http://localhost:8000/v1", "test-model", missingEnv)
|
||||||
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
PromptDir: "./examples/prompts",
|
PromptDir: frameworkPromptDir,
|
||||||
ProfileDir: profileDir,
|
ProfileDir: profileDir,
|
||||||
SchemaDir: "./examples/schemas",
|
SchemaDir: frameworkSchemaDir,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected engine construction to succeed, got %v", err)
|
t.Fatalf("expected engine construction to succeed, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = engine.Prepare(context.Background(), scriptorium.RunRequest{
|
_, err = engine.Prepare(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
ProfileID: "requires-auth",
|
ProfileID: "requires-auth",
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
@@ -555,10 +617,10 @@ func TestRunValidationFailureReturnsResult(t *testing.T) {
|
|||||||
fake := &fakeLLMClient{
|
fake := &fakeLLMClient{
|
||||||
response: &scriptorium.GenerateResponse{Content: ""},
|
response: &scriptorium.GenerateResponse{Content: ""},
|
||||||
}
|
}
|
||||||
engine := newExampleEngineWithOptions(t, "./examples/schemas", scriptorium.WithLLMClient(fake))
|
engine := newContractEngineWithOptions(t, frameworkSchemaDir, scriptorium.WithLLMClient(fake))
|
||||||
|
|
||||||
result, err := engine.Run(context.Background(), scriptorium.RunRequest{
|
result, err := engine.Run(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
"glossary": scriptorium.Inline("gate: A guarded passage."),
|
"glossary": scriptorium.Inline("gate: A guarded passage."),
|
||||||
@@ -600,7 +662,7 @@ func TestPublicErrorsSupportErrorsIs(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "profile not found",
|
name: "profile not found",
|
||||||
req: scriptorium.RunRequest{
|
req: scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
ProfileID: "missing-profile",
|
ProfileID: "missing-profile",
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
@@ -612,9 +674,9 @@ func TestPublicErrorsSupportErrorsIs(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "artifact load",
|
name: "artifact load",
|
||||||
req: scriptorium.RunRequest{
|
req: scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.File("./examples/fixtures/does-not-exist.md"),
|
"transcript": scriptorium.File(filepath.Join(t.TempDir(), "does-not-exist.md")),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
client: &fakeLLMClient{response: &scriptorium.GenerateResponse{Content: "ok"}},
|
client: &fakeLLMClient{response: &scriptorium.GenerateResponse{Content: "ok"}},
|
||||||
@@ -623,7 +685,7 @@ func TestPublicErrorsSupportErrorsIs(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "prompt render",
|
name: "prompt render",
|
||||||
req: scriptorium.RunRequest{
|
req: scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
},
|
},
|
||||||
client: &fakeLLMClient{response: &scriptorium.GenerateResponse{Content: "ok"}},
|
client: &fakeLLMClient{response: &scriptorium.GenerateResponse{Content: "ok"}},
|
||||||
want: scriptorium.ErrPromptRender,
|
want: scriptorium.ErrPromptRender,
|
||||||
@@ -631,7 +693,7 @@ func TestPublicErrorsSupportErrorsIs(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "llm failure",
|
name: "llm failure",
|
||||||
req: scriptorium.RunRequest{
|
req: scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
"glossary": scriptorium.Inline("gate: A guarded passage."),
|
"glossary": scriptorium.Inline("gate: A guarded passage."),
|
||||||
@@ -643,7 +705,7 @@ func TestPublicErrorsSupportErrorsIs(t *testing.T) {
|
|||||||
{
|
{
|
||||||
name: "validation runtime failure",
|
name: "validation runtime failure",
|
||||||
req: scriptorium.RunRequest{
|
req: scriptorium.RunRequest{
|
||||||
PromptID: "generic.structured_events",
|
PromptID: frameworkStructuredEventsPromptID,
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
},
|
},
|
||||||
@@ -659,9 +721,9 @@ func TestPublicErrorsSupportErrorsIs(t *testing.T) {
|
|||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
schemaDir := tc.schemaDir
|
schemaDir := tc.schemaDir
|
||||||
if schemaDir == "" {
|
if schemaDir == "" {
|
||||||
schemaDir = "./examples/schemas"
|
schemaDir = frameworkSchemaDir
|
||||||
}
|
}
|
||||||
engine := newExampleEngineWithOptions(t, schemaDir, scriptorium.WithLLMClient(tc.client))
|
engine := newContractEngineWithOptions(t, schemaDir, scriptorium.WithLLMClient(tc.client))
|
||||||
_, err := engine.Run(context.Background(), tc.req)
|
_, err := engine.Run(context.Background(), tc.req)
|
||||||
if !errors.Is(err, tc.want) {
|
if !errors.Is(err, tc.want) {
|
||||||
t.Fatalf("expected errors.Is(%v), got %v", tc.want, err)
|
t.Fatalf("expected errors.Is(%v), got %v", tc.want, err)
|
||||||
@@ -682,16 +744,16 @@ api_key: secret
|
|||||||
}
|
}
|
||||||
|
|
||||||
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
PromptDir: "./examples/prompts",
|
PromptDir: frameworkPromptDir,
|
||||||
ProfileDir: profileDir,
|
ProfileDir: profileDir,
|
||||||
SchemaDir: "./examples/schemas",
|
SchemaDir: frameworkSchemaDir,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected engine construction to succeed, got %v", err)
|
t.Fatalf("expected engine construction to succeed, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = engine.Prepare(context.Background(), scriptorium.RunRequest{
|
_, err = engine.Prepare(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
ProfileID: "raw-profile",
|
ProfileID: "raw-profile",
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
@@ -716,16 +778,16 @@ unknown_field: true
|
|||||||
}
|
}
|
||||||
|
|
||||||
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
PromptDir: "./examples/prompts",
|
PromptDir: frameworkPromptDir,
|
||||||
ProfileDir: profileDir,
|
ProfileDir: profileDir,
|
||||||
SchemaDir: "./examples/schemas",
|
SchemaDir: frameworkSchemaDir,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected engine construction to succeed, got %v", err)
|
t.Fatalf("expected engine construction to succeed, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = engine.Prepare(context.Background(), scriptorium.RunRequest{
|
_, err = engine.Prepare(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
ProfileID: "broken-profile",
|
ProfileID: "broken-profile",
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
@@ -744,15 +806,15 @@ func TestPromptRepositoryReadFailureMapsToPromptLoad(t *testing.T) {
|
|||||||
missingPromptDir := filepath.Join(t.TempDir(), "missing-prompts")
|
missingPromptDir := filepath.Join(t.TempDir(), "missing-prompts")
|
||||||
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
PromptDir: missingPromptDir,
|
PromptDir: missingPromptDir,
|
||||||
ProfileDir: "./examples/profiles",
|
ProfileDir: frameworkProfileDir,
|
||||||
SchemaDir: "./examples/schemas",
|
SchemaDir: frameworkSchemaDir,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected engine construction to succeed, got %v", err)
|
t.Fatalf("expected engine construction to succeed, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = engine.Prepare(context.Background(), scriptorium.RunRequest{
|
_, err = engine.Prepare(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
"glossary": scriptorium.Inline("gate: A guarded passage."),
|
"glossary": scriptorium.Inline("gate: A guarded passage."),
|
||||||
@@ -769,17 +831,17 @@ func TestPromptRepositoryReadFailureMapsToPromptLoad(t *testing.T) {
|
|||||||
func TestSelectedProfileRepositoryReadFailureMapsToProfileLoad(t *testing.T) {
|
func TestSelectedProfileRepositoryReadFailureMapsToProfileLoad(t *testing.T) {
|
||||||
missingProfileDir := filepath.Join(t.TempDir(), "missing-profiles")
|
missingProfileDir := filepath.Join(t.TempDir(), "missing-profiles")
|
||||||
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
PromptDir: "./examples/prompts",
|
PromptDir: frameworkPromptDir,
|
||||||
ProfileDir: missingProfileDir,
|
ProfileDir: missingProfileDir,
|
||||||
SchemaDir: "./examples/schemas",
|
SchemaDir: frameworkSchemaDir,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected engine construction to succeed, got %v", err)
|
t.Fatalf("expected engine construction to succeed, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = engine.Prepare(context.Background(), scriptorium.RunRequest{
|
_, err = engine.Prepare(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
ProfileID: "local-fast",
|
ProfileID: frameworkFastProfileID,
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
"glossary": scriptorium.Inline("gate: A guarded passage."),
|
"glossary": scriptorium.Inline("gate: A guarded passage."),
|
||||||
@@ -796,15 +858,15 @@ func TestSelectedProfileRepositoryReadFailureMapsToProfileLoad(t *testing.T) {
|
|||||||
func TestPrepareUsesBuiltInProfileWithoutProfileDir(t *testing.T) {
|
func TestPrepareUsesBuiltInProfileWithoutProfileDir(t *testing.T) {
|
||||||
t.Setenv("OPENROUTER_API_KEY", "test-key")
|
t.Setenv("OPENROUTER_API_KEY", "test-key")
|
||||||
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
PromptDir: "./examples/prompts",
|
PromptDir: frameworkPromptDir,
|
||||||
SchemaDir: "./examples/schemas",
|
SchemaDir: frameworkSchemaDir,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected engine construction to succeed, got %v", err)
|
t.Fatalf("expected engine construction to succeed, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
prepared, err := engine.Prepare(context.Background(), scriptorium.RunRequest{
|
prepared, err := engine.Prepare(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
ProfileID: "mistral-small-3",
|
ProfileID: "mistral-small-3",
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
@@ -852,16 +914,16 @@ func TestCustomProfileOverridesBuiltInProfile(t *testing.T) {
|
|||||||
writePublicProfileFile(t, profileDir, "mistral-small-3", "http://localhost:8000/v1", "custom-model")
|
writePublicProfileFile(t, profileDir, "mistral-small-3", "http://localhost:8000/v1", "custom-model")
|
||||||
|
|
||||||
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
PromptDir: "./examples/prompts",
|
PromptDir: frameworkPromptDir,
|
||||||
ProfileDir: profileDir,
|
ProfileDir: profileDir,
|
||||||
SchemaDir: "./examples/schemas",
|
SchemaDir: frameworkSchemaDir,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected engine construction to succeed, got %v", err)
|
t.Fatalf("expected engine construction to succeed, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
prepared, err := engine.Prepare(context.Background(), scriptorium.RunRequest{
|
prepared, err := engine.Prepare(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
ProfileID: "mistral-small-3",
|
ProfileID: "mistral-small-3",
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
@@ -889,16 +951,16 @@ unexpected: true
|
|||||||
}
|
}
|
||||||
|
|
||||||
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
PromptDir: "./examples/prompts",
|
PromptDir: frameworkPromptDir,
|
||||||
ProfileDir: profileDir,
|
ProfileDir: profileDir,
|
||||||
SchemaDir: "./examples/schemas",
|
SchemaDir: frameworkSchemaDir,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected engine construction to succeed, got %v", err)
|
t.Fatalf("expected engine construction to succeed, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = engine.Prepare(context.Background(), scriptorium.RunRequest{
|
_, err = engine.Prepare(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
ProfileID: "mistral-small-3",
|
ProfileID: "mistral-small-3",
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
@@ -915,7 +977,7 @@ func TestPrepareWorksWithPromptFSAndRelativeContentFile(t *testing.T) {
|
|||||||
"assets/prompts/fs-summary.yaml": &fstest.MapFile{Data: []byte(`
|
"assets/prompts/fs-summary.yaml": &fstest.MapFile{Data: []byte(`
|
||||||
id: fs.summary
|
id: fs.summary
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
default_profile: local-fast
|
default_profile: contract-fast
|
||||||
inputs:
|
inputs:
|
||||||
- name: transcript
|
- name: transcript
|
||||||
required: true
|
required: true
|
||||||
@@ -932,8 +994,8 @@ output:
|
|||||||
|
|
||||||
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
PromptDir: t.TempDir(),
|
PromptDir: t.TempDir(),
|
||||||
ProfileDir: "./examples/profiles",
|
ProfileDir: frameworkProfileDir,
|
||||||
SchemaDir: "./examples/schemas",
|
SchemaDir: frameworkSchemaDir,
|
||||||
}, scriptorium.WithPromptFS(promptFS, "assets/prompts"))
|
}, scriptorium.WithPromptFS(promptFS, "assets/prompts"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected engine construction to succeed, got %v", err)
|
t.Fatalf("expected engine construction to succeed, got %v", err)
|
||||||
@@ -958,7 +1020,7 @@ func TestPrepareWithPromptFSRejectsEscapedContentFile(t *testing.T) {
|
|||||||
"assets/prompts/fs-escape.yaml": &fstest.MapFile{Data: []byte(`
|
"assets/prompts/fs-escape.yaml": &fstest.MapFile{Data: []byte(`
|
||||||
id: fs.escape
|
id: fs.escape
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
default_profile: local-fast
|
default_profile: contract-fast
|
||||||
messages:
|
messages:
|
||||||
- role: user
|
- role: user
|
||||||
content_file: ../outside.tmpl
|
content_file: ../outside.tmpl
|
||||||
@@ -972,8 +1034,8 @@ output:
|
|||||||
|
|
||||||
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
PromptDir: t.TempDir(),
|
PromptDir: t.TempDir(),
|
||||||
ProfileDir: "./examples/profiles",
|
ProfileDir: frameworkProfileDir,
|
||||||
SchemaDir: "./examples/schemas",
|
SchemaDir: frameworkSchemaDir,
|
||||||
}, scriptorium.WithPromptFS(promptFS, "assets/prompts"))
|
}, scriptorium.WithPromptFS(promptFS, "assets/prompts"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected engine construction to succeed, got %v", err)
|
t.Fatalf("expected engine construction to succeed, got %v", err)
|
||||||
@@ -991,7 +1053,7 @@ func TestPrepareWorksWithPromptFile(t *testing.T) {
|
|||||||
if err := os.WriteFile(promptPath, []byte(`
|
if err := os.WriteFile(promptPath, []byte(`
|
||||||
id: single.file.prompt
|
id: single.file.prompt
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
default_profile: local-fast
|
default_profile: contract-fast
|
||||||
inputs:
|
inputs:
|
||||||
- name: transcript
|
- name: transcript
|
||||||
required: true
|
required: true
|
||||||
@@ -1010,8 +1072,8 @@ output:
|
|||||||
}
|
}
|
||||||
|
|
||||||
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
ProfileDir: "./examples/profiles",
|
ProfileDir: frameworkProfileDir,
|
||||||
SchemaDir: "./examples/schemas",
|
SchemaDir: frameworkSchemaDir,
|
||||||
}, scriptorium.WithPromptFile(promptPath))
|
}, scriptorium.WithPromptFile(promptPath))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected engine construction to succeed, got %v", err)
|
t.Fatalf("expected engine construction to succeed, got %v", err)
|
||||||
@@ -1044,15 +1106,15 @@ model: profile-fs-model
|
|||||||
}
|
}
|
||||||
|
|
||||||
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
PromptDir: "./examples/prompts",
|
PromptDir: frameworkPromptDir,
|
||||||
SchemaDir: "./examples/schemas",
|
SchemaDir: frameworkSchemaDir,
|
||||||
}, scriptorium.WithProfileFS(profileFS, "profiles"))
|
}, scriptorium.WithProfileFS(profileFS, "profiles"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected engine construction to succeed, got %v", err)
|
t.Fatalf("expected engine construction to succeed, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
prepared, err := engine.Prepare(context.Background(), scriptorium.RunRequest{
|
prepared, err := engine.Prepare(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
ProfileID: "mistral-small-3",
|
ProfileID: "mistral-small-3",
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
@@ -1079,15 +1141,15 @@ model: profile-file-model
|
|||||||
}
|
}
|
||||||
|
|
||||||
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
PromptDir: "./examples/prompts",
|
PromptDir: frameworkPromptDir,
|
||||||
SchemaDir: "./examples/schemas",
|
SchemaDir: frameworkSchemaDir,
|
||||||
}, scriptorium.WithProfileFile(profilePath))
|
}, scriptorium.WithProfileFile(profilePath))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected engine construction to succeed, got %v", err)
|
t.Fatalf("expected engine construction to succeed, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
prepared, err := engine.Prepare(context.Background(), scriptorium.RunRequest{
|
prepared, err := engine.Prepare(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
ProfileID: "mistral-small-3",
|
ProfileID: "mistral-small-3",
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
@@ -1104,8 +1166,8 @@ model: profile-file-model
|
|||||||
|
|
||||||
func TestPrepareWorksWithInMemoryProfilesWithoutProfileFiles(t *testing.T) {
|
func TestPrepareWorksWithInMemoryProfilesWithoutProfileFiles(t *testing.T) {
|
||||||
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
PromptDir: "./examples/prompts",
|
PromptDir: frameworkPromptDir,
|
||||||
SchemaDir: "./examples/schemas",
|
SchemaDir: frameworkSchemaDir,
|
||||||
}, scriptorium.WithProfiles(scriptorium.Profile{
|
}, scriptorium.WithProfiles(scriptorium.Profile{
|
||||||
ID: "memory-profile",
|
ID: "memory-profile",
|
||||||
Endpoint: "http://memory-profile/v1",
|
Endpoint: "http://memory-profile/v1",
|
||||||
@@ -1116,7 +1178,7 @@ func TestPrepareWorksWithInMemoryProfilesWithoutProfileFiles(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
prepared, err := engine.Prepare(context.Background(), scriptorium.RunRequest{
|
prepared, err := engine.Prepare(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
ProfileID: "memory-profile",
|
ProfileID: "memory-profile",
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
@@ -1141,8 +1203,8 @@ model: profile-fs-model
|
|||||||
}
|
}
|
||||||
|
|
||||||
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
PromptDir: "./examples/prompts",
|
PromptDir: frameworkPromptDir,
|
||||||
SchemaDir: "./examples/schemas",
|
SchemaDir: frameworkSchemaDir,
|
||||||
},
|
},
|
||||||
scriptorium.WithProfileFS(profileFS, "profiles"),
|
scriptorium.WithProfileFS(profileFS, "profiles"),
|
||||||
scriptorium.WithProfiles(scriptorium.Profile{
|
scriptorium.WithProfiles(scriptorium.Profile{
|
||||||
@@ -1156,7 +1218,7 @@ model: profile-fs-model
|
|||||||
}
|
}
|
||||||
|
|
||||||
prepared, err := engine.Prepare(context.Background(), scriptorium.RunRequest{
|
prepared, err := engine.Prepare(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
ProfileID: "mistral-small-3",
|
ProfileID: "mistral-small-3",
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
@@ -1172,7 +1234,7 @@ model: profile-fs-model
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestWithProfilesRejectsDuplicateIDs(t *testing.T) {
|
func TestWithProfilesRejectsDuplicateIDs(t *testing.T) {
|
||||||
_, err := scriptorium.NewEngine(scriptorium.Config{PromptDir: "./examples/prompts"},
|
_, err := scriptorium.NewEngine(scriptorium.Config{PromptDir: frameworkPromptDir},
|
||||||
scriptorium.WithProfiles(
|
scriptorium.WithProfiles(
|
||||||
scriptorium.Profile{ID: "duplicate", Endpoint: "http://one/v1", Model: "one"},
|
scriptorium.Profile{ID: "duplicate", Endpoint: "http://one/v1", Model: "one"},
|
||||||
scriptorium.Profile{ID: "duplicate", Endpoint: "http://two/v1", Model: "two"},
|
scriptorium.Profile{ID: "duplicate", Endpoint: "http://two/v1", Model: "two"},
|
||||||
@@ -1196,15 +1258,15 @@ func TestOpenAICompatibleProfileRunsThroughNormalProfilePath(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
PromptDir: "./examples/prompts",
|
PromptDir: frameworkPromptDir,
|
||||||
SchemaDir: "./examples/schemas",
|
SchemaDir: frameworkSchemaDir,
|
||||||
}, scriptorium.WithProfiles(prof), scriptorium.WithLLMClient(fake))
|
}, scriptorium.WithProfiles(prof), scriptorium.WithLLMClient(fake))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected engine construction to succeed, got %v", err)
|
t.Fatalf("expected engine construction to succeed, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = engine.Run(context.Background(), scriptorium.RunRequest{
|
_, err = engine.Run(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
ProfileID: "template-profile",
|
ProfileID: "template-profile",
|
||||||
APIKey: "template-key",
|
APIKey: "template-key",
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
@@ -1313,8 +1375,8 @@ func TestEngineRunLayersTransportAndGenerationTimeouts(t *testing.T) {
|
|||||||
Transport: transport,
|
Transport: transport,
|
||||||
}
|
}
|
||||||
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
PromptDir: "./examples/prompts",
|
PromptDir: frameworkPromptDir,
|
||||||
SchemaDir: "./examples/schemas",
|
SchemaDir: frameworkSchemaDir,
|
||||||
Timeout: tc.configTimeout,
|
Timeout: tc.configTimeout,
|
||||||
HTTPClient: httpClient,
|
HTTPClient: httpClient,
|
||||||
}, scriptorium.WithProfiles(scriptorium.Profile{
|
}, scriptorium.WithProfiles(scriptorium.Profile{
|
||||||
@@ -1335,7 +1397,7 @@ func TestEngineRunLayersTransportAndGenerationTimeouts(t *testing.T) {
|
|||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
_, err = engine.Run(ctx, scriptorium.RunRequest{
|
_, err = engine.Run(ctx, scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
ProfileID: "layered-timeout",
|
ProfileID: "layered-timeout",
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
@@ -1376,7 +1438,7 @@ func TestOpenAICompatibleProfileDefersExtraParamsValidation(t *testing.T) {
|
|||||||
ExtraParams: cyclic,
|
ExtraParams: cyclic,
|
||||||
})
|
})
|
||||||
|
|
||||||
_, err := scriptorium.NewEngine(scriptorium.Config{PromptDir: "./examples/prompts"},
|
_, err := scriptorium.NewEngine(scriptorium.Config{PromptDir: frameworkPromptDir},
|
||||||
scriptorium.WithProfiles(prof),
|
scriptorium.WithProfiles(prof),
|
||||||
)
|
)
|
||||||
if !errors.Is(err, scriptorium.ErrInvalidConfig) {
|
if !errors.Is(err, scriptorium.ErrInvalidConfig) {
|
||||||
@@ -1402,8 +1464,8 @@ func TestOpenAICompatibleProfileNestedExtraParamsRunThroughWithProfiles(t *testi
|
|||||||
extraParams["added"] = "mutated-after-construction"
|
extraParams["added"] = "mutated-after-construction"
|
||||||
|
|
||||||
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
PromptDir: "./examples/prompts",
|
PromptDir: frameworkPromptDir,
|
||||||
SchemaDir: "./examples/schemas",
|
SchemaDir: frameworkSchemaDir,
|
||||||
}, scriptorium.WithProfiles(prof), scriptorium.WithLLMClient(fake))
|
}, scriptorium.WithProfiles(prof), scriptorium.WithLLMClient(fake))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected engine construction to succeed, got %v", err)
|
t.Fatalf("expected engine construction to succeed, got %v", err)
|
||||||
@@ -1411,7 +1473,7 @@ func TestOpenAICompatibleProfileNestedExtraParamsRunThroughWithProfiles(t *testi
|
|||||||
nested["added"] = "mutated-after-construction"
|
nested["added"] = "mutated-after-construction"
|
||||||
|
|
||||||
_, err = engine.Run(context.Background(), scriptorium.RunRequest{
|
_, err = engine.Run(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
ProfileID: "nested-template-profile",
|
ProfileID: "nested-template-profile",
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
@@ -1434,8 +1496,8 @@ func TestOpenAICompatibleProfileNestedExtraParamsRunThroughWithProfiles(t *testi
|
|||||||
|
|
||||||
func TestInMemoryProfileAPIKeyRequiredBehavior(t *testing.T) {
|
func TestInMemoryProfileAPIKeyRequiredBehavior(t *testing.T) {
|
||||||
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
PromptDir: "./examples/prompts",
|
PromptDir: frameworkPromptDir,
|
||||||
SchemaDir: "./examples/schemas",
|
SchemaDir: frameworkSchemaDir,
|
||||||
}, scriptorium.WithProfiles(scriptorium.Profile{
|
}, scriptorium.WithProfiles(scriptorium.Profile{
|
||||||
ID: "requires-key",
|
ID: "requires-key",
|
||||||
Endpoint: "http://requires-key/v1",
|
Endpoint: "http://requires-key/v1",
|
||||||
@@ -1447,7 +1509,7 @@ func TestInMemoryProfileAPIKeyRequiredBehavior(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
req := scriptorium.RunRequest{
|
req := scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
ProfileID: "requires-key",
|
ProfileID: "requires-key",
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
@@ -1466,8 +1528,8 @@ func TestInMemoryProfileAPIKeyRequiredBehavior(t *testing.T) {
|
|||||||
|
|
||||||
func TestInMemoryProfileWithoutAPIKeyRequiredWorksWithoutKey(t *testing.T) {
|
func TestInMemoryProfileWithoutAPIKeyRequiredWorksWithoutKey(t *testing.T) {
|
||||||
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
PromptDir: "./examples/prompts",
|
PromptDir: frameworkPromptDir,
|
||||||
SchemaDir: "./examples/schemas",
|
SchemaDir: frameworkSchemaDir,
|
||||||
}, scriptorium.WithProfiles(scriptorium.Profile{
|
}, scriptorium.WithProfiles(scriptorium.Profile{
|
||||||
ID: "no-key-required",
|
ID: "no-key-required",
|
||||||
Endpoint: "http://no-key/v1",
|
Endpoint: "http://no-key/v1",
|
||||||
@@ -1478,7 +1540,7 @@ func TestInMemoryProfileWithoutAPIKeyRequiredWorksWithoutKey(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, err = engine.Prepare(context.Background(), scriptorium.RunRequest{
|
_, err = engine.Prepare(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
ProfileID: "no-key-required",
|
ProfileID: "no-key-required",
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
@@ -1500,8 +1562,8 @@ func TestInMemoryProfileExtraParamsAreCopiedAcrossPublicBoundary(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
PromptDir: "./examples/prompts",
|
PromptDir: frameworkPromptDir,
|
||||||
SchemaDir: "./examples/schemas",
|
SchemaDir: frameworkSchemaDir,
|
||||||
},
|
},
|
||||||
scriptorium.WithProfiles(scriptorium.Profile{
|
scriptorium.WithProfiles(scriptorium.Profile{
|
||||||
ID: "copy-profile",
|
ID: "copy-profile",
|
||||||
@@ -1519,7 +1581,7 @@ func TestInMemoryProfileExtraParamsAreCopiedAcrossPublicBoundary(t *testing.T) {
|
|||||||
extraParams["added"] = "mutated"
|
extraParams["added"] = "mutated"
|
||||||
|
|
||||||
_, err = engine.Run(context.Background(), scriptorium.RunRequest{
|
_, err = engine.Run(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
ProfileID: "copy-profile",
|
ProfileID: "copy-profile",
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
@@ -1553,7 +1615,7 @@ func TestWithProfilesRejectsInvalidExtraParams(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
_, err := scriptorium.NewEngine(scriptorium.Config{PromptDir: "./examples/prompts"},
|
_, err := scriptorium.NewEngine(scriptorium.Config{PromptDir: frameworkPromptDir},
|
||||||
scriptorium.WithProfiles(scriptorium.Profile{
|
scriptorium.WithProfiles(scriptorium.Profile{
|
||||||
ID: "invalid-extra-params",
|
ID: "invalid-extra-params",
|
||||||
Endpoint: "http://invalid/v1",
|
Endpoint: "http://invalid/v1",
|
||||||
@@ -1583,7 +1645,7 @@ func TestWithProfilesRejectsCyclicExtraParams(t *testing.T) {
|
|||||||
}
|
}
|
||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
_, err := scriptorium.NewEngine(scriptorium.Config{PromptDir: "./examples/prompts"},
|
_, err := scriptorium.NewEngine(scriptorium.Config{PromptDir: frameworkPromptDir},
|
||||||
scriptorium.WithProfiles(scriptorium.Profile{
|
scriptorium.WithProfiles(scriptorium.Profile{
|
||||||
ID: "cyclic-extra-params",
|
ID: "cyclic-extra-params",
|
||||||
Endpoint: "http://cyclic/v1",
|
Endpoint: "http://cyclic/v1",
|
||||||
@@ -1602,7 +1664,7 @@ func TestRunStructuredOutputWorksWithSchemaFS(t *testing.T) {
|
|||||||
fake := &fakeLLMClient{response: &scriptorium.GenerateResponse{Content: `{"events":[]}`}}
|
fake := &fakeLLMClient{response: &scriptorium.GenerateResponse{Content: `{"events":[]}`}}
|
||||||
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
PromptDir: t.TempDir(),
|
PromptDir: t.TempDir(),
|
||||||
ProfileDir: "./examples/profiles",
|
ProfileDir: frameworkProfileDir,
|
||||||
SchemaDir: t.TempDir(),
|
SchemaDir: t.TempDir(),
|
||||||
},
|
},
|
||||||
scriptorium.WithPromptFS(publicStructuredPromptFS("schema.fs.prompt", "events.schema.json"), "prompts"),
|
scriptorium.WithPromptFS(publicStructuredPromptFS("schema.fs.prompt", "events.schema.json"), "prompts"),
|
||||||
@@ -1639,7 +1701,7 @@ func TestRunStructuredOutputWorksWithSchemaFile(t *testing.T) {
|
|||||||
|
|
||||||
fake := &fakeLLMClient{response: &scriptorium.GenerateResponse{Content: `{"events":[]}`}}
|
fake := &fakeLLMClient{response: &scriptorium.GenerateResponse{Content: `{"events":[]}`}}
|
||||||
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
ProfileDir: "./examples/profiles",
|
ProfileDir: frameworkProfileDir,
|
||||||
},
|
},
|
||||||
scriptorium.WithPromptFS(publicStructuredPromptFS("schema.file.prompt", "events.schema.json"), "prompts"),
|
scriptorium.WithPromptFS(publicStructuredPromptFS("schema.file.prompt", "events.schema.json"), "prompts"),
|
||||||
scriptorium.WithSchemaFile(schemaPath),
|
scriptorium.WithSchemaFile(schemaPath),
|
||||||
@@ -1686,7 +1748,7 @@ func TestSourceOptionsRejectInvalidInputs(t *testing.T) {
|
|||||||
|
|
||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
_, err := scriptorium.NewEngine(scriptorium.Config{PromptDir: "./examples/prompts"}, tc.opt)
|
_, err := scriptorium.NewEngine(scriptorium.Config{PromptDir: frameworkPromptDir}, tc.opt)
|
||||||
if !errors.Is(err, scriptorium.ErrInvalidConfig) {
|
if !errors.Is(err, scriptorium.ErrInvalidConfig) {
|
||||||
t.Fatalf("expected ErrInvalidConfig, got %v", err)
|
t.Fatalf("expected ErrInvalidConfig, got %v", err)
|
||||||
}
|
}
|
||||||
@@ -1707,15 +1769,15 @@ func TestPackageOptionsComposeFromSlice(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
engine, err := scriptorium.NewEngine(scriptorium.Config{
|
||||||
PromptDir: "./examples/prompts",
|
PromptDir: frameworkPromptDir,
|
||||||
SchemaDir: "./examples/schemas",
|
SchemaDir: frameworkSchemaDir,
|
||||||
}, options...)
|
}, options...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected package-provided options to compose, got %v", err)
|
t.Fatalf("expected package-provided options to compose, got %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = engine.Run(context.Background(), scriptorium.RunRequest{
|
_, err = engine.Run(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
ProfileID: "slice-profile",
|
ProfileID: "slice-profile",
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
@@ -1735,7 +1797,7 @@ func TestPackageOptionsComposeFromSlice(t *testing.T) {
|
|||||||
|
|
||||||
func TestExtraParamsTypedNestedValuesAreCopiedAcrossPublicBoundary(t *testing.T) {
|
func TestExtraParamsTypedNestedValuesAreCopiedAcrossPublicBoundary(t *testing.T) {
|
||||||
fake := &fakeLLMClient{response: &scriptorium.GenerateResponse{Content: "ok"}}
|
fake := &fakeLLMClient{response: &scriptorium.GenerateResponse{Content: "ok"}}
|
||||||
engine := newExampleEngineWithOptions(t, "./examples/schemas", scriptorium.WithLLMClient(fake))
|
engine := newContractEngineWithOptions(t, frameworkSchemaDir, scriptorium.WithLLMClient(fake))
|
||||||
|
|
||||||
labels := map[string]string{"route": "primary"}
|
labels := map[string]string{"route": "primary"}
|
||||||
counts := map[string]int{"retry_budget": 2}
|
counts := map[string]int{"retry_budget": 2}
|
||||||
@@ -1754,7 +1816,7 @@ func TestExtraParamsTypedNestedValuesAreCopiedAcrossPublicBoundary(t *testing.T)
|
|||||||
}
|
}
|
||||||
|
|
||||||
_, err := engine.Run(context.Background(), scriptorium.RunRequest{
|
_, err := engine.Run(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
"glossary": scriptorium.Inline("gate: A guarded passage."),
|
"glossary": scriptorium.Inline("gate: A guarded passage."),
|
||||||
@@ -1807,10 +1869,10 @@ func TestRunRejectsInvalidExtraParams(t *testing.T) {
|
|||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
fake := &fakeLLMClient{response: &scriptorium.GenerateResponse{Content: "ok"}}
|
fake := &fakeLLMClient{response: &scriptorium.GenerateResponse{Content: "ok"}}
|
||||||
engine := newExampleEngineWithOptions(t, "./examples/schemas", scriptorium.WithLLMClient(fake))
|
engine := newContractEngineWithOptions(t, frameworkSchemaDir, scriptorium.WithLLMClient(fake))
|
||||||
|
|
||||||
_, err := engine.Run(context.Background(), scriptorium.RunRequest{
|
_, err := engine.Run(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
"glossary": scriptorium.Inline("gate: A guarded passage."),
|
"glossary": scriptorium.Inline("gate: A guarded passage."),
|
||||||
@@ -1843,10 +1905,10 @@ func TestRunRejectsCyclicExtraParams(t *testing.T) {
|
|||||||
for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
t.Run(tc.name, func(t *testing.T) {
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
fake := &fakeLLMClient{response: &scriptorium.GenerateResponse{Content: "ok"}}
|
fake := &fakeLLMClient{response: &scriptorium.GenerateResponse{Content: "ok"}}
|
||||||
engine := newExampleEngineWithOptions(t, "./examples/schemas", scriptorium.WithLLMClient(fake))
|
engine := newContractEngineWithOptions(t, frameworkSchemaDir, scriptorium.WithLLMClient(fake))
|
||||||
|
|
||||||
_, err := engine.Run(context.Background(), scriptorium.RunRequest{
|
_, err := engine.Run(context.Background(), scriptorium.RunRequest{
|
||||||
PromptID: "generic.markdown_summary",
|
PromptID: frameworkMarkdownSummaryPromptID,
|
||||||
Inputs: map[string]scriptorium.ArtifactRef{
|
Inputs: map[string]scriptorium.ArtifactRef{
|
||||||
"transcript": scriptorium.Inline("Rin opens the gate."),
|
"transcript": scriptorium.Inline("Rin opens the gate."),
|
||||||
"glossary": scriptorium.Inline("gate: A guarded passage."),
|
"glossary": scriptorium.Inline("gate: A guarded passage."),
|
||||||
@@ -1864,52 +1926,52 @@ func TestRunRejectsCyclicExtraParams(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestWithLLMClientRejectsNilClient(t *testing.T) {
|
func TestWithLLMClientRejectsNilClient(t *testing.T) {
|
||||||
_, err := scriptorium.NewEngine(exampleConfig("./examples/schemas"), scriptorium.WithLLMClient(nil))
|
_, err := scriptorium.NewEngine(contractConfig(frameworkSchemaDir), scriptorium.WithLLMClient(nil))
|
||||||
if !errors.Is(err, scriptorium.ErrInvalidConfig) {
|
if !errors.Is(err, scriptorium.ErrInvalidConfig) {
|
||||||
t.Fatalf("expected ErrInvalidConfig, got %v", err)
|
t.Fatalf("expected ErrInvalidConfig, got %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestNewEngineConstructsDefaultLLMClientWithoutCredentials(t *testing.T) {
|
func TestNewEngineConstructsDefaultLLMClientWithoutCredentials(t *testing.T) {
|
||||||
if _, err := scriptorium.NewEngine(exampleConfig("./examples/schemas")); err != nil {
|
if _, err := scriptorium.NewEngine(contractConfig(frameworkSchemaDir)); err != nil {
|
||||||
t.Fatalf("expected default engine construction without credentials to succeed, got %v", err)
|
t.Fatalf("expected default engine construction without credentials to succeed, got %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newExampleEngine(t *testing.T) *scriptorium.Engine {
|
func newContractEngine(t *testing.T) *scriptorium.Engine {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
for _, path := range []string{
|
for _, path := range []string{
|
||||||
"./examples/prompts",
|
frameworkPromptDir,
|
||||||
"./examples/profiles",
|
frameworkProfileDir,
|
||||||
"./examples/schemas",
|
frameworkSchemaDir,
|
||||||
} {
|
} {
|
||||||
if _, err := os.Stat(path); err != nil {
|
if _, err := os.Stat(path); err != nil {
|
||||||
t.Fatalf("expected example path %s to exist: %v", path, err)
|
t.Fatalf("expected framework contract path %s to exist: %v", path, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
engine, err := scriptorium.NewEngine(exampleConfig("./examples/schemas"))
|
engine, err := scriptorium.NewEngine(contractConfig(frameworkSchemaDir))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected engine construction to succeed, got %v", err)
|
t.Fatalf("expected engine construction to succeed, got %v", err)
|
||||||
}
|
}
|
||||||
return engine
|
return engine
|
||||||
}
|
}
|
||||||
|
|
||||||
func newExampleEngineWithOptions(t *testing.T, schemaDir string, opts ...scriptorium.Option) *scriptorium.Engine {
|
func newContractEngineWithOptions(t *testing.T, schemaDir string, opts ...scriptorium.Option) *scriptorium.Engine {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
|
|
||||||
engine, err := scriptorium.NewEngine(exampleConfig(schemaDir), opts...)
|
engine, err := scriptorium.NewEngine(contractConfig(schemaDir), opts...)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected engine construction to succeed, got %v", err)
|
t.Fatalf("expected engine construction to succeed, got %v", err)
|
||||||
}
|
}
|
||||||
return engine
|
return engine
|
||||||
}
|
}
|
||||||
|
|
||||||
func exampleConfig(schemaDir string) scriptorium.Config {
|
func contractConfig(schemaDir string) scriptorium.Config {
|
||||||
return scriptorium.Config{
|
return scriptorium.Config{
|
||||||
PromptDir: "./examples/prompts",
|
PromptDir: frameworkPromptDir,
|
||||||
ProfileDir: "./examples/profiles",
|
ProfileDir: frameworkProfileDir,
|
||||||
SchemaDir: schemaDir,
|
SchemaDir: schemaDir,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1962,7 +2024,7 @@ func publicStructuredPromptFS(id string, schemaPath string) fstest.MapFS {
|
|||||||
return fstest.MapFS{
|
return fstest.MapFS{
|
||||||
"prompts/prompt.yaml": &fstest.MapFile{Data: []byte(`id: ` + id + `
|
"prompts/prompt.yaml": &fstest.MapFile{Data: []byte(`id: ` + id + `
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
default_profile: local-fast
|
default_profile: contract-fast
|
||||||
inputs:
|
inputs:
|
||||||
- name: transcript
|
- name: transcript
|
||||||
required: true
|
required: true
|
||||||
|
|||||||
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user