Cut modules over to Scriptorium prompts
This commit is contained in:
@@ -1,7 +1,6 @@
|
||||
package spells
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
@@ -41,29 +40,21 @@ func TestExtractReturnsSpellCandidateFromStructuredOutput(t *testing.T) {
|
||||
if req.StageName != Key {
|
||||
t.Fatalf("StageName = %q, want %q", req.StageName, Key)
|
||||
}
|
||||
schema, err := loadResponseSchema()
|
||||
if err != nil {
|
||||
t.Fatalf("loadResponseSchema() error = %v, want nil", err)
|
||||
if req.PromptID != PromptID || req.PromptVersion != SchemaVersion {
|
||||
t.Fatalf("prompt = %q/%q, want %q/%q", req.PromptID, req.PromptVersion, PromptID, SchemaVersion)
|
||||
}
|
||||
if req.ResponseSchemaName != schema.Name {
|
||||
t.Fatalf("ResponseSchemaName = %q, want %q", req.ResponseSchemaName, schema.Name)
|
||||
if req.SessionID != "session-123" || req.ProfileID != "profile-spells" {
|
||||
t.Fatalf("session/profile = %q/%q, want session-123/profile-spells", req.SessionID, req.ProfileID)
|
||||
}
|
||||
if !bytes.Equal(req.ResponseSchema, schema.JSONSchema) {
|
||||
t.Fatal("ResponseSchema does not match registered D&D spells schema")
|
||||
if len(req.Messages) != 0 || req.ResponseSchemaName != "" || len(req.ResponseSchema) != 0 {
|
||||
t.Fatalf("legacy prompt fields set: messages=%#v schema=%q/%s", req.Messages, req.ResponseSchemaName, req.ResponseSchema)
|
||||
}
|
||||
if len(req.Messages) != 2 {
|
||||
t.Fatalf("len(Messages) = %d, want 2", len(req.Messages))
|
||||
transcript := req.Inputs["transcript"]
|
||||
if transcript.Name != "transcript" || transcript.MediaType != "application/json" || transcript.Digest != "sha256:transcript" || transcript.OriginURI != "file:///session-alpha.json" {
|
||||
t.Fatalf("transcript metadata = %#v", transcript)
|
||||
}
|
||||
if req.Messages[0].Role != "system" || req.Messages[1].Role != "user" {
|
||||
t.Fatalf("Messages roles = %#v, want system then user", req.Messages)
|
||||
}
|
||||
if !strings.Contains(req.Messages[0].Content, "D&D spell-cast") {
|
||||
t.Fatalf("system message = %q, want D&D spell context", req.Messages[0].Content)
|
||||
}
|
||||
for _, want := range []string{"session-alpha", "session-alpha:chunk:0", "seg-001", "Cure Wounds"} {
|
||||
if !strings.Contains(req.Messages[1].Content, want) {
|
||||
t.Fatalf("user message = %q, want substring %q", req.Messages[1].Content, want)
|
||||
}
|
||||
if got := string(transcript.Content); got != spellTranscriptJSON {
|
||||
t.Fatalf("transcript content = %q, want original source input", got)
|
||||
}
|
||||
|
||||
if len(result.Candidates) != 1 {
|
||||
@@ -116,7 +107,7 @@ func TestExtractorManifestMetadataIncludesPromptAndSchemaProvenance(t *testing.T
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractIncludesReferencesInPrompt(t *testing.T) {
|
||||
func TestExtractPassesReferencesAsPromptInputs(t *testing.T) {
|
||||
client := &fakeSpellsLLMClient{response: extractionResponse{SpellCasts: []spellCastResponse{}}}
|
||||
req := extractionRequestWithClient(client)
|
||||
req.References = contracts.ReferenceSet{
|
||||
@@ -143,26 +134,18 @@ func TestExtractIncludesReferencesInPrompt(t *testing.T) {
|
||||
if len(client.requests) != 1 {
|
||||
t.Fatalf("LLM calls = %d, want 1", len(client.requests))
|
||||
}
|
||||
system := client.requests[0].Messages[0].Content
|
||||
for _, want := range []string{
|
||||
"Reference material, when present, is supporting context only.",
|
||||
"in reference material.",
|
||||
} {
|
||||
if !strings.Contains(system, want) {
|
||||
t.Fatalf("system prompt = %q, want substring %q", system, want)
|
||||
}
|
||||
request := client.requests[0]
|
||||
if len(request.Messages) != 0 {
|
||||
t.Fatalf("Messages = %#v, want no locally rendered prompt", request.Messages)
|
||||
}
|
||||
user := client.requests[0].Messages[1].Content
|
||||
for _, want := range []string{
|
||||
"Roster reference material:",
|
||||
"Aria Brightmantle: party cleric",
|
||||
"Glossary reference material:",
|
||||
"Brightmantle: local temple name",
|
||||
"mentioned only in reference material.",
|
||||
} {
|
||||
if !strings.Contains(user, want) {
|
||||
t.Fatalf("user prompt = %q, want substring %q", user, want)
|
||||
}
|
||||
if got := string(request.Inputs["roster"].Content); got != "Aria Brightmantle: party cleric" {
|
||||
t.Fatalf("roster input = %q, want reference content", got)
|
||||
}
|
||||
if got := string(request.Inputs["glossary"].Content); got != "Brightmantle: local temple name" {
|
||||
t.Fatalf("glossary input = %q, want reference content", got)
|
||||
}
|
||||
if strings.Contains(string(request.Inputs["transcript"].Content), "Aria Brightmantle: party cleric") {
|
||||
t.Fatalf("transcript input contains reference content")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,9 +291,18 @@ func TestExtractCopiesCandidateSourceRefs(t *testing.T) {
|
||||
func extractionRequestWithClient(client contracts.StructuredLLMClient) contracts.ExtractionRequest {
|
||||
req := promptExtractionRequest()
|
||||
req.LLMClient = client
|
||||
req.SourceInput = spellSourceInput()
|
||||
req.SessionID = "session-123"
|
||||
req.LLMProfile = "profile-spells"
|
||||
return req
|
||||
}
|
||||
|
||||
const spellTranscriptJSON = `{"id":"session-alpha","segments":[{"id":"seg-001","text":"Aria raises her hand and casts Cure Wounds."}]}`
|
||||
|
||||
func spellSourceInput() contracts.LLMInputMaterial {
|
||||
return contracts.NewLLMInputMaterial("source", "application/json", []byte(spellTranscriptJSON), "sha256:transcript", "file:///session-alpha.json")
|
||||
}
|
||||
|
||||
func emptyChunkRequest(req contracts.ExtractionRequest) contracts.ExtractionRequest {
|
||||
req.Chunk = &contracts.SourceChunk{
|
||||
ID: req.Chunk.ID,
|
||||
@@ -327,13 +319,7 @@ type fakeSpellsLLMClient struct {
|
||||
}
|
||||
|
||||
func (client *fakeSpellsLLMClient) CompleteStructured(ctx context.Context, req contracts.StructuredCompletionRequest, out any) (contracts.StructuredCompletionResponse, error) {
|
||||
client.requests = append(client.requests, contracts.StructuredCompletionRequest{
|
||||
StageName: req.StageName,
|
||||
Messages: append([]contracts.LLMMessage(nil), req.Messages...),
|
||||
Model: req.Model,
|
||||
ResponseSchemaName: req.ResponseSchemaName,
|
||||
ResponseSchema: append(json.RawMessage(nil), req.ResponseSchema...),
|
||||
})
|
||||
client.requests = append(client.requests, cloneStructuredCompletionRequest(req))
|
||||
if client.err != nil {
|
||||
return contracts.StructuredCompletionResponse{}, client.err
|
||||
}
|
||||
@@ -349,3 +335,10 @@ func (client *fakeSpellsLLMClient) CompleteStructured(ctx context.Context, req c
|
||||
}
|
||||
return contracts.StructuredCompletionResponse{Content: content}, nil
|
||||
}
|
||||
|
||||
func cloneStructuredCompletionRequest(req contracts.StructuredCompletionRequest) contracts.StructuredCompletionRequest {
|
||||
req.Messages = append([]contracts.LLMMessage(nil), req.Messages...)
|
||||
req.ResponseSchema = append(json.RawMessage(nil), req.ResponseSchema...)
|
||||
req.Inputs = req.Inputs.Clone()
|
||||
return req
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user