2026-07-28 04:33:30 +00:00
package usecase
import (
"context"
"crypto/sha256"
"encoding/hex"
"errors"
"fmt"
2026-08-11 21:12:56 +00:00
"math"
2026-07-28 04:33:30 +00:00
"reflect"
"regexp"
2026-08-11 21:12:56 +00:00
"strconv"
2026-07-28 04:33:30 +00:00
"strings"
2026-07-29 21:11:08 +00:00
"sync"
2026-07-28 04:33:30 +00:00
"testing"
2026-07-29 21:11:08 +00:00
"time"
2026-07-28 04:33:30 +00:00
2026-07-29 21:01:37 +00:00
"gitea.maximumdirect.net/eric/promptkit/internal/capacity"
2026-07-28 04:33:30 +00:00
"gitea.maximumdirect.net/eric/promptkit/internal/defaults"
"gitea.maximumdirect.net/eric/promptkit/internal/domain"
"gitea.maximumdirect.net/eric/promptkit/internal/llm"
"gitea.maximumdirect.net/eric/promptkit/internal/prompt"
"gitea.maximumdirect.net/eric/promptkit/internal/validate"
)
type fakePromptRepo struct {
2026-10-17 05:47:14 +00:00
def * domain . PromptDefinition
err error
lastID string
2026-07-28 04:33:30 +00:00
}
type fakeExecutionProfileRepo struct {
profiles map [ string ] * domain . ExecutionProfile
err error
lastID string
}
2026-07-29 21:11:08 +00:00
type staticPromptRepo struct {
def * domain . PromptDefinition
}
func ( r staticPromptRepo ) GetPromptDefinition (
context . Context ,
string ,
) ( * domain . PromptDefinition , error ) {
return r . def , nil
}
type staticExecutionProfileRepo struct {
profile * domain . ExecutionProfile
}
func ( r staticExecutionProfileRepo ) GetProfile (
context . Context ,
string ,
) ( * domain . ExecutionProfile , error ) {
value := * r . profile
return & value , nil
}
type staticArtifactReader struct { }
func ( staticArtifactReader ) Read (
context . Context ,
domain . ArtifactRef ,
) ( * domain . Artifact , error ) {
return & domain . Artifact { Body : [ ] byte ( "artifact" ) , Hash : hashString ( "artifact" ) } , nil
}
type staticRenderer struct { }
func ( staticRenderer ) Render (
context . Context ,
* domain . PromptDefinition ,
map [ string ] * domain . Artifact ,
map [ string ] string ,
) ( * domain . RenderedPrompt , error ) {
return & domain . RenderedPrompt {
Messages : [ ] domain . RenderedMessage { { Role : "user" , Content : "hello" } } ,
} , nil
}
2026-07-28 04:33:30 +00:00
func ( f * fakeExecutionProfileRepo ) GetProfile ( ctx context . Context , id string ) ( * domain . ExecutionProfile , error ) {
f . lastID = id
if f . err != nil {
return nil , f . err
}
if p , ok := f . profiles [ id ] ; ok {
cp := * p
return & cp , nil
}
return nil , errors . New ( "profile not found" )
}
2026-10-17 05:47:14 +00:00
func ( f * fakePromptRepo ) GetPromptDefinition ( ctx context . Context , id string ) ( * domain . PromptDefinition , error ) {
2026-07-28 04:33:30 +00:00
f . lastID = id
if f . err != nil {
return nil , f . err
}
return f . def , nil
}
type fakeArtifactReader struct {
artifactsByURI map [ string ] * domain . Artifact
errByURI map [ string ] error
2026-07-29 21:01:37 +00:00
calls int
2026-07-28 04:33:30 +00:00
}
func ( f * fakeArtifactReader ) Read ( ctx context . Context , ref domain . ArtifactRef ) ( * domain . Artifact , error ) {
2026-07-29 21:01:37 +00:00
f . calls ++
2026-07-28 04:33:30 +00:00
if err , ok := f . errByURI [ ref . URI ] ; ok {
return nil , err
}
if art , ok := f . artifactsByURI [ ref . URI ] ; ok {
cp := * art
return & cp , nil
}
return nil , errors . New ( "artifact not found" )
}
type fakeRenderer struct {
rendered * domain . RenderedPrompt
err error
2026-07-29 21:01:37 +00:00
calls int
2026-07-28 04:33:30 +00:00
}
func ( f * fakeRenderer ) Render ( ctx context . Context , def * domain . PromptDefinition , inputs map [ string ] * domain . Artifact , vars map [ string ] string ) ( * domain . RenderedPrompt , error ) {
2026-07-29 21:01:37 +00:00
f . calls ++
2026-07-28 04:33:30 +00:00
if f . err != nil {
return nil , f . err
}
return f . rendered , nil
}
type fakeLLM struct {
resp * domain . GenerateResponse
err error
lastReq domain . GenerateRequest
calls int
forbid bool
}
func ( f * fakeLLM ) Generate ( ctx context . Context , req domain . GenerateRequest ) ( * domain . GenerateResponse , error ) {
f . calls ++
f . lastReq = req
if err := ctx . Err ( ) ; err != nil {
return nil , err
}
if f . forbid {
return nil , errors . New ( "llm should not be called" )
}
if f . err != nil {
return nil , f . err
}
return f . resp , nil
}
type fakeValidator struct {
result domain . ValidationResult
err error
schemaDoc any
schemaErr error
schemaLoadPath string
schemaLoads int
2026-07-29 21:01:37 +00:00
validateCalls int
2026-07-28 04:33:30 +00:00
}
func ( f * fakeValidator ) Validate ( ctx context . Context , artifact * domain . Artifact , contract domain . OutputContract ) ( domain . ValidationResult , error ) {
2026-07-29 21:01:37 +00:00
f . validateCalls ++
2026-07-28 04:33:30 +00:00
if f . err != nil {
return domain . ValidationResult { } , f . err
}
return f . result , nil
}
2026-08-11 23:05:11 +00:00
func ( f * fakeValidator ) PrepareValidation ( _ context . Context , contract domain . OutputContract ) ( validate . PreparedValidation , error ) {
var schemaDocument any
if contract . ValidationMode == domain . ValidationJSONSchema {
f . schemaLoads ++
f . schemaLoadPath = contract . SchemaPath
if f . schemaErr != nil {
return nil , f . schemaErr
}
schemaDocument = f . schemaDoc
if schemaDocument == nil {
schemaDocument = map [ string ] any { "type" : "object" }
}
2026-07-28 04:33:30 +00:00
}
2026-08-11 23:05:11 +00:00
return & fakePreparedValidator { validator : f , contract : contract , schemaDocument : schemaDocument } , nil
}
type fakePreparedValidator struct {
validator * fakeValidator
contract domain . OutputContract
schemaDocument any
}
func ( p * fakePreparedValidator ) Validate ( ctx context . Context , artifact * domain . Artifact ) ( domain . ValidationResult , error ) {
return p . validator . Validate ( ctx , artifact , p . contract )
}
func ( p * fakePreparedValidator ) SchemaDocument ( ) any {
return p . schemaDocument
2026-07-28 04:33:30 +00:00
}
type fakeRepairer struct {
responses [ ] * domain . GenerateResponse
err error
calls int
reqs [ ] RepairRequest
}
2026-08-11 23:21:34 +00:00
type sequenceLLM struct {
responses [ ] * domain . GenerateResponse
requests [ ] domain . GenerateRequest
}
func ( c * sequenceLLM ) Generate ( _ context . Context , req domain . GenerateRequest ) ( * domain . GenerateResponse , error ) {
c . requests = append ( c . requests , req )
index := len ( c . requests ) - 1
if index >= len ( c . responses ) {
return nil , errors . New ( "no generation response configured" )
}
return c . responses [ index ] , nil
}
type recordingRepairer struct {
next OutputRepairer
reqs [ ] RepairRequest
}
func ( r * recordingRepairer ) Repair ( ctx context . Context , req RepairRequest ) ( * domain . GenerateResponse , error ) {
r . reqs = append ( r . reqs , req )
return r . next . Repair ( ctx , req )
}
2026-07-29 21:01:37 +00:00
type fakeRunAdmitter struct {
backendIDs [ ] string
err error
releaseCalls int
}
2026-07-29 21:11:08 +00:00
type recordingRunAdmitter struct {
mu sync . Mutex
next RunAdmitter
backendIDs [ ] string
}
func ( a * recordingRunAdmitter ) Admit ( ctx context . Context , backendID string ) ( func ( ) , error ) {
a . mu . Lock ( )
a . backendIDs = append ( a . backendIDs , backendID )
a . mu . Unlock ( )
return a . next . Admit ( ctx , backendID )
}
func ( a * recordingRunAdmitter ) admittedBackendIDs ( ) [ ] string {
a . mu . Lock ( )
defer a . mu . Unlock ( )
return append ( [ ] string ( nil ) , a . backendIDs ... )
}
type controlledRepairLLM struct {
mu sync . Mutex
active int
peak int
calls int
repairCalls int
events chan controlledGeneration
backendIDs [ ] string
}
type controlledGeneration struct {
release chan struct { }
}
func ( c * controlledRepairLLM ) Generate (
ctx context . Context ,
req domain . GenerateRequest ,
) ( * domain . GenerateResponse , error ) {
2026-08-25 11:54:50 +00:00
messages := req . Prompt . Messages
isRepair := len ( messages ) >= 2 &&
messages [ len ( messages ) - 2 ] . Role == "assistant" &&
messages [ len ( messages ) - 1 ] . Role == "user"
2026-07-29 21:11:08 +00:00
c . mu . Lock ( )
c . calls ++
c . active ++
if c . active > c . peak {
c . peak = c . active
}
if isRepair {
c . repairCalls ++
}
c . backendIDs = append ( c . backendIDs , req . Target . BackendID )
c . mu . Unlock ( )
defer func ( ) {
c . mu . Lock ( )
c . active --
c . mu . Unlock ( )
} ( )
event := controlledGeneration { release : make ( chan struct { } ) }
c . events <- event
select {
case <- event . release :
case <- ctx . Done ( ) :
return nil , ctx . Err ( )
}
if isRepair {
return & domain . GenerateResponse { Content : ` { } ` } , nil
}
return & domain . GenerateResponse { Content : ` { "broken": ` } , nil
}
func ( c * controlledRepairLLM ) snapshot ( ) ( peak , calls , repairCalls int , backendIDs [ ] string ) {
c . mu . Lock ( )
defer c . mu . Unlock ( )
return c . peak , c . calls , c . repairCalls , append ( [ ] string ( nil ) , c . backendIDs ... )
}
2026-07-29 21:01:37 +00:00
func ( f * fakeRunAdmitter ) Admit ( _ context . Context , backendID string ) ( func ( ) , error ) {
f . backendIDs = append ( f . backendIDs , backendID )
if f . err != nil {
return nil , f . err
}
return func ( ) {
f . releaseCalls ++
} , nil
}
2026-07-28 04:33:30 +00:00
func ( f * fakeRepairer ) Repair ( ctx context . Context , req RepairRequest ) ( * domain . GenerateResponse , error ) {
f . calls ++
f . reqs = append ( f . reqs , req )
if f . err != nil {
return nil , f . err
}
if len ( f . responses ) == 0 {
return nil , errors . New ( "no repair response configured" )
}
idx := f . calls - 1
if idx >= len ( f . responses ) {
idx = len ( f . responses ) - 1
}
return f . responses [ idx ] , nil
}
func TestRunnerPrepareWithExplicitProfileSelection ( t * testing . T ) {
promptRepo := & fakePromptRepo { def : promptDef ( domain . FormatMarkdown , domain . ValidationBasic , 0 ) }
execRepo := & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { "exec" : defaultExecutionProfile ( ) } }
reader := & fakeArtifactReader { artifactsByURI : map [ string ] * domain . Artifact {
"a://t" : { Body : [ ] byte ( "transcript" ) , Hash : hashString ( "transcript" ) } ,
"a://g" : { Body : [ ] byte ( "glossary" ) , Hash : hashString ( "glossary" ) } ,
} }
renderer := & fakeRenderer { rendered : & domain . RenderedPrompt { SessionID : "session-123" , Messages : [ ] domain . RenderedMessage { { Role : "system" , Content : "sys" } , { Role : "user" , Content : "usr" } } } }
llmClient := & fakeLLM { forbid : true }
2026-09-30 04:18:27 +00:00
runner := NewRunner ( promptRepo , execRepo , reader , renderer , llmClient , nil , nil )
2026-07-28 04:33:30 +00:00
prepared , err := runner . Prepare ( context . Background ( ) , domain . RunRequest {
2026-10-17 05:47:14 +00:00
PromptID : "p" ,
ProfileID : "exec" ,
2026-07-28 04:33:30 +00:00
Inputs : map [ string ] domain . ArtifactRef {
"transcript" : { Type : domain . ArtifactRefFile , URI : "a://t" } ,
"glossary" : { Type : domain . ArtifactRefFile , URI : "a://g" } ,
} ,
Execution : & domain . ExecutionTargetOverride { Endpoint : "http://override/v1" , Model : "m" , Temperature : float64Ptr ( 0.3 ) , TimeoutSeconds : intPtr ( 90 ) } ,
} )
if err != nil {
t . Fatalf ( "expected no error, got %v" , err )
}
2026-10-17 05:54:32 +00:00
if prepared . PromptID != "p" || prepared . PromptVersion == nil || * prepared . PromptVersion != "1" {
2026-07-28 04:33:30 +00:00
t . Fatalf ( "unexpected prepared prompt metadata: %+v" , prepared )
}
if prepared . SelectedProfileID != "exec" {
t . Fatalf ( "expected selected profile exec, got %q" , prepared . SelectedProfileID )
}
if prepared . PromptHash == "" || prepared . RenderedPromptHash == "" {
t . Fatal ( "expected prompt hashes" )
}
if prepared . EffectiveModelParams . Model != "m" || prepared . EffectiveModelParams . Endpoint != "http://override/v1" {
t . Fatalf ( "unexpected model params: %+v" , prepared . EffectiveModelParams )
}
if prepared . OutputContract . Format != domain . FormatMarkdown {
t . Fatalf ( "expected output format markdown, got %q" , prepared . OutputContract . Format )
}
if len ( prepared . InputHashes ) != 2 || prepared . InputHashes [ "transcript" ] == "" || prepared . InputHashes [ "glossary" ] == "" {
t . Fatalf ( "expected input hashes, got %#v" , prepared . InputHashes )
}
if len ( prepared . Messages ) != 2 {
t . Fatalf ( "expected two messages, got %d" , len ( prepared . Messages ) )
}
if prepared . SessionID != "session-123" {
t . Fatalf ( "expected prepared session id, got %q" , prepared . SessionID )
}
if llmClient . calls != 0 {
t . Fatalf ( "prepare should not call llm, calls=%d" , llmClient . calls )
}
}
2026-07-29 19:43:26 +00:00
func TestRunnerDirectSessionResolution ( t * testing . T ) {
t . Run ( "direct value wins and changes only the rendered prompt hash" , func ( t * testing . T ) {
def := promptDef ( domain . FormatText , domain . ValidationNone , 0 )
def . SessionID = "template-{{.template_session}}"
promptRepo := & fakePromptRepo { def : def }
runner := NewRunner (
promptRepo ,
& fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { "exec" : defaultExecutionProfile ( ) } } ,
2026-09-30 04:18:27 +00:00
2026-07-29 19:43:26 +00:00
defaultArtifactReader ( ) ,
prompt . NewGoRenderer ( ) ,
& fakeLLM { forbid : true } ,
2026-07-29 21:01:37 +00:00
nil , nil )
2026-07-29 19:43:26 +00:00
req := domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : singleInputRef ( ) ,
Vars : map [ string ] string { "template_session" : "from-template" } ,
}
req . SessionID = " direct-one "
first , err := runner . Prepare ( context . Background ( ) , req )
if err != nil {
t . Fatalf ( "prepare first direct session: %v" , err )
}
req . SessionID = "direct-two"
second , err := runner . Prepare ( context . Background ( ) , req )
if err != nil {
t . Fatalf ( "prepare second direct session: %v" , err )
}
if first . SessionID != "direct-one" || second . SessionID != "direct-two" {
t . Fatalf ( "direct sessions were not normalized: first=%q second=%q" , first . SessionID , second . SessionID )
}
if first . PromptHash != second . PromptHash {
t . Fatalf ( "direct session changed prompt-definition hash: first=%q second=%q" , first . PromptHash , second . PromptHash )
}
if first . RenderedPromptHash == second . RenderedPromptHash {
t . Fatal ( "changing direct session did not change rendered-prompt hash" )
}
if def . SessionID != "template-{{.template_session}}" {
t . Fatalf ( "repository-owned prompt definition was mutated: %q" , def . SessionID )
}
} )
t . Run ( "direct value bypasses failing session template without changing messages" , func ( t * testing . T ) {
def := promptDef ( domain . FormatText , domain . ValidationNone , 0 )
def . SessionID = "{{.missing_session}}"
def . Templates = [ ] domain . PromptMessageTemplate {
{ Role : "user" , Content : "Hello {{.name}}" } ,
}
runner := NewRunner (
& fakePromptRepo { def : def } ,
& fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { "exec" : defaultExecutionProfile ( ) } } ,
2026-09-30 04:18:27 +00:00
2026-07-29 19:43:26 +00:00
defaultArtifactReader ( ) ,
prompt . NewGoRenderer ( ) ,
& fakeLLM { forbid : true } ,
2026-07-29 21:01:37 +00:00
nil , nil )
2026-07-29 19:43:26 +00:00
prepared , err := runner . Prepare ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
SessionID : "direct-session" ,
Inputs : singleInputRef ( ) ,
Vars : map [ string ] string { "name" : "Rin" } ,
} )
if err != nil {
t . Fatalf ( "prepare with direct session: %v" , err )
}
if prepared . SessionID != "direct-session" {
t . Fatalf ( "prepared session id = %q, want direct-session" , prepared . SessionID )
}
if len ( prepared . Messages ) != 1 || prepared . Messages [ 0 ] . Content != "Hello Rin" {
t . Fatalf ( "message templates did not render normally: %+v" , prepared . Messages )
}
} )
t . Run ( "blank direct value retains prompt template behavior" , func ( t * testing . T ) {
def := promptDef ( domain . FormatText , domain . ValidationNone , 0 )
def . SessionID = " template-{{.template_session}} "
runner := NewRunner (
& fakePromptRepo { def : def } ,
& fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { "exec" : defaultExecutionProfile ( ) } } ,
2026-09-30 04:18:27 +00:00
2026-07-29 19:43:26 +00:00
defaultArtifactReader ( ) ,
prompt . NewGoRenderer ( ) ,
& fakeLLM { forbid : true } ,
2026-07-29 21:01:37 +00:00
nil , nil )
2026-07-29 19:43:26 +00:00
prepared , err := runner . Prepare ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
SessionID : " \t " ,
Inputs : singleInputRef ( ) ,
Vars : map [ string ] string { "template_session" : "rendered" } ,
} )
if err != nil {
t . Fatalf ( "prepare with prompt session template: %v" , err )
}
if prepared . SessionID != "template-rendered" {
t . Fatalf ( "prepared session id = %q, want template-rendered" , prepared . SessionID )
}
} )
t . Run ( "overlong direct value fails before loading or generation" , func ( t * testing . T ) {
promptRepo := & fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) }
llmClient := & fakeLLM { resp : & domain . GenerateResponse { Content : "unexpected" } }
runner := NewRunner (
promptRepo ,
& fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { "exec" : defaultExecutionProfile ( ) } } ,
2026-09-30 04:18:27 +00:00
2026-07-29 19:43:26 +00:00
defaultArtifactReader ( ) ,
defaultRenderer ( ) ,
llmClient ,
2026-07-29 21:01:37 +00:00
nil , nil )
2026-07-29 19:43:26 +00:00
_ , err := runner . Run ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
SessionID : strings . Repeat ( "界" , domain . SessionIDMaxLength + 1 ) ,
Inputs : singleInputRef ( ) ,
} )
if ! errors . Is ( err , ErrInvalidRequest ) {
t . Fatalf ( "expected ErrInvalidRequest, got %v" , err )
}
if promptRepo . lastID != "" {
t . Fatalf ( "invalid direct session loaded prompt %q" , promptRepo . lastID )
}
if llmClient . calls != 0 {
t . Fatalf ( "invalid direct session invoked generation %d times" , llmClient . calls )
}
} )
2026-08-11 21:12:56 +00:00
t . Run ( "malformed direct value fails before loading or generation" , func ( t * testing . T ) {
promptRepo := & fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) }
llmClient := & fakeLLM { resp : & domain . GenerateResponse { Content : "unexpected" } }
runner := NewRunner (
promptRepo ,
& fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { "exec" : defaultExecutionProfile ( ) } } ,
2026-09-30 04:18:27 +00:00
2026-08-11 21:12:56 +00:00
defaultArtifactReader ( ) ,
defaultRenderer ( ) ,
llmClient ,
nil , nil )
_ , err := runner . Run ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
SessionID : "session" + string ( [ ] byte { 0xff } ) ,
Inputs : singleInputRef ( ) ,
} )
if ! errors . Is ( err , ErrInvalidRequest ) {
t . Fatalf ( "expected ErrInvalidRequest, got %v" , err )
}
if promptRepo . lastID != "" {
t . Fatalf ( "invalid direct session loaded prompt %q" , promptRepo . lastID )
}
if llmClient . calls != 0 {
t . Fatalf ( "invalid direct session invoked generation %d times" , llmClient . calls )
}
} )
2026-07-29 19:43:26 +00:00
}
2026-07-28 04:33:30 +00:00
func TestRunnerPrepareUsesPromptDefaultProfileWhenNoExplicitProfileID ( t * testing . T ) {
promptRepo := & fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) }
promptRepo . def . DefaultProfile = "from-prompt"
execRepo := & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile {
2026-09-30 04:18:27 +00:00
"from-prompt" : { ID : "from-prompt" , ResolvedTarget : & domain . ExecutionTarget { Endpoint : "http://llm/v1" , Model : "m" , TimeoutSeconds : defaults . ExecutionDefaultTimeoutSeconds } } ,
2026-07-28 04:33:30 +00:00
} }
runner := newMinimalRunner ( promptRepo , execRepo )
prepared , err := runner . Prepare ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
Inputs : singleInputRef ( ) ,
} )
if err != nil {
t . Fatalf ( "expected no error, got %v" , err )
}
if execRepo . lastID != "from-prompt" {
t . Fatalf ( "expected prompt default profile lookup, got %q" , execRepo . lastID )
}
if prepared . SelectedProfileID != "from-prompt" {
t . Fatalf ( "expected selected profile from-prompt, got %q" , prepared . SelectedProfileID )
}
}
func TestRunnerPrepareMissingExplicitProfileAndMissingDefaultProfileFails ( t * testing . T ) {
repo := & fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) }
repo . def . DefaultProfile = ""
runner := newMinimalRunner ( repo , & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { "exec" : defaultExecutionProfile ( ) } } )
_ , err := runner . Prepare ( context . Background ( ) , domain . RunRequest { PromptID : "p" , Inputs : singleInputRef ( ) } )
if ! errors . Is ( err , ErrInvalidRequest ) {
t . Fatalf ( "expected ErrInvalidRequest, got %v" , err )
}
if ! errors . Is ( err , ErrProfileRequired ) {
t . Fatalf ( "expected ErrProfileRequired, got %v" , err )
}
}
func TestRunnerPrepareSelectedProfileDoesNotExistFails ( t * testing . T ) {
repo := & fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) }
repo . def . DefaultProfile = "does-not-exist"
runner := newMinimalRunner ( repo , & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { } } )
_ , err := runner . Prepare ( context . Background ( ) , domain . RunRequest { PromptID : "p" , Inputs : singleInputRef ( ) } )
if ! errors . Is ( err , ErrProfileLoad ) {
t . Fatalf ( "expected ErrProfileLoad, got %v" , err )
}
}
func TestRunnerPreparePromptLoadFailure ( t * testing . T ) {
2026-09-30 04:18:27 +00:00
runner := NewRunner ( & fakePromptRepo { err : errors . New ( "boom" ) } , & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { "exec" : defaultExecutionProfile ( ) } } , defaultArtifactReader ( ) , defaultRenderer ( ) , & fakeLLM { } , nil , nil )
2026-07-28 04:33:30 +00:00
_ , err := runner . Prepare ( context . Background ( ) , domain . RunRequest { PromptID : "p" } )
if ! errors . Is ( err , ErrPromptLoad ) {
t . Fatalf ( "expected ErrPromptLoad, got %v" , err )
}
if errors . Is ( err , ErrProfileLoad ) {
t . Fatalf ( "did not expect ErrProfileLoad, got %v" , err )
}
}
func TestRunnerPrepareRuntimeOverrideBeatsSelectedProfileValue ( t * testing . T ) {
promptRepo := & fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) }
execRepo := & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile {
"exec" : {
2026-09-30 04:18:27 +00:00
ID : "exec" , ResolvedTarget : & domain . ExecutionTarget { Endpoint : "http://profile/v1" ,
Model : "profile-model" ,
Temperature : 0.2 ,
MaxTokens : 500 ,
TopP : 0.9 ,
TimeoutSeconds : 120 ,
ServiceTier : "priority" } ,
2026-07-28 04:33:30 +00:00
} ,
} }
2026-09-30 04:18:27 +00:00
runner := NewRunner ( promptRepo , execRepo , defaultArtifactReader ( ) , defaultRenderer ( ) , & fakeLLM { forbid : true } , nil , nil )
2026-07-28 04:33:30 +00:00
prepared , err := runner . Prepare ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : singleInputRef ( ) ,
Execution : & domain . ExecutionTargetOverride {
Endpoint : "http://override/v1" ,
Model : "override-model" ,
Temperature : float64Ptr ( 0.7 ) ,
TimeoutSeconds : intPtr ( 30 ) ,
ServiceTier : "flex" ,
} ,
} )
if err != nil {
t . Fatalf ( "expected no error, got %v" , err )
}
if prepared . EffectiveModelParams . Endpoint != "http://override/v1" || prepared . EffectiveModelParams . Model != "override-model" {
t . Fatalf ( "expected endpoint/model override to win, got %+v" , prepared . EffectiveModelParams )
}
if prepared . EffectiveModelParams . TopP != 0.9 {
t . Fatalf ( "expected profile top_p to remain, got %v" , prepared . EffectiveModelParams . TopP )
}
if prepared . EffectiveModelParams . ServiceTier != "flex" {
t . Fatalf ( "expected service_tier override to win, got %q" , prepared . EffectiveModelParams . ServiceTier )
}
}
func TestRunnerPrepareRequestNumericOverridePresence ( t * testing . T ) {
tests := [ ] struct {
name string
override * domain . ExecutionTargetOverride
wantTemperature float64
wantMaxTokens int
wantTopP float64
wantTimeoutSecs int
wantPresence domain . ExecutionTargetPresence
} {
{
name : "omitted preserves profile values" ,
override : & domain . ExecutionTargetOverride { } ,
wantTemperature : 0.7 ,
wantMaxTokens : 321 ,
wantTopP : 0.8 ,
wantTimeoutSecs : 45 ,
} ,
{
name : "explicit zero temperature" ,
override : & domain . ExecutionTargetOverride { Temperature : float64Ptr ( 0 ) } ,
wantTemperature : 0 ,
wantMaxTokens : 321 ,
wantTopP : 0.8 ,
wantTimeoutSecs : 45 ,
wantPresence : domain . ExecutionTargetPresence { Temperature : true } ,
} ,
{
name : "explicit zero max tokens" ,
override : & domain . ExecutionTargetOverride { MaxTokens : intPtr ( 0 ) } ,
wantTemperature : 0.7 ,
wantMaxTokens : 0 ,
wantTopP : 0.8 ,
wantTimeoutSecs : 45 ,
wantPresence : domain . ExecutionTargetPresence { MaxTokens : true } ,
} ,
{
name : "explicit zero top p" ,
override : & domain . ExecutionTargetOverride { TopP : float64Ptr ( 0 ) } ,
wantTemperature : 0.7 ,
wantMaxTokens : 321 ,
wantTopP : 0 ,
wantTimeoutSecs : 45 ,
wantPresence : domain . ExecutionTargetPresence { TopP : true } ,
} ,
{
name : "explicit zero timeout" ,
override : & domain . ExecutionTargetOverride { TimeoutSeconds : intPtr ( 0 ) } ,
wantTemperature : 0.7 ,
wantMaxTokens : 321 ,
wantTopP : 0.8 ,
wantTimeoutSecs : 0 ,
wantPresence : domain . ExecutionTargetPresence { TimeoutSeconds : true } ,
} ,
}
for _ , tc := range tests {
t . Run ( tc . name , func ( t * testing . T ) {
runner := NewRunner (
& fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) } ,
& fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile {
"exec" : {
2026-09-30 04:18:27 +00:00
ID : "exec" , ResolvedTarget : & domain . ExecutionTarget { Endpoint : "http://profile/v1" ,
Model : "profile-model" ,
Temperature : 0.7 ,
MaxTokens : 321 ,
TopP : 0.8 ,
TimeoutSeconds : 45 } ,
2026-07-28 04:33:30 +00:00
} ,
2026-09-30 04:18:27 +00:00
} } ,
2026-07-29 17:10:34 +00:00
2026-07-28 04:33:30 +00:00
defaultArtifactReader ( ) ,
defaultRenderer ( ) ,
& fakeLLM { forbid : true } ,
2026-07-29 21:01:37 +00:00
nil , nil )
2026-07-28 04:33:30 +00:00
prepared , err := runner . Prepare ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : singleInputRef ( ) ,
Execution : tc . override ,
} )
if err != nil {
t . Fatalf ( "expected no error, got %v" , err )
}
got := prepared . EffectiveModelParams
if got . Temperature != tc . wantTemperature ||
got . MaxTokens != tc . wantMaxTokens ||
got . TopP != tc . wantTopP ||
got . TimeoutSeconds != tc . wantTimeoutSecs {
t . Fatalf ( "unexpected effective numeric settings: %+v" , got )
}
if prepared . TargetPresence != tc . wantPresence {
t . Fatalf ( "unexpected target presence: got %+v want %+v" , prepared . TargetPresence , tc . wantPresence )
}
} )
}
}
func TestRunnerPrepareInvalidRequestNumericOverridesFail ( t * testing . T ) {
2026-08-11 21:12:56 +00:00
type testCase struct {
2026-07-28 04:33:30 +00:00
name string
override * domain . ExecutionTargetOverride
2026-08-11 21:12:56 +00:00
}
tests := [ ] testCase {
2026-07-28 04:33:30 +00:00
{ name : "temperature below range" , override : & domain . ExecutionTargetOverride { Temperature : float64Ptr ( - 0.1 ) } } ,
{ name : "temperature above range" , override : & domain . ExecutionTargetOverride { Temperature : float64Ptr ( 2.1 ) } } ,
{ name : "max tokens below range" , override : & domain . ExecutionTargetOverride { MaxTokens : intPtr ( - 1 ) } } ,
{ name : "top p below range" , override : & domain . ExecutionTargetOverride { TopP : float64Ptr ( - 0.1 ) } } ,
{ name : "top p above range" , override : & domain . ExecutionTargetOverride { TopP : float64Ptr ( 1.1 ) } } ,
{ name : "timeout below range" , override : & domain . ExecutionTargetOverride { TimeoutSeconds : intPtr ( - 1 ) } } ,
2026-08-11 21:12:56 +00:00
{ name : "temperature is not finite" , override : & domain . ExecutionTargetOverride { Temperature : float64Ptr ( math . NaN ( ) ) } } ,
{ name : "top p is not finite" , override : & domain . ExecutionTargetOverride { TopP : float64Ptr ( math . Inf ( 1 ) ) } } ,
}
if strconv . IntSize == 64 {
durationLimit := int64 ( math . MaxInt64 / int64 ( time . Second ) )
tests = append ( tests , testCase { name : "timeout cannot be represented as a duration" , override : & domain . ExecutionTargetOverride { TimeoutSeconds : intPtr ( int ( durationLimit ) + 1 ) } } )
2026-07-28 04:33:30 +00:00
}
for _ , tc := range tests {
t . Run ( tc . name , func ( t * testing . T ) {
runner := NewRunner (
& fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) } ,
2026-09-30 04:18:27 +00:00
& fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { "exec" : defaultExecutionProfile ( ) } } ,
2026-07-29 17:10:34 +00:00
2026-07-28 04:33:30 +00:00
defaultArtifactReader ( ) ,
defaultRenderer ( ) ,
& fakeLLM { forbid : true } ,
2026-07-29 21:01:37 +00:00
nil , nil )
2026-07-28 04:33:30 +00:00
_ , err := runner . Prepare ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : singleInputRef ( ) ,
Execution : tc . override ,
} )
if ! errors . Is ( err , ErrInvalidRequest ) {
t . Fatalf ( "expected ErrInvalidRequest, got %v" , err )
}
} )
}
}
func TestRunnerPrepareSelectedProfileBeatsBuiltInDefault ( t * testing . T ) {
promptRepo := & fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) }
execRepo := & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile {
"exec" : {
2026-09-30 04:18:27 +00:00
ID : "exec" , ResolvedTarget : & domain . ExecutionTarget { Endpoint : "http://profile/v1" ,
Model : "profile-model" ,
TopP : 0.8 ,
TimeoutSeconds : 90 ,
ServiceTier : "priority" } ,
2026-07-28 04:33:30 +00:00
} ,
} }
2026-09-30 04:18:27 +00:00
runner := NewRunner ( promptRepo , execRepo , defaultArtifactReader ( ) , defaultRenderer ( ) , & fakeLLM { forbid : true } , nil , nil )
2026-07-28 04:33:30 +00:00
prepared , err := runner . Prepare ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : singleInputRef ( ) ,
} )
if err != nil {
t . Fatalf ( "expected no error, got %v" , err )
}
if prepared . EffectiveModelParams . TopP != 0.8 {
t . Fatalf ( "expected profile top_p to beat default, got %v" , prepared . EffectiveModelParams . TopP )
}
if prepared . EffectiveModelParams . TimeoutSeconds != 90 {
t . Fatalf ( "expected profile timeout to beat default, got %d" , prepared . EffectiveModelParams . TimeoutSeconds )
}
if prepared . EffectiveModelParams . ServiceTier != "priority" {
t . Fatalf ( "expected profile service_tier to beat default, got %q" , prepared . EffectiveModelParams . ServiceTier )
}
}
func TestRunnerPrepareRequiredInputMissingFails ( t * testing . T ) {
def := promptDef ( domain . FormatText , domain . ValidationNone , 0 )
def . Templates = [ ] domain . PromptMessageTemplate { { Role : "user" , Content : ` {{ input "transcript" }} ` } }
runner := NewRunner (
& fakePromptRepo { def : def } ,
2026-09-30 04:18:27 +00:00
& fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { "exec" : defaultExecutionProfile ( ) } } ,
2026-07-29 17:10:34 +00:00
2026-07-28 04:33:30 +00:00
defaultArtifactReader ( ) ,
prompt . NewGoRenderer ( ) ,
& fakeLLM { forbid : true } ,
2026-07-29 21:01:37 +00:00
nil , nil )
2026-07-29 17:10:34 +00:00
2026-07-28 04:33:30 +00:00
_ , err := runner . Prepare ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : map [ string ] domain . ArtifactRef { } ,
} )
if ! errors . Is ( err , ErrPromptRender ) {
t . Fatalf ( "expected ErrPromptRender, got %v" , err )
}
if ! errors . Is ( err , prompt . ErrMissingRequiredInput ) {
t . Fatalf ( "expected ErrMissingRequiredInput, got %v" , err )
}
}
func TestRunnerPrepareUnknownTemplateInputReferenceFails ( t * testing . T ) {
def := promptDef ( domain . FormatText , domain . ValidationNone , 0 )
def . Inputs = [ ] domain . PromptInput { { Name : "transcript" , Required : false } }
def . Templates = [ ] domain . PromptMessageTemplate { { Role : "user" , Content : ` {{ input "ghost" }} ` } }
runner := NewRunner (
& fakePromptRepo { def : def } ,
2026-09-30 04:18:27 +00:00
& fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { "exec" : defaultExecutionProfile ( ) } } ,
2026-07-29 17:10:34 +00:00
2026-07-28 04:33:30 +00:00
defaultArtifactReader ( ) ,
prompt . NewGoRenderer ( ) ,
& fakeLLM { forbid : true } ,
2026-07-29 21:01:37 +00:00
nil , nil )
2026-07-29 17:10:34 +00:00
2026-07-28 04:33:30 +00:00
_ , err := runner . Prepare ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : map [ string ] domain . ArtifactRef { } ,
} )
if ! errors . Is ( err , ErrPromptRender ) {
t . Fatalf ( "expected ErrPromptRender, got %v" , err )
}
if ! errors . Is ( err , prompt . ErrUnknownInput ) {
t . Fatalf ( "expected ErrUnknownInput, got %v" , err )
}
}
func TestRunnerPrepareAPIKeyEnvNameIncludedButNotResolvedValue ( t * testing . T ) {
const envName = "PROMPTKIT_TEST_API_KEY"
const secret = "top-secret-value"
t . Setenv ( envName , secret )
promptRepo := & fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) }
execRepo := & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile {
2026-09-30 04:18:27 +00:00
"exec" : { ID : "exec" , ResolvedTarget : & domain . ExecutionTarget { Endpoint : "http://profile/v1" , Model : "profile-model" , APIKeyEnv : envName , TimeoutSeconds : defaults . ExecutionDefaultTimeoutSeconds } } ,
2026-07-28 04:33:30 +00:00
} }
2026-09-30 04:18:27 +00:00
runner := NewRunner ( promptRepo , execRepo , defaultArtifactReader ( ) , defaultRenderer ( ) , & fakeLLM { forbid : true } , nil , nil )
2026-07-28 04:33:30 +00:00
prepared , err := runner . Prepare ( context . Background ( ) , domain . RunRequest { PromptID : "p" , ProfileID : "exec" , Inputs : singleInputRef ( ) } )
if err != nil {
t . Fatalf ( "expected no error, got %v" , err )
}
if prepared . EffectiveModelParams . APIKeyEnv != envName {
t . Fatalf ( "expected api key env name, got %q" , prepared . EffectiveModelParams . APIKeyEnv )
}
metadataDump := fmt . Sprintf ( "%+v|%s|%s" , prepared . EffectiveModelParams , prepared . PromptHash , prepared . RenderedPromptHash )
if strings . Contains ( metadataDump , secret ) {
t . Fatalf ( "unexpected api key value in prepared metadata dump: %s" , metadataDump )
}
}
func TestRunnerPrepareJSONSchemaBuildsStructuredOutputSpec ( t * testing . T ) {
def := promptDef ( domain . FormatJSON , domain . ValidationJSONSchema , 0 )
def . Validation . SchemaPath = "events.schema.json"
validator := & fakeValidator {
schemaDoc : map [ string ] any {
"type" : "object" ,
"properties" : map [ string ] any {
"events" : map [ string ] any { "type" : "array" } ,
} ,
} ,
}
runner := NewRunner (
& fakePromptRepo { def : def } ,
2026-09-30 04:18:27 +00:00
& fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { "exec" : defaultExecutionProfile ( ) } } ,
2026-07-29 17:10:34 +00:00
2026-07-28 04:33:30 +00:00
defaultArtifactReader ( ) ,
defaultRenderer ( ) ,
& fakeLLM { forbid : true } ,
2026-07-29 21:01:37 +00:00
validator , nil )
2026-07-28 04:33:30 +00:00
prepared , err := runner . Prepare ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : singleInputRef ( ) ,
} )
if err != nil {
t . Fatalf ( "expected no error, got %v" , err )
}
if validator . schemaLoads != 1 {
t . Fatalf ( "expected one schema load, got %d" , validator . schemaLoads )
}
if validator . schemaLoadPath != "events.schema.json" {
t . Fatalf ( "expected schema path events.schema.json, got %q" , validator . schemaLoadPath )
}
if prepared . StructuredOutput == nil {
t . Fatal ( "expected structured output spec" )
}
if prepared . StructuredOutput . Type != domain . StructuredOutputJSONSchema {
t . Fatalf ( "expected structured output type json_schema, got %q" , prepared . StructuredOutput . Type )
}
if prepared . StructuredOutput . JSONSchema == nil {
t . Fatal ( "expected structured output json_schema payload" )
}
2026-10-17 05:47:14 +00:00
if prepared . StructuredOutput . JSONSchema . Name != "p" {
t . Fatalf ( "expected derived schema name p, got %q" , prepared . StructuredOutput . JSONSchema . Name )
2026-07-28 04:33:30 +00:00
}
if prepared . StructuredOutput . JSONSchema . Strict != true {
t . Fatalf ( "expected strict=true, got %v" , prepared . StructuredOutput . JSONSchema . Strict )
}
}
func TestRunnerPrepareJSONSchemaSchemaLoadFailureReturnsValidationError ( t * testing . T ) {
def := promptDef ( domain . FormatJSON , domain . ValidationJSONSchema , 0 )
def . Validation . SchemaPath = "missing.schema.json"
validator := & fakeValidator { schemaErr : errors . New ( "schema unavailable" ) }
runner := NewRunner (
& fakePromptRepo { def : def } ,
2026-09-30 04:18:27 +00:00
& fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { "exec" : defaultExecutionProfile ( ) } } ,
2026-07-29 17:10:34 +00:00
2026-07-28 04:33:30 +00:00
defaultArtifactReader ( ) ,
defaultRenderer ( ) ,
& fakeLLM { forbid : true } ,
2026-07-29 21:01:37 +00:00
validator , nil )
2026-07-28 04:33:30 +00:00
_ , err := runner . Prepare ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : singleInputRef ( ) ,
} )
if ! errors . Is ( err , ErrValidation ) {
t . Fatalf ( "expected ErrValidation, got %v" , err )
}
if validator . schemaLoads != 1 {
t . Fatalf ( "expected one schema load attempt, got %d" , validator . schemaLoads )
}
if validator . schemaLoadPath != "missing.schema.json" {
t . Fatalf ( "expected schema path missing.schema.json, got %q" , validator . schemaLoadPath )
}
}
func TestRunnerRunJSONSchemaSchemaLoadFailureFailsBeforeLLM ( t * testing . T ) {
def := promptDef ( domain . FormatJSON , domain . ValidationJSONSchema , 0 )
def . Validation . SchemaPath = "missing.schema.json"
llmClient := & fakeLLM { forbid : true }
validator := & fakeValidator { schemaErr : errors . New ( "schema unavailable" ) }
runner := NewRunner (
& fakePromptRepo { def : def } ,
2026-09-30 04:18:27 +00:00
& fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { "exec" : defaultExecutionProfile ( ) } } ,
2026-07-29 17:10:34 +00:00
2026-07-28 04:33:30 +00:00
defaultArtifactReader ( ) ,
defaultRenderer ( ) ,
llmClient ,
2026-07-29 21:01:37 +00:00
validator , nil )
2026-07-28 04:33:30 +00:00
_ , err := runner . Run ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : singleInputRef ( ) ,
} )
if ! errors . Is ( err , ErrValidation ) {
t . Fatalf ( "expected ErrValidation, got %v" , err )
}
if llmClient . calls != 0 {
t . Fatalf ( "expected llm not called when schema loading fails, calls=%d" , llmClient . calls )
}
}
func TestDeriveStructuredSchemaName ( t * testing . T ) {
tests := [ ] struct {
2026-10-17 05:47:14 +00:00
name string
id string
want string
2026-07-28 04:33:30 +00:00
} {
{
2026-10-17 05:47:14 +00:00
name : "sanitizes punctuation and keeps dashes" ,
id : "prompt.id/alpha" ,
want : "prompt_id_alpha" ,
2026-07-28 04:33:30 +00:00
} ,
{
2026-10-17 05:47:14 +00:00
name : "fallback when empty" ,
id : "" ,
want : "promptkit_schema" ,
2026-07-28 04:33:30 +00:00
} ,
}
for _ , tc := range tests {
t . Run ( tc . name , func ( t * testing . T ) {
2026-10-17 05:47:14 +00:00
got := deriveStructuredSchemaName ( tc . id )
2026-07-28 04:33:30 +00:00
if got != tc . want {
t . Fatalf ( "expected %q, got %q" , tc . want , got )
}
} )
}
}
2026-08-26 02:16:16 +00:00
func TestHashRenderedPromptIncludesEveryContractedField ( t * testing . T ) {
base := domain . RenderedPrompt { Messages : [ ] domain . RenderedMessage {
{ Role : domain . RoleSystem , Content : "sys" } ,
{ Role : domain . RoleUser , Content : "usr" } ,
} }
identical := domain . RenderedPrompt { Messages : [ ] domain . RenderedMessage {
{ Role : domain . RoleSystem , Content : "sys" } ,
{ Role : domain . RoleUser , Content : "usr" } ,
2026-07-28 04:33:30 +00:00
} }
2026-08-26 02:16:16 +00:00
baseHash := hashRenderedPrompt ( base )
if baseHash != hashRenderedPrompt ( identical ) {
t . Fatal ( "identical rendered prompts must have the same hash" )
2026-07-28 04:33:30 +00:00
}
withCache := domain . RenderedPrompt { Messages : [ ] domain . RenderedMessage {
{
Role : "system" ,
Content : "sys" ,
CacheControl : & domain . CacheControl {
Type : domain . CacheControlEphemeral ,
TTL : "1h" ,
} ,
} ,
2026-08-26 02:16:16 +00:00
{ Role : domain . RoleUser , Content : "usr" } ,
2026-07-28 04:33:30 +00:00
} }
alsoWithCache := domain . RenderedPrompt { Messages : [ ] domain . RenderedMessage {
{
Role : "system" ,
Content : "sys" ,
CacheControl : & domain . CacheControl {
Type : domain . CacheControlEphemeral ,
TTL : "1h" ,
} ,
} ,
2026-08-26 02:16:16 +00:00
{ Role : domain . RoleUser , Content : "usr" } ,
2026-07-28 04:33:30 +00:00
} }
withoutTTL := domain . RenderedPrompt { Messages : [ ] domain . RenderedMessage {
{
Role : "system" ,
Content : "sys" ,
CacheControl : & domain . CacheControl {
Type : domain . CacheControlEphemeral ,
} ,
} ,
2026-08-26 02:16:16 +00:00
{ Role : domain . RoleUser , Content : "usr" } ,
2026-07-28 04:33:30 +00:00
} }
cachedHash := hashRenderedPrompt ( withCache )
2026-08-26 02:16:16 +00:00
if cachedHash == baseHash {
2026-07-28 04:33:30 +00:00
t . Fatal ( "expected cache control to change rendered prompt hash" )
}
if cachedHash != hashRenderedPrompt ( alsoWithCache ) {
t . Fatal ( "expected identical cache control metadata to produce stable hash" )
}
if cachedHash == hashRenderedPrompt ( withoutTTL ) {
t . Fatal ( "expected ttl changes to affect rendered prompt hash" )
}
2026-08-26 02:16:16 +00:00
variants := [ ] struct {
name string
prompt domain . RenderedPrompt
} {
{ name : "role" , prompt : domain . RenderedPrompt { Messages : [ ] domain . RenderedMessage { { Role : domain . RoleDeveloper , Content : "sys" } , { Role : domain . RoleUser , Content : "usr" } } } } ,
{ name : "content" , prompt : domain . RenderedPrompt { Messages : [ ] domain . RenderedMessage { { Role : domain . RoleSystem , Content : "changed" } , { Role : domain . RoleUser , Content : "usr" } } } } ,
{ name : "order" , prompt : domain . RenderedPrompt { Messages : [ ] domain . RenderedMessage { { Role : domain . RoleUser , Content : "usr" } , { Role : domain . RoleSystem , Content : "sys" } } } } ,
{ name : "session" , prompt : domain . RenderedPrompt { SessionID : "session" , Messages : base . Messages } } ,
}
for _ , variant := range variants {
t . Run ( variant . name , func ( t * testing . T ) {
if hashRenderedPrompt ( variant . prompt ) == baseHash {
t . Fatalf ( "%s did not change the rendered-prompt hash" , variant . name )
}
} )
}
oneMessage := domain . RenderedPrompt { Messages : [ ] domain . RenderedMessage { { Role : domain . RoleUser , Content : "x\n---\nassistant\ny" } } }
twoMessages := domain . RenderedPrompt { Messages : [ ] domain . RenderedMessage { { Role : domain . RoleUser , Content : "x" } , { Role : domain . RoleAssistant , Content : "y" } } }
if hashRenderedPrompt ( oneMessage ) == hashRenderedPrompt ( twoMessages ) {
t . Fatal ( "length-framed hashing did not distinguish legacy separator collision" )
}
2026-07-28 04:33:30 +00:00
}
func TestHashRenderedPromptIncludesSessionIDWhenPresent ( t * testing . T ) {
withoutSession := domain . RenderedPrompt { Messages : [ ] domain . RenderedMessage {
{ Role : "system" , Content : "sys" } ,
{ Role : "user" , Content : "usr" } ,
} }
withSession := domain . RenderedPrompt {
SessionID : "session-123" ,
Messages : [ ] domain . RenderedMessage {
{ Role : "system" , Content : "sys" } ,
{ Role : "user" , Content : "usr" } ,
} ,
}
alsoWithSession := domain . RenderedPrompt {
SessionID : "session-123" ,
Messages : [ ] domain . RenderedMessage {
{ Role : "system" , Content : "sys" } ,
{ Role : "user" , Content : "usr" } ,
} ,
}
otherSession := domain . RenderedPrompt {
SessionID : "session-456" ,
Messages : [ ] domain . RenderedMessage {
{ Role : "system" , Content : "sys" } ,
{ Role : "user" , Content : "usr" } ,
} ,
}
sessionHash := hashRenderedPrompt ( withSession )
if sessionHash == hashRenderedPrompt ( withoutSession ) {
t . Fatal ( "expected session_id to change rendered prompt hash" )
}
if sessionHash != hashRenderedPrompt ( alsoWithSession ) {
t . Fatal ( "expected identical session_id to produce stable hash" )
}
if sessionHash == hashRenderedPrompt ( otherSession ) {
t . Fatal ( "expected session_id value changes to affect rendered prompt hash" )
}
}
2026-08-26 02:16:16 +00:00
func TestRunnerComposesAppendedMessagesIntoEveryRenderedPrompt ( t * testing . T ) {
renderer := & fakeRenderer { rendered : & domain . RenderedPrompt {
SessionID : "rendered-session" ,
Messages : [ ] domain . RenderedMessage {
{ Role : domain . RoleSystem , Content : "ordinary prefix" , CacheControl : & domain . CacheControl { Type : domain . CacheControlEphemeral , TTL : "1h" } } ,
{ Role : domain . RoleUser , Content : "ordinary request" } ,
} ,
} }
client := & fakeLLM { resp : & domain . GenerateResponse { Content : "output" } }
runner := NewRunner (
& fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) } ,
& fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { "exec" : defaultExecutionProfile ( ) } } ,
2026-09-30 04:18:27 +00:00
2026-08-26 02:16:16 +00:00
defaultArtifactReader ( ) ,
renderer ,
client ,
nil ,
nil ,
)
appended := [ ] domain . RenderedMessage {
{ Role : domain . RoleAssistant , Content : "consumer response" } ,
{ Role : domain . RoleUser , Content : "consumer correction" , CacheControl : & domain . CacheControl { Type : domain . CacheControlEphemeral } } ,
}
request := domain . RunRequest { PromptID : "p" , ProfileID : "exec" , Inputs : singleInputRef ( ) , AppendedMessages : appended }
plain , err := runner . Prepare ( context . Background ( ) , domain . RunRequest { PromptID : "p" , ProfileID : "exec" , Inputs : singleInputRef ( ) } )
if err != nil {
t . Fatalf ( "prepare without appended messages: %v" , err )
}
empty , err := runner . Prepare ( context . Background ( ) , domain . RunRequest { PromptID : "p" , ProfileID : "exec" , Inputs : singleInputRef ( ) , AppendedMessages : [ ] domain . RenderedMessage { } } )
if err != nil {
t . Fatalf ( "prepare with empty appended messages: %v" , err )
}
if ! reflect . DeepEqual ( empty . Messages , plain . Messages ) || empty . RenderedPromptHash != plain . RenderedPromptHash {
t . Fatalf ( "empty appended messages changed preparation: empty=%#v plain=%#v" , empty , plain )
}
prepared , err := runner . Prepare ( context . Background ( ) , request )
if err != nil {
t . Fatalf ( "prepare with appended messages: %v" , err )
}
if prepared . PromptHash != plain . PromptHash || prepared . RenderedPromptHash == plain . RenderedPromptHash {
t . Fatalf ( "hashes with appended messages = (%q, %q), plain = (%q, %q)" , prepared . PromptHash , prepared . RenderedPromptHash , plain . PromptHash , plain . RenderedPromptHash )
}
expected := [ ] domain . RenderedMessage {
{ Role : domain . RoleSystem , Content : "ordinary prefix" , CacheControl : & domain . CacheControl { Type : domain . CacheControlEphemeral , TTL : "1h" } } ,
{ Role : domain . RoleUser , Content : "ordinary request" } ,
{ Role : domain . RoleAssistant , Content : "consumer response" } ,
{ Role : domain . RoleUser , Content : "consumer correction" , CacheControl : & domain . CacheControl { Type : domain . CacheControlEphemeral } } ,
}
if ! reflect . DeepEqual ( prepared . Messages , expected ) {
t . Fatalf ( "prepared messages = %#v, want %#v" , prepared . Messages , expected )
}
result , err := runner . Run ( context . Background ( ) , request )
if err != nil {
t . Fatalf ( "run with appended messages: %v" , err )
}
if result . RenderedPromptHash != prepared . RenderedPromptHash || ! reflect . DeepEqual ( client . lastReq . Prompt . Messages , expected ) {
t . Fatalf ( "run did not use the prepared effective prompt: result=%#v request=%#v prepared=%#v" , result , client . lastReq . Prompt . Messages , prepared )
}
renderer . rendered . Messages [ 0 ] . Content = "changed source"
appended [ 1 ] . CacheControl . Type = "changed caller value"
if ! reflect . DeepEqual ( prepared . Messages , expected ) {
t . Fatalf ( "prepared messages changed after source or caller mutation: %#v" , prepared . Messages )
}
}
2026-07-28 04:33:30 +00:00
func TestRunnerRunSuccessful ( t * testing . T ) {
promptRepo := & fakePromptRepo { def : promptDef ( domain . FormatMarkdown , domain . ValidationBasic , 0 ) }
execRepo := & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { "exec" : defaultExecutionProfile ( ) } }
reader := & fakeArtifactReader { artifactsByURI : map [ string ] * domain . Artifact {
"a://t" : { Body : [ ] byte ( "transcript" ) , Hash : hashString ( "transcript" ) } ,
"a://g" : { Body : [ ] byte ( "glossary" ) , Hash : hashString ( "glossary" ) } ,
} }
renderer := & fakeRenderer { rendered : & domain . RenderedPrompt { SessionID : "session-123" , Messages : [ ] domain . RenderedMessage { { Role : "system" , Content : "sys" } , { Role : "user" , Content : "usr" } } } }
llmClient := & fakeLLM { resp : & domain . GenerateResponse { Content : "# recap" , Usage : domain . TokenUsage { TotalTokens : 7 } } }
2026-09-30 04:18:27 +00:00
runner := NewRunner ( promptRepo , execRepo , reader , renderer , llmClient , nil , nil )
2026-07-28 04:33:30 +00:00
res , err := runner . Run ( context . Background ( ) , domain . RunRequest {
2026-10-17 05:47:14 +00:00
PromptID : "p" ,
ProfileID : "exec" ,
2026-07-28 04:33:30 +00:00
Inputs : map [ string ] domain . ArtifactRef {
"transcript" : { Type : domain . ArtifactRefFile , URI : "a://t" } ,
"glossary" : { Type : domain . ArtifactRefFile , URI : "a://g" } ,
} ,
Execution : & domain . ExecutionTargetOverride { Endpoint : "http://override/v1" , Model : "m" , Temperature : float64Ptr ( 0.3 ) , TimeoutSeconds : intPtr ( 90 ) } ,
} )
if err != nil {
t . Fatalf ( "expected no error, got %v" , err )
}
2026-10-17 05:54:32 +00:00
if res . PromptID != "p" || res . PromptVersion == nil || * res . PromptVersion != "1" {
2026-07-28 04:33:30 +00:00
t . Fatalf ( "unexpected prompt metadata: %+v" , res )
}
if res . SelectedProfileID != "exec" {
t . Fatalf ( "expected selected profile exec, got %q" , res . SelectedProfileID )
}
if ok , _ := regexp . MatchString ( ` ^[0-9a-f] { 8}-[0-9a-f] { 4}-4[0-9a-f] { 3}-[89ab][0-9a-f] { 3}-[0-9a-f] { 12}$ ` , res . RunID ) ; ! ok {
t . Fatalf ( "invalid run id: %q" , res . RunID )
}
if res . PromptHash == "" || res . RenderedPromptHash == "" {
t . Fatal ( "expected prompt hashes" )
}
if res . EffectiveModelParams . Model != "m" || res . Endpoint != "http://override/v1" {
t . Fatalf ( "unexpected model params: %+v" , res . EffectiveModelParams )
}
if res . Artifact . Name != defaults . OutputArtifactName {
t . Fatalf ( "expected default output artifact name %q, got %q" , defaults . OutputArtifactName , res . Artifact . Name )
}
if res . Artifact . ContentType != defaults . ContentTypeTextMarkdown {
t . Fatalf ( "expected markdown content type %q, got %q" , defaults . ContentTypeTextMarkdown , res . Artifact . ContentType )
}
if res . RawOutput != "# recap" {
t . Fatalf ( "expected raw output, got %q" , res . RawOutput )
}
if res . Validation . Status != domain . ValidationSkipped {
t . Fatalf ( "expected skipped validation, got %q" , res . Validation . Status )
}
if llmClient . lastReq . Target . TimeoutSeconds != 90 {
t . Fatalf ( "expected timeout propagation, got %d" , llmClient . lastReq . Target . TimeoutSeconds )
}
if ! llmClient . lastReq . TargetPresence . Temperature || ! llmClient . lastReq . TargetPresence . TimeoutSeconds {
t . Fatalf ( "expected numeric override presence to be sent to llm, got %+v" , llmClient . lastReq . TargetPresence )
}
if llmClient . lastReq . Prompt . SessionID != "session-123" {
t . Fatalf ( "expected session id to be sent to llm, got %q" , llmClient . lastReq . Prompt . SessionID )
}
2026-07-29 19:43:26 +00:00
if res . SessionID != "session-123" {
t . Fatalf ( "expected session id in run result, got %q" , res . SessionID )
}
2026-07-28 04:33:30 +00:00
if res . Usage . TotalTokens != 7 {
t . Fatalf ( "expected token usage to be retained, got %+v" , res . Usage )
}
if res . StartTime . IsZero ( ) || res . EndTime . IsZero ( ) || res . EndTime . Before ( res . StartTime ) {
t . Fatalf ( "unexpected run timing: start=%v end=%v" , res . StartTime , res . EndTime )
}
if res . Duration != res . EndTime . Sub ( res . StartTime ) {
t . Fatalf ( "expected duration %v, got %v" , res . EndTime . Sub ( res . StartTime ) , res . Duration )
}
}
func TestRunnerRunPassesExtraParamsToGenerateRequestTarget ( t * testing . T ) {
extraParams := map [ string ] any {
"string_value" : "enabled" ,
"number_value" : 42 ,
"boolean_value" : true ,
"object_value" : map [ string ] any { "nested" : "value" } ,
"array_value" : [ ] any { "first" , 3 , false } ,
}
promptRepo := & fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) }
execRepo := & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile {
"exec" : {
2026-09-30 04:18:27 +00:00
ID : "exec" , ResolvedTarget : & domain . ExecutionTarget { Endpoint : "http://profile/v1" ,
Model : "profile-model" ,
ExtraParams : extraParams , TimeoutSeconds : defaults . ExecutionDefaultTimeoutSeconds } ,
2026-07-28 04:33:30 +00:00
} ,
} }
llmClient := & fakeLLM { resp : & domain . GenerateResponse { Content : "ok" } }
2026-09-30 04:18:27 +00:00
runner := NewRunner ( promptRepo , execRepo , defaultArtifactReader ( ) , defaultRenderer ( ) , llmClient , nil , nil )
2026-07-28 04:33:30 +00:00
res , err := runner . Run ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : singleInputRef ( ) ,
} )
if err != nil {
t . Fatalf ( "expected no error, got %v" , err )
}
if ! reflect . DeepEqual ( res . EffectiveModelParams . ExtraParams , extraParams ) {
t . Fatalf ( "expected run result extra_params to match profile values, got %#v" , res . EffectiveModelParams . ExtraParams )
}
if ! reflect . DeepEqual ( llmClient . lastReq . Target . ExtraParams , extraParams ) {
t . Fatalf ( "expected generate request extra_params to match profile values, got %#v" , llmClient . lastReq . Target . ExtraParams )
}
}
func TestRunnerRunAndPrepareResolveSameProfileAndEffectiveSettings ( t * testing . T ) {
promptRepo := & fakePromptRepo { def : promptDef ( domain . FormatMarkdown , domain . ValidationBasic , 0 ) }
execRepo := & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { "exec" : defaultExecutionProfile ( ) } }
reader := & fakeArtifactReader { artifactsByURI : map [ string ] * domain . Artifact {
"a://t" : { Body : [ ] byte ( "transcript" ) , Hash : hashString ( "transcript" ) } ,
} }
renderer := & fakeRenderer { rendered : & domain . RenderedPrompt { Messages : [ ] domain . RenderedMessage { { Role : "system" , Content : "sys" } , { Role : "user" , Content : "usr" } } } }
llmClient := & fakeLLM { resp : & domain . GenerateResponse { Content : "# recap" } }
2026-09-30 04:18:27 +00:00
runner := NewRunner ( promptRepo , execRepo , reader , renderer , llmClient , nil , nil )
2026-07-28 04:33:30 +00:00
req := domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : map [ string ] domain . ArtifactRef {
"transcript" : { Type : domain . ArtifactRefFile , URI : "a://t" } ,
} ,
Execution : & domain . ExecutionTargetOverride { Endpoint : "http://override/v1" , Model : "m" , Temperature : float64Ptr ( 0.3 ) , TimeoutSeconds : intPtr ( 90 ) } ,
}
prepared , err := runner . Prepare ( context . Background ( ) , req )
if err != nil {
t . Fatalf ( "prepare should succeed, got %v" , err )
}
res , err := runner . Run ( context . Background ( ) , req )
if err != nil {
t . Fatalf ( "run should succeed, got %v" , err )
}
if res . SelectedProfileID != prepared . SelectedProfileID {
t . Fatalf ( "expected selected profile to match prepare, run=%q prepare=%q" , res . SelectedProfileID , prepared . SelectedProfileID )
}
if ! reflect . DeepEqual ( res . EffectiveModelParams , prepared . EffectiveModelParams ) {
t . Fatalf ( "effective model params mismatch:\nrun=%+v\nprepare=%+v" , res . EffectiveModelParams , prepared . EffectiveModelParams )
}
if ! reflect . DeepEqual ( res . InputHashes , prepared . InputHashes ) {
t . Fatalf ( "input hashes mismatch:\nrun=%#v\nprepare=%#v" , res . InputHashes , prepared . InputHashes )
}
if res . RenderedPromptHash != prepared . RenderedPromptHash {
t . Fatalf ( "expected rendered prompt hash to match prepare, run=%q prepare=%q" , res . RenderedPromptHash , prepared . RenderedPromptHash )
}
if ! reflect . DeepEqual ( llmClient . lastReq . Prompt . Messages , prepared . Messages ) {
t . Fatalf ( "expected run to send prepare-rendered messages to llm" )
}
}
2026-07-29 21:01:37 +00:00
func TestRunnerAdmissionUsesResolvedBackendIdentity ( t * testing . T ) {
t . Run ( "selected backend survives endpoint override" , func ( t * testing . T ) {
admitter := & fakeRunAdmitter { }
runner := NewRunner (
& fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) } ,
& fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile {
"exec" : {
2026-09-30 04:18:27 +00:00
ID : "exec" , ResolvedTarget : & domain . ExecutionTarget { BackendID : "custom" ,
Model : "model" , TimeoutSeconds : defaults . ExecutionDefaultTimeoutSeconds } ,
2026-07-29 21:01:37 +00:00
} ,
} } ,
2026-09-30 04:18:27 +00:00
2026-07-29 21:01:37 +00:00
defaultArtifactReader ( ) ,
defaultRenderer ( ) ,
& fakeLLM { resp : & domain . GenerateResponse { Content : "ok" } } ,
nil ,
admitter ,
)
result , err := runner . Run ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : singleInputRef ( ) ,
Execution : & domain . ExecutionTargetOverride {
Endpoint : "http://override.example/v1" ,
} ,
} )
if err != nil {
t . Fatalf ( "run: %v" , err )
}
if ! reflect . DeepEqual ( admitter . backendIDs , [ ] string { "custom" } ) {
t . Fatalf ( "admitted backend IDs=%#v, want custom" , admitter . backendIDs )
}
if result . SelectedBackendID != "custom" ||
result . Endpoint != "http://override.example/v1" {
t . Fatalf ( "unexpected routed result: %+v" , result )
}
} )
t . Run ( "endpoint-only preparation remains unrestricted" , func ( t * testing . T ) {
admitter := & fakeRunAdmitter { }
runner := NewRunner (
& fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) } ,
& fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile {
"exec" : defaultExecutionProfile ( ) ,
} } ,
2026-09-30 04:18:27 +00:00
2026-07-29 21:01:37 +00:00
defaultArtifactReader ( ) ,
defaultRenderer ( ) ,
& fakeLLM { resp : & domain . GenerateResponse { Content : "ok" } } ,
nil ,
admitter ,
)
request := domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : singleInputRef ( ) ,
}
if _ , err := runner . Prepare ( context . Background ( ) , request ) ; err != nil {
t . Fatalf ( "prepare: %v" , err )
}
if len ( admitter . backendIDs ) != 0 {
t . Fatalf ( "prepare called admission with %#v" , admitter . backendIDs )
}
if _ , err := runner . Run ( context . Background ( ) , request ) ; err != nil {
t . Fatalf ( "run: %v" , err )
}
if ! reflect . DeepEqual ( admitter . backendIDs , [ ] string { "" } ) {
t . Fatalf ( "admitted backend IDs=%#v, want blank ID" , admitter . backendIDs )
}
} )
}
func TestRunnerAdmissionFailureSkipsCompletionCollaborators ( t * testing . T ) {
tests := [ ] struct {
2026-07-30 23:21:27 +00:00
name string
admissionError error
wantCapacityType bool
2026-07-29 21:01:37 +00:00
} {
{
2026-07-30 23:21:27 +00:00
name : "capacity exhausted" ,
admissionError : capacity . ErrCapacityExceeded ,
wantCapacityType : true ,
2026-07-29 21:01:37 +00:00
} ,
{
name : "context canceled" ,
admissionError : context . Canceled ,
} ,
}
for _ , tc := range tests {
t . Run ( tc . name , func ( t * testing . T ) {
def := promptDef ( domain . FormatJSON , domain . ValidationJSONSchema , 1 )
def . Validation . SchemaPath = "schema.json"
reader := defaultArtifactReader ( )
renderer := defaultRenderer ( )
llmClient := & fakeLLM { resp : & domain . GenerateResponse { Content : ` { } ` } }
validator := & fakeValidator { }
repairer := & fakeRepairer {
responses : [ ] * domain . GenerateResponse { { Content : ` { } ` } } ,
}
admitter := & fakeRunAdmitter { err : tc . admissionError }
runner := NewRunnerWithRepairer (
& fakePromptRepo { def : def } ,
& fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile {
2026-09-30 04:18:27 +00:00
"exec" : { ID : "exec" , ResolvedTarget : & domain . ExecutionTarget { BackendID : "custom" , Endpoint : "http://backend.example/v1" , Model : "model" } } ,
2026-07-29 21:01:37 +00:00
} } ,
2026-09-30 04:18:27 +00:00
2026-07-29 21:01:37 +00:00
reader ,
renderer ,
llmClient ,
validator ,
repairer ,
admitter ,
)
result , err := runner . Run ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : singleInputRef ( ) ,
} )
if result != nil {
t . Fatalf ( "admission failure returned partial result: %+v" , result )
}
if ! errors . Is ( err , tc . admissionError ) {
t . Fatalf ( "admission error=%v, want identity %v" , err , tc . admissionError )
}
if errors . Is ( err , ErrInvalidRequest ) || errors . Is ( err , ErrLLMGenerate ) {
t . Fatalf ( "admission error was recategorized: %v" , err )
}
2026-07-30 23:21:27 +00:00
var capacityErr * CapacityError
if tc . wantCapacityType {
if ! errors . As ( err , & capacityErr ) {
t . Fatalf ( "capacity error=%v, want internal typed identity" , err )
}
if capacityErr . BackendID != "custom" {
t . Fatalf ( "capacity backend ID=%q, want custom" , capacityErr . BackendID )
}
} else if errors . As ( err , & capacityErr ) {
t . Fatalf ( "non-capacity admission error exposed typed capacity identity: %v" , err )
2026-07-29 21:01:37 +00:00
}
if ! reflect . DeepEqual ( admitter . backendIDs , [ ] string { "custom" } ) {
t . Fatalf ( "admitted backend IDs=%#v, want custom" , admitter . backendIDs )
}
if admitter . releaseCalls != 0 ||
validator . schemaLoads != 0 ||
validator . validateCalls != 0 ||
reader . calls != 0 ||
renderer . calls != 0 ||
llmClient . calls != 0 ||
repairer . calls != 0 {
t . Fatalf (
"later collaborators invoked: releases=%d schema=%d validate=%d artifacts=%d render=%d llm=%d repair=%d" ,
admitter . releaseCalls ,
validator . schemaLoads ,
validator . validateCalls ,
reader . calls ,
renderer . calls ,
llmClient . calls ,
repairer . calls ,
)
}
} )
}
}
func TestRunnerReleasesAdmissionAcrossRunOutcomes ( t * testing . T ) {
artifactFailure := errors . New ( "artifact failed" )
generationFailure := errors . New ( "generation failed" )
validationFailure := errors . New ( "validation failed" )
tests := [ ] struct {
name string
artifactError error
generationErr error
validationErr error
wantError error
} {
{ name : "success" } ,
{
name : "completion failure" ,
artifactError : artifactFailure ,
wantError : ErrArtifactLoad ,
} ,
{
name : "generation failure" ,
generationErr : generationFailure ,
wantError : ErrLLMGenerate ,
} ,
{
name : "validation failure" ,
validationErr : validationFailure ,
wantError : ErrValidation ,
} ,
}
for _ , tc := range tests {
t . Run ( tc . name , func ( t * testing . T ) {
reader := defaultArtifactReader ( )
if tc . artifactError != nil {
reader . errByURI = map [ string ] error { "a://ok" : tc . artifactError }
}
llmClient := & fakeLLM {
resp : & domain . GenerateResponse { Content : "ok" } ,
err : tc . generationErr ,
}
validator := & fakeValidator {
result : domain . ValidationResult {
Status : domain . ValidationPassed ,
Mode : domain . ValidationBasic ,
IsValid : true ,
} ,
err : tc . validationErr ,
}
admitter := & fakeRunAdmitter { }
runner := NewRunner (
& fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationBasic , 0 ) } ,
& fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile {
"exec" : defaultExecutionProfile ( ) ,
} } ,
2026-09-30 04:18:27 +00:00
2026-07-29 21:01:37 +00:00
reader ,
defaultRenderer ( ) ,
llmClient ,
validator ,
admitter ,
)
result , err := runner . Run ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : singleInputRef ( ) ,
} )
if tc . wantError == nil {
if err != nil || result == nil {
t . Fatalf ( "successful run=(%+v, %v)" , result , err )
}
} else {
if result != nil || ! errors . Is ( err , tc . wantError ) {
t . Fatalf ( "failed run=(%+v, %v), want %v" , result , err , tc . wantError )
}
}
if len ( admitter . backendIDs ) != 1 || admitter . releaseCalls != 1 {
t . Fatalf ( "admission calls=%#v releases=%d, want one each" ,
admitter . backendIDs , admitter . releaseCalls )
}
} )
}
}
2026-07-28 04:33:30 +00:00
func TestRunnerRunExplicitProfileIDIsUsed ( t * testing . T ) {
promptRepo := & fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) }
promptRepo . def . DefaultProfile = "default-prof"
execRepo := & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile {
2026-09-30 04:18:27 +00:00
"explicit-prof" : { ID : "explicit-prof" , ResolvedTarget : & domain . ExecutionTarget { Endpoint : "http://explicit/v1" , Model : "explicit" , TimeoutSeconds : defaults . ExecutionDefaultTimeoutSeconds } } ,
"default-prof" : { ID : "default-prof" , ResolvedTarget : & domain . ExecutionTarget { Endpoint : "http://default/v1" , Model : "default" , TimeoutSeconds : defaults . ExecutionDefaultTimeoutSeconds } } ,
2026-07-28 04:33:30 +00:00
} }
runner := newMinimalRunner ( promptRepo , execRepo )
res , err := runner . Run ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "explicit-prof" ,
Inputs : singleInputRef ( ) ,
} )
if err != nil {
t . Fatalf ( "expected no error, got %v" , err )
}
if execRepo . lastID != "explicit-prof" {
t . Fatalf ( "expected explicit profile lookup, got %q" , execRepo . lastID )
}
if res . SelectedProfileID != "explicit-prof" {
t . Fatalf ( "expected selected profile explicit-prof, got %q" , res . SelectedProfileID )
}
}
func TestRunnerRunPromptDefaultProfileIsUsedWhenNoExplicitProfileID ( t * testing . T ) {
promptRepo := & fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) }
promptRepo . def . DefaultProfile = "from-prompt"
execRepo := & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile {
2026-09-30 04:18:27 +00:00
"from-prompt" : { ID : "from-prompt" , ResolvedTarget : & domain . ExecutionTarget { Endpoint : "http://llm/v1" , Model : "m" , TimeoutSeconds : defaults . ExecutionDefaultTimeoutSeconds } } ,
2026-07-28 04:33:30 +00:00
} }
runner := newMinimalRunner ( promptRepo , execRepo )
res , err := runner . Run ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
Inputs : singleInputRef ( ) ,
} )
if err != nil {
t . Fatalf ( "expected no error, got %v" , err )
}
if execRepo . lastID != "from-prompt" {
t . Fatalf ( "expected prompt default profile lookup, got %q" , execRepo . lastID )
}
if res . SelectedProfileID != "from-prompt" {
t . Fatalf ( "expected selected profile from-prompt, got %q" , res . SelectedProfileID )
}
}
func TestRunnerRunMissingExplicitProfileAndMissingDefaultProfileFails ( t * testing . T ) {
repo := & fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) }
repo . def . DefaultProfile = ""
runner := newMinimalRunner ( repo , & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { "exec" : defaultExecutionProfile ( ) } } )
_ , err := runner . Run ( context . Background ( ) , domain . RunRequest { PromptID : "p" , Inputs : singleInputRef ( ) } )
if ! errors . Is ( err , ErrInvalidRequest ) {
t . Fatalf ( "expected ErrInvalidRequest, got %v" , err )
}
}
func TestRunnerRunInvalidDefaultProfileFails ( t * testing . T ) {
repo := & fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) }
repo . def . DefaultProfile = "does-not-exist"
runner := newMinimalRunner ( repo , & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { } } )
_ , err := runner . Run ( context . Background ( ) , domain . RunRequest { PromptID : "p" , Inputs : singleInputRef ( ) } )
if ! errors . Is ( err , ErrProfileLoad ) {
t . Fatalf ( "expected ErrProfileLoad, got %v" , err )
}
}
func TestRunnerRunExecutionProfileLoadFailure ( t * testing . T ) {
repo := & fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) }
runner := newMinimalRunner ( repo , & fakeExecutionProfileRepo { err : errors . New ( "load failed" ) } )
_ , err := runner . Run ( context . Background ( ) , domain . RunRequest { PromptID : "p" , ProfileID : "exec" , Inputs : singleInputRef ( ) } )
if ! errors . Is ( err , ErrProfileLoad ) {
t . Fatalf ( "expected profile load failure, got %v" , err )
}
}
func TestRunnerRunExplicitRuntimeOverrideBeatsSelectedProfileValue ( t * testing . T ) {
promptRepo := & fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) }
execRepo := & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile {
"exec" : {
2026-09-30 04:18:27 +00:00
ID : "exec" , ResolvedTarget : & domain . ExecutionTarget { Endpoint : "http://profile/v1" ,
Model : "profile-model" ,
Temperature : 0.2 ,
MaxTokens : 500 ,
TopP : 0.9 ,
TimeoutSeconds : 120 ,
ServiceTier : "priority" } ,
2026-07-28 04:33:30 +00:00
} ,
} }
llmClient := & fakeLLM { resp : & domain . GenerateResponse { Content : "ok" } }
2026-09-30 04:18:27 +00:00
runner := NewRunner ( promptRepo , execRepo , defaultArtifactReader ( ) , defaultRenderer ( ) , llmClient , nil , nil )
2026-07-28 04:33:30 +00:00
res , err := runner . Run ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : singleInputRef ( ) ,
Execution : & domain . ExecutionTargetOverride {
Endpoint : "http://override/v1" ,
Model : "override-model" ,
Temperature : float64Ptr ( 0.7 ) ,
TimeoutSeconds : intPtr ( 30 ) ,
ServiceTier : "flex" ,
} ,
} )
if err != nil {
t . Fatalf ( "expected no error, got %v" , err )
}
if res . Endpoint != "http://override/v1" || res . ModelName != "override-model" {
t . Fatalf ( "expected endpoint/model override to win, got endpoint=%q model=%q" , res . Endpoint , res . ModelName )
}
if res . EffectiveModelParams . Temperature != 0.7 || res . EffectiveModelParams . TimeoutSeconds != 30 {
t . Fatalf ( "expected numeric override to win, got %+v" , res . EffectiveModelParams )
}
if res . EffectiveModelParams . TopP != 0.9 {
t . Fatalf ( "expected non-overridden profile top_p to remain, got %v" , res . EffectiveModelParams . TopP )
}
if res . EffectiveModelParams . ServiceTier != "flex" {
t . Fatalf ( "expected service_tier override to win, got %q" , res . EffectiveModelParams . ServiceTier )
}
}
func TestRunnerRunSelectedProfileBeatsBuiltInDefault ( t * testing . T ) {
promptRepo := & fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) }
execRepo := & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile {
"exec" : {
2026-09-30 04:18:27 +00:00
ID : "exec" , ResolvedTarget : & domain . ExecutionTarget { Endpoint : "http://profile/v1" ,
Model : "profile-model" ,
TopP : 0.8 ,
TimeoutSeconds : 90 ,
ServiceTier : "priority" } ,
2026-07-28 04:33:30 +00:00
} ,
} }
llmClient := & fakeLLM { resp : & domain . GenerateResponse { Content : "ok" } }
2026-09-30 04:18:27 +00:00
runner := NewRunner ( promptRepo , execRepo , defaultArtifactReader ( ) , defaultRenderer ( ) , llmClient , nil , nil )
2026-07-28 04:33:30 +00:00
res , err := runner . Run ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : singleInputRef ( ) ,
} )
if err != nil {
t . Fatalf ( "expected no error, got %v" , err )
}
if res . EffectiveModelParams . TopP != 0.8 {
t . Fatalf ( "expected profile top_p to beat default, got %v" , res . EffectiveModelParams . TopP )
}
if res . EffectiveModelParams . TimeoutSeconds != 90 {
t . Fatalf ( "expected profile timeout to beat default, got %d" , res . EffectiveModelParams . TimeoutSeconds )
}
if res . EffectiveModelParams . ServiceTier != "priority" {
t . Fatalf ( "expected profile service_tier to beat default, got %q" , res . EffectiveModelParams . ServiceTier )
}
}
func TestRunnerRunAPIKeyEnvResolvesFromEnvironment ( t * testing . T ) {
t . Setenv ( "PROMPTKIT_TEST_API_KEY" , "secret" )
promptRepo := & fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) }
execRepo := & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile {
2026-09-30 04:18:27 +00:00
"exec" : { ID : "exec" , ResolvedTarget : & domain . ExecutionTarget { Endpoint : "http://profile/v1" , Model : "profile-model" , APIKeyEnv : "PROMPTKIT_TEST_API_KEY" , TimeoutSeconds : defaults . ExecutionDefaultTimeoutSeconds } } ,
2026-07-28 04:33:30 +00:00
} }
2026-09-30 04:18:27 +00:00
runner := NewRunner ( promptRepo , execRepo , defaultArtifactReader ( ) , defaultRenderer ( ) , & fakeLLM { resp : & domain . GenerateResponse { Content : "ok" } } , nil , nil )
2026-07-28 04:33:30 +00:00
res , err := runner . Run ( context . Background ( ) , domain . RunRequest { PromptID : "p" , ProfileID : "exec" , Inputs : singleInputRef ( ) } )
if err != nil {
t . Fatalf ( "expected no error, got %v" , err )
}
if res . EffectiveModelParams . APIKeyEnv != "PROMPTKIT_TEST_API_KEY" {
t . Fatalf ( "expected api_key_env name in effective params, got %q" , res . EffectiveModelParams . APIKeyEnv )
}
}
2026-08-25 00:39:26 +00:00
func TestRunnerRunOptionalAPIKeyEnvMissingEnvironmentValueReachesLLM ( t * testing . T ) {
const environmentName = "PROMPTKIT_MISSING_KEY"
t . Setenv ( environmentName , "" )
2026-07-28 04:33:30 +00:00
promptRepo := & fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) }
execRepo := & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile {
2026-09-30 04:18:27 +00:00
"exec" : { ID : "exec" , ResolvedTarget : & domain . ExecutionTarget { Endpoint : "http://profile/v1" , Model : "profile-model" , APIKeyEnv : environmentName , TimeoutSeconds : defaults . ExecutionDefaultTimeoutSeconds } } ,
2026-07-28 04:33:30 +00:00
} }
2026-08-25 00:39:26 +00:00
llmClient := & fakeLLM { resp : & domain . GenerateResponse { Content : "ok" } }
2026-09-30 04:18:27 +00:00
runner := NewRunner ( promptRepo , execRepo , defaultArtifactReader ( ) , defaultRenderer ( ) , llmClient , nil , nil )
2026-07-28 04:33:30 +00:00
2026-08-25 00:39:26 +00:00
result , err := runner . Run ( context . Background ( ) , domain . RunRequest { PromptID : "p" , ProfileID : "exec" , Inputs : singleInputRef ( ) } )
if err != nil || result == nil {
t . Fatalf ( "optional credential run = (%+v, %v), want success" , result , err )
2026-07-28 04:33:30 +00:00
}
2026-08-25 00:39:26 +00:00
if llmClient . calls != 1 {
t . Fatalf ( "LLM calls = %d, want 1" , llmClient . calls )
2026-07-28 04:33:30 +00:00
}
2026-08-25 00:39:26 +00:00
if llmClient . lastReq . Target . APIKeyEnv != environmentName {
t . Fatalf ( "LLM api_key_env = %q, want %q" , llmClient . lastReq . Target . APIKeyEnv , environmentName )
2026-07-28 04:33:30 +00:00
}
}
func TestRunnerRunDirectAPIKeyBypassesMissingEnvAndReachesLLM ( t * testing . T ) {
const directKey = "direct-runner-key"
promptRepo := & fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) }
execRepo := & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile {
2026-09-30 04:18:27 +00:00
"exec" : { ID : "exec" , ResolvedTarget : & domain . ExecutionTarget { Endpoint : "http://profile/v1" , Model : "profile-model" , APIKeyEnv : "PROMPTKIT_MISSING_KEY" , TimeoutSeconds : defaults . ExecutionDefaultTimeoutSeconds } } ,
2026-07-28 04:33:30 +00:00
} }
llmClient := & fakeLLM { resp : & domain . GenerateResponse { Content : "ok" } }
2026-09-30 04:18:27 +00:00
runner := NewRunner ( promptRepo , execRepo , defaultArtifactReader ( ) , defaultRenderer ( ) , llmClient , nil , nil )
2026-07-28 04:33:30 +00:00
2026-07-30 19:06:17 +00:00
result , err := runner . Run ( context . Background ( ) , domain . RunRequest {
2026-07-28 04:33:30 +00:00
PromptID : "p" ,
ProfileID : "exec" ,
APIKey : directKey ,
Inputs : singleInputRef ( ) ,
} )
if err != nil {
t . Fatalf ( "expected no error, got %v" , err )
}
if llmClient . lastReq . Target . APIKey != directKey {
t . Fatalf ( "expected direct API key to reach LLM request" )
}
2026-07-30 19:06:17 +00:00
if result . EffectiveModelParams . APIKey != "" {
t . Fatal ( "run result retained direct API key" )
}
2026-07-28 04:33:30 +00:00
if llmClient . lastReq . Target . APIKeyEnv != "PROMPTKIT_MISSING_KEY" {
t . Fatalf ( "expected api_key_env name to remain on target, got %q" , llmClient . lastReq . Target . APIKeyEnv )
}
}
func TestRunnerPrepareAPIKeyRequiredFailsWithoutDirectKey ( t * testing . T ) {
promptRepo := & fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) }
execRepo := & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile {
2026-09-30 04:18:27 +00:00
"exec" : { ID : "exec" , ResolvedTarget : & domain . ExecutionTarget { Endpoint : "http://profile/v1" , Model : "profile-model" , APIKeyRequired : true , TimeoutSeconds : defaults . ExecutionDefaultTimeoutSeconds } } ,
2026-07-28 04:33:30 +00:00
} }
2026-09-30 04:18:27 +00:00
runner := NewRunner ( promptRepo , execRepo , defaultArtifactReader ( ) , defaultRenderer ( ) , & fakeLLM { resp : & domain . GenerateResponse { Content : "ok" } } , nil , nil )
2026-07-28 04:33:30 +00:00
_ , err := runner . Prepare ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : singleInputRef ( ) ,
} )
if ! errors . Is ( err , ErrAPIKeyRequired ) {
t . Fatalf ( "expected ErrAPIKeyRequired, got %v" , err )
}
}
func TestRunnerRunAPIKeyRequiredSucceedsWithDirectKey ( t * testing . T ) {
const directKey = "direct-required-key"
promptRepo := & fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) }
execRepo := & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile {
2026-09-30 04:18:27 +00:00
"exec" : { ID : "exec" , ResolvedTarget : & domain . ExecutionTarget { Endpoint : "http://profile/v1" , Model : "profile-model" , APIKeyRequired : true , TimeoutSeconds : defaults . ExecutionDefaultTimeoutSeconds } } ,
2026-07-28 04:33:30 +00:00
} }
llmClient := & fakeLLM { resp : & domain . GenerateResponse { Content : "ok" } }
2026-09-30 04:18:27 +00:00
runner := NewRunner ( promptRepo , execRepo , defaultArtifactReader ( ) , defaultRenderer ( ) , llmClient , nil , nil )
2026-07-28 04:33:30 +00:00
_ , err := runner . Run ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
APIKey : directKey ,
Inputs : singleInputRef ( ) ,
} )
if err != nil {
t . Fatalf ( "expected no error, got %v" , err )
}
if llmClient . lastReq . Target . APIKey != directKey {
t . Fatalf ( "expected direct API key to reach LLM request" )
}
if ! llmClient . lastReq . Target . APIKeyRequired {
t . Fatalf ( "expected APIKeyRequired to be carried to target" )
}
}
func TestRunnerRunRuntimeAPIKeyEnvOverrideWorks ( t * testing . T ) {
const envName = "PROMPTKIT_RUNTIME_API_KEY"
t . Setenv ( envName , "runtime-secret" )
promptRepo := & fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) }
execRepo := & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile {
2026-09-30 04:18:27 +00:00
"exec" : { ID : "exec" , ResolvedTarget : & domain . ExecutionTarget { Endpoint : "http://profile/v1" , Model : "profile-model" , TimeoutSeconds : defaults . ExecutionDefaultTimeoutSeconds } } ,
2026-07-28 04:33:30 +00:00
} }
2026-09-30 04:18:27 +00:00
runner := NewRunner ( promptRepo , execRepo , defaultArtifactReader ( ) , defaultRenderer ( ) , & fakeLLM { resp : & domain . GenerateResponse { Content : "ok" } } , nil , nil )
2026-07-28 04:33:30 +00:00
res , err := runner . Run ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : singleInputRef ( ) ,
Execution : & domain . ExecutionTargetOverride { APIKeyEnv : envName } ,
} )
if err != nil {
t . Fatalf ( "expected no error, got %v" , err )
}
if res . EffectiveModelParams . APIKeyEnv != envName {
t . Fatalf ( "expected runtime api_key_env override in effective params, got %q" , res . EffectiveModelParams . APIKeyEnv )
}
}
func TestRunnerRunRuntimeAPIKeyEnvOverrideBeatsProfile ( t * testing . T ) {
const profileEnv = "PROMPTKIT_PROFILE_API_KEY"
const runtimeEnv = "PROMPTKIT_RUNTIME_API_KEY"
t . Setenv ( runtimeEnv , "runtime-secret" )
promptRepo := & fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) }
execRepo := & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile {
2026-09-30 04:18:27 +00:00
"exec" : { ID : "exec" , ResolvedTarget : & domain . ExecutionTarget { Endpoint : "http://profile/v1" , Model : "profile-model" , APIKeyEnv : profileEnv , TimeoutSeconds : defaults . ExecutionDefaultTimeoutSeconds } } ,
2026-07-28 04:33:30 +00:00
} }
2026-09-30 04:18:27 +00:00
runner := NewRunner ( promptRepo , execRepo , defaultArtifactReader ( ) , defaultRenderer ( ) , & fakeLLM { resp : & domain . GenerateResponse { Content : "ok" } } , nil , nil )
2026-07-28 04:33:30 +00:00
res , err := runner . Run ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : singleInputRef ( ) ,
Execution : & domain . ExecutionTargetOverride { APIKeyEnv : runtimeEnv } ,
} )
if err != nil {
t . Fatalf ( "expected no error, got %v" , err )
}
if res . EffectiveModelParams . APIKeyEnv != runtimeEnv {
t . Fatalf ( "expected runtime override to beat profile api_key_env, got %q" , res . EffectiveModelParams . APIKeyEnv )
}
}
func TestRunnerRunAPIKeyValueNotPresentInMetadata ( t * testing . T ) {
const envName = "PROMPTKIT_TEST_API_KEY"
const secret = "top-secret-value"
t . Setenv ( envName , secret )
promptRepo := & fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) }
execRepo := & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile {
2026-09-30 04:18:27 +00:00
"exec" : { ID : "exec" , ResolvedTarget : & domain . ExecutionTarget { Endpoint : "http://profile/v1" , Model : "profile-model" , APIKeyEnv : envName , TimeoutSeconds : defaults . ExecutionDefaultTimeoutSeconds } } ,
2026-07-28 04:33:30 +00:00
} }
2026-09-30 04:18:27 +00:00
runner := NewRunner ( promptRepo , execRepo , defaultArtifactReader ( ) , defaultRenderer ( ) , & fakeLLM { resp : & domain . GenerateResponse { Content : "ok" } } , nil , nil )
2026-07-28 04:33:30 +00:00
res , err := runner . Run ( context . Background ( ) , domain . RunRequest { PromptID : "p" , ProfileID : "exec" , Inputs : singleInputRef ( ) } )
if err != nil {
t . Fatalf ( "expected no error, got %v" , err )
}
if res . EffectiveModelParams . APIKeyEnv != envName {
t . Fatalf ( "expected api key env name, got %q" , res . EffectiveModelParams . APIKeyEnv )
}
metadataDump := fmt . Sprintf ( "%+v|%s|%s|%s|%s" , res . EffectiveModelParams , res . Endpoint , res . ModelName , res . PromptHash , res . RenderedPromptHash )
if strings . Contains ( metadataDump , secret ) {
t . Fatalf ( "unexpected api key value in metadata dump: %s" , metadataDump )
}
}
func TestRunnerRunPromptLoadFailure ( t * testing . T ) {
2026-09-30 04:18:27 +00:00
runner := NewRunner ( & fakePromptRepo { err : errors . New ( "boom" ) } , & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { "exec" : defaultExecutionProfile ( ) } } , defaultArtifactReader ( ) , defaultRenderer ( ) , & fakeLLM { } , nil , nil )
2026-07-28 04:33:30 +00:00
_ , err := runner . Run ( context . Background ( ) , domain . RunRequest { PromptID : "p" } )
if ! errors . Is ( err , ErrPromptLoad ) {
t . Fatalf ( "expected ErrPromptLoad, got %v" , err )
}
if errors . Is ( err , ErrProfileLoad ) {
t . Fatalf ( "did not expect ErrProfileLoad, got %v" , err )
}
}
func TestRunnerRunArtifactLoadFailure ( t * testing . T ) {
runner := NewRunner (
& fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) } ,
2026-09-30 04:18:27 +00:00
& fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { "exec" : defaultExecutionProfile ( ) } } ,
2026-07-29 17:10:34 +00:00
2026-07-28 04:33:30 +00:00
& fakeArtifactReader { errByURI : map [ string ] error { "a://bad" : errors . New ( "read failed" ) } } ,
& fakeRenderer { rendered : & domain . RenderedPrompt { } } ,
& fakeLLM { resp : & domain . GenerateResponse { Content : "ok" } } ,
2026-07-29 21:01:37 +00:00
nil , nil )
2026-07-28 04:33:30 +00:00
_ , err := runner . Run ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : map [ string ] domain . ArtifactRef { "transcript" : { Type : domain . ArtifactRefFile , URI : "a://bad" } } ,
} )
if ! errors . Is ( err , ErrArtifactLoad ) {
t . Fatalf ( "expected ErrArtifactLoad, got %v" , err )
}
}
func TestRunnerRunPromptRenderFailure ( t * testing . T ) {
runner := NewRunner (
& fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) } ,
2026-09-30 04:18:27 +00:00
& fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { "exec" : defaultExecutionProfile ( ) } } ,
2026-07-29 17:10:34 +00:00
2026-07-28 04:33:30 +00:00
defaultArtifactReader ( ) ,
& fakeRenderer { err : errors . New ( "render failed" ) } ,
& fakeLLM { resp : & domain . GenerateResponse { Content : "ok" } } ,
2026-07-29 21:01:37 +00:00
nil , nil )
2026-07-29 17:10:34 +00:00
2026-07-28 04:33:30 +00:00
_ , err := runner . Run ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : singleInputRef ( ) ,
} )
if ! errors . Is ( err , ErrPromptRender ) {
t . Fatalf ( "expected ErrPromptRender, got %v" , err )
}
}
func TestRunnerRunLLMFailure ( t * testing . T ) {
runner := NewRunner (
& fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) } ,
2026-09-30 04:18:27 +00:00
& fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { "exec" : defaultExecutionProfile ( ) } } ,
2026-07-29 17:10:34 +00:00
2026-07-28 04:33:30 +00:00
defaultArtifactReader ( ) ,
defaultRenderer ( ) ,
& fakeLLM { err : errors . New ( "llm failed" ) } ,
2026-07-29 21:01:37 +00:00
nil , nil )
2026-07-29 17:10:34 +00:00
2026-07-28 04:33:30 +00:00
_ , err := runner . Run ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : singleInputRef ( ) ,
} )
if ! errors . Is ( err , ErrLLMGenerate ) {
t . Fatalf ( "expected ErrLLMGenerate, got %v" , err )
}
}
func TestRunnerRunCancellationPreservesGenerationCategory ( t * testing . T ) {
runner := NewRunner (
& fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) } ,
2026-09-30 04:18:27 +00:00
& fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { "exec" : defaultExecutionProfile ( ) } } ,
2026-07-29 17:10:34 +00:00
2026-07-28 04:33:30 +00:00
defaultArtifactReader ( ) ,
defaultRenderer ( ) ,
& fakeLLM { resp : & domain . GenerateResponse { Content : "ignored" } } ,
2026-07-29 21:01:37 +00:00
nil , nil )
2026-07-29 17:10:34 +00:00
2026-07-28 04:33:30 +00:00
ctx , cancel := context . WithCancel ( context . Background ( ) )
cancel ( )
_ , err := runner . Run ( ctx , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : singleInputRef ( ) ,
} )
if ! errors . Is ( err , ErrLLMGenerate ) {
t . Fatalf ( "expected ErrLLMGenerate, got %v" , err )
}
if ! errors . Is ( err , context . Canceled ) {
t . Fatalf ( "expected context cancellation identity, got %v" , err )
}
}
func TestRunnerRunLLMInvalidRequestMapsToUsecaseInvalidRequest ( t * testing . T ) {
runner := NewRunner (
& fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) } ,
2026-09-30 04:18:27 +00:00
& fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { "exec" : defaultExecutionProfile ( ) } } ,
2026-07-29 17:10:34 +00:00
2026-07-28 04:33:30 +00:00
defaultArtifactReader ( ) ,
defaultRenderer ( ) ,
& fakeLLM { err : llm . ErrInvalidRequest } ,
2026-07-29 21:01:37 +00:00
nil , nil )
2026-07-29 17:10:34 +00:00
2026-07-28 04:33:30 +00:00
_ , err := runner . Run ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : singleInputRef ( ) ,
} )
if ! errors . Is ( err , ErrInvalidRequest ) {
t . Fatalf ( "expected ErrInvalidRequest, got %v" , err )
}
if errors . Is ( err , ErrLLMGenerate ) {
t . Fatalf ( "did not expect ErrLLMGenerate, got %v" , err )
}
}
func TestRunnerRunValidationStillWorks ( t * testing . T ) {
validator := & fakeValidator { result : domain . ValidationResult { Status : domain . ValidationFailed , Mode : domain . ValidationBasic , Errors : [ ] string { "bad" } , IsValid : false } }
runner := NewRunner (
& fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationBasic , 0 ) } ,
2026-09-30 04:18:27 +00:00
& fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile { "exec" : defaultExecutionProfile ( ) } } ,
2026-07-29 17:10:34 +00:00
2026-07-28 04:33:30 +00:00
defaultArtifactReader ( ) ,
defaultRenderer ( ) ,
& fakeLLM { resp : & domain . GenerateResponse { Content : "raw output" } } ,
2026-07-29 21:01:37 +00:00
validator , nil )
2026-07-29 17:10:34 +00:00
2026-07-28 04:33:30 +00:00
res , err := runner . Run ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : singleInputRef ( ) ,
} )
if err != nil {
t . Fatalf ( "expected no error, got %v" , err )
}
if res . Validation . Status != domain . ValidationFailed || res . RawOutput != "raw output" {
t . Fatalf ( "unexpected validation/raw output: %+v" , res )
}
}
2026-08-11 23:21:34 +00:00
func TestRunnerRepairStateMachine ( t * testing . T ) {
failed := func ( mode domain . ValidationMode , diagnostic string ) domain . ValidationResult {
return domain . ValidationResult {
Status : domain . ValidationFailed ,
Mode : mode ,
Errors : [ ] string { diagnostic } ,
IsValid : false ,
}
2026-07-28 04:33:30 +00:00
}
2026-08-11 23:21:34 +00:00
passed := func ( mode domain . ValidationMode ) domain . ValidationResult {
return domain . ValidationResult {
Status : domain . ValidationPassed ,
Mode : mode ,
IsValid : true ,
}
2026-07-28 04:33:30 +00:00
}
2026-08-11 23:21:34 +00:00
responses := func ( count int ) [ ] * domain . GenerateResponse {
values := make ( [ ] * domain . GenerateResponse , count )
for index := range values {
unit := index + 1
values [ index ] = & domain . GenerateResponse {
Content : fmt . Sprintf ( ` { "candidate":%d} ` , index ) ,
Usage : domain . TokenUsage {
PromptTokens : unit ,
CompletionTokens : unit * 10 ,
TotalTokens : unit * 100 ,
CachedTokens : unit * 1000 ,
CacheWriteTokens : unit * 10000 ,
} ,
}
}
return values
2026-07-28 04:33:30 +00:00
}
2026-08-11 23:21:34 +00:00
zeroOverrides := & domain . ExecutionTargetOverride {
Temperature : float64Ptr ( 0 ) ,
MaxTokens : intPtr ( 0 ) ,
TopP : float64Ptr ( 0 ) ,
TimeoutSeconds : intPtr ( 0 ) ,
2026-07-28 04:33:30 +00:00
}
2026-08-11 23:21:34 +00:00
allPresent := domain . ExecutionTargetPresence {
Temperature : true ,
MaxTokens : true ,
TopP : true ,
TimeoutSeconds : true ,
2026-07-28 04:33:30 +00:00
}
2026-08-25 09:51:28 +00:00
emptyThenValid := responses ( 2 )
emptyThenValid [ 0 ] . Content = " \t "
2026-08-11 23:21:34 +00:00
tests := [ ] struct {
name string
mode domain . ValidationMode
budget int
validationResults [ ] domain . ValidationResult
responses [ ] * domain . GenerateResponse
execution * domain . ExecutionTargetOverride
wantPresence domain . ExecutionTargetPresence
wantRepairs int
wantStatus domain . ValidationStatus
structured bool
} {
{
name : "initial success does not repair" ,
mode : domain . ValidationJSON ,
budget : 3 ,
validationResults : [ ] domain . ValidationResult { passed ( domain . ValidationJSON ) } ,
responses : responses ( 1 ) ,
wantStatus : domain . ValidationPassed ,
} ,
{
2026-08-25 09:51:28 +00:00
name : "empty basic output repairs successfully" ,
2026-08-11 23:21:34 +00:00
mode : domain . ValidationBasic ,
budget : 3 ,
2026-08-25 09:51:28 +00:00
validationResults : [ ] domain . ValidationResult { failed ( domain . ValidationBasic , "empty output" ) , passed ( domain . ValidationBasic ) } ,
responses : emptyThenValid ,
wantRepairs : 1 ,
wantStatus : domain . ValidationPassed ,
2026-08-11 23:21:34 +00:00
} ,
{
name : "inherited numeric values remain absent" ,
mode : domain . ValidationJSON ,
budget : 1 ,
validationResults : [ ] domain . ValidationResult {
failed ( domain . ValidationJSON , "initial syntax" ) ,
passed ( domain . ValidationJSON ) ,
} ,
responses : responses ( 2 ) ,
wantRepairs : 1 ,
wantStatus : domain . ValidationPassed ,
} ,
{
name : "explicit numeric zeros remain present" ,
mode : domain . ValidationJSONSchema ,
budget : 1 ,
execution : zeroOverrides ,
structured : true ,
validationResults : [ ] domain . ValidationResult {
failed ( domain . ValidationJSONSchema , "initial schema mismatch" ) ,
passed ( domain . ValidationJSONSchema ) ,
} ,
responses : responses ( 2 ) ,
wantPresence : allPresent ,
wantRepairs : 1 ,
wantStatus : domain . ValidationPassed ,
} ,
{
name : "successful repair stops below larger budget" ,
mode : domain . ValidationJSON ,
2026-08-25 09:41:15 +00:00
budget : 3 ,
2026-08-11 23:21:34 +00:00
validationResults : [ ] domain . ValidationResult {
failed ( domain . ValidationJSON , "candidate zero" ) ,
failed ( domain . ValidationJSON , "candidate one" ) ,
passed ( domain . ValidationJSON ) ,
} ,
responses : responses ( 3 ) ,
wantRepairs : 2 ,
wantStatus : domain . ValidationPassed ,
} ,
{
name : "failed repairs exhaust exact larger budget" ,
mode : domain . ValidationJSON ,
budget : 3 ,
validationResults : [ ] domain . ValidationResult {
failed ( domain . ValidationJSON , "candidate zero" ) ,
failed ( domain . ValidationJSON , "candidate one" ) ,
failed ( domain . ValidationJSON , "candidate two" ) ,
failed ( domain . ValidationJSON , "candidate three" ) ,
} ,
responses : responses ( 4 ) ,
wantRepairs : 3 ,
wantStatus : domain . ValidationFailed ,
} ,
}
for _ , tc := range tests {
t . Run ( tc . name , func ( t * testing . T ) {
definition := promptDef ( domain . FormatJSON , tc . mode , tc . budget )
plan := & recordingPreparedValidation { results : tc . validationResults }
if tc . structured {
definition . Validation . SchemaPath = "schema.json"
plan . schemaDocument = map [ string ] any { "type" : "object" }
}
validator := & recordingValidationPreparer { plan : plan }
client := & sequenceLLM { responses : tc . responses }
repairer := & recordingRepairer { next : NewDefaultOutputRepairer ( client ) }
runner := NewRunnerWithRepairer (
& fakePromptRepo { def : definition } ,
& fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile {
2026-09-30 04:18:27 +00:00
"exec" : { ID : "exec" , ResolvedTarget : & domain . ExecutionTarget { BackendID : "custom" , Endpoint : "http://backend.example/v1" , Model : "profile-model" } } ,
2026-08-11 23:21:34 +00:00
} } ,
2026-09-30 04:18:27 +00:00
2026-08-11 23:21:34 +00:00
defaultArtifactReader ( ) ,
defaultRenderer ( ) ,
client ,
validator ,
repairer ,
nil ,
)
result , err := runner . Run ( context . Background ( ) , domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
SessionID : " repair-session " ,
APIKey : "direct-secret" ,
Inputs : singleInputRef ( ) ,
Execution : tc . execution ,
} )
if err != nil {
t . Fatalf ( "run: %v" , err )
}
if len ( client . requests ) != tc . wantRepairs + 1 || len ( repairer . reqs ) != tc . wantRepairs {
t . Fatalf (
"generation/repair calls = (%d, %d), want (%d, %d)" ,
len ( client . requests ) , len ( repairer . reqs ) , tc . wantRepairs + 1 , tc . wantRepairs ,
)
}
if len ( plan . artifacts ) != tc . wantRepairs + 1 {
t . Fatalf ( "validation calls = %d, want %d" , len ( plan . artifacts ) , tc . wantRepairs + 1 )
}
initialRequest := client . requests [ 0 ]
if initialRequest . TargetPresence != tc . wantPresence {
t . Fatalf ( "initial target presence = %+v, want %+v" , initialRequest . TargetPresence , tc . wantPresence )
}
if initialRequest . Target . APIKey != "direct-secret" || initialRequest . Target . BackendID != "custom" ||
initialRequest . Prompt . SessionID != "repair-session" {
t . Fatalf ( "initial common request fields = %+v" , initialRequest )
}
if initialRequest . Target . Endpoint != "http://backend.example/v1" ||
initialRequest . Target . Model != "profile-model" ||
initialRequest . Target . Temperature != 0 || initialRequest . Target . MaxTokens != 0 || initialRequest . Target . TopP != 0 {
t . Fatalf ( "initial effective target = %+v" , initialRequest . Target )
}
if tc . structured != ( initialRequest . StructuredOutput != nil ) {
t . Fatalf ( "initial structured output = %+v, want present %v" , initialRequest . StructuredOutput , tc . structured )
}
if tc . structured && ( initialRequest . StructuredOutput . JSONSchema == nil ||
2026-10-17 05:47:14 +00:00
initialRequest . StructuredOutput . JSONSchema . Name != "p" ) {
t . Fatalf ( "initial JSON Schema metadata = %+v, want derived schema name p" , initialRequest . StructuredOutput )
2026-08-11 23:21:34 +00:00
}
for index , req := range repairer . reqs {
if req . Attempt != index + 1 || req . MaxAttempts != tc . budget || req . Mode != tc . mode {
t . Fatalf ( "repair request %d progression = %+v" , index , req )
}
if req . PreviousOutput != tc . responses [ index ] . Content ||
! reflect . DeepEqual ( req . ValidationErrors , tc . validationResults [ index ] . Errors ) {
t . Fatalf ( "repair request %d prior state = %+v" , index , req )
}
2026-08-25 09:51:28 +00:00
if ! reflect . DeepEqual ( req . OriginalMessages , initialRequest . Prompt . Messages ) {
t . Fatalf ( "repair request %d original messages drifted: %#v" , index , req . OriginalMessages )
}
2026-08-11 23:21:34 +00:00
if req . TargetPresence != tc . wantPresence || ! reflect . DeepEqual ( req . Target , initialRequest . Target ) ||
req . SessionID != initialRequest . Prompt . SessionID ||
! reflect . DeepEqual ( req . StructuredOutput , initialRequest . StructuredOutput ) {
t . Fatalf ( "repair request %d common fields drifted: %+v" , index , req )
}
generated := client . requests [ index + 1 ]
if generated . TargetPresence != initialRequest . TargetPresence ||
! reflect . DeepEqual ( generated . Target , initialRequest . Target ) ||
generated . Prompt . SessionID != initialRequest . Prompt . SessionID ||
! reflect . DeepEqual ( generated . StructuredOutput , initialRequest . StructuredOutput ) {
t . Fatalf ( "repair generation request %d common fields drifted: %+v" , index , generated )
}
2026-08-25 09:51:28 +00:00
expectedMessages := len ( initialRequest . Prompt . Messages ) + 1
if strings . TrimSpace ( tc . responses [ index ] . Content ) != "" {
expectedMessages ++
}
if len ( generated . Prompt . Messages ) != expectedMessages ||
generated . Prompt . Messages [ len ( generated . Prompt . Messages ) - 1 ] . Role != "user" {
t . Fatalf ( "repair generation request %d messages = %#v" , index , generated . Prompt . Messages )
}
if strings . TrimSpace ( tc . responses [ index ] . Content ) != "" {
assistant := generated . Prompt . Messages [ len ( generated . Prompt . Messages ) - 2 ]
if assistant . Role != "assistant" || assistant . Content != tc . responses [ index ] . Content {
t . Fatalf ( "repair generation request %d candidate = %+v" , index , assistant )
}
2026-08-11 23:21:34 +00:00
}
}
lastResponse := tc . responses [ tc . wantRepairs ]
if result . RawOutput != lastResponse . Content || string ( result . Artifact . Body ) != lastResponse . Content {
t . Fatalf ( "final output = (%q, %q), want %q" , result . RawOutput , result . Artifact . Body , lastResponse . Content )
}
if result . Validation . Status != tc . wantStatus || result . Validation . RepairAttempts != tc . wantRepairs {
t . Fatalf ( "final validation = %+v, want status %q and %d repairs" , result . Validation , tc . wantStatus , tc . wantRepairs )
}
if result . SelectedBackendID != "custom" || result . SessionID != "repair-session" ||
result . EffectiveModelParams . APIKey != "" {
t . Fatalf ( "result execution metadata = %+v" , result )
}
var wantUsage domain . TokenUsage
for _ , response := range tc . responses [ : tc . wantRepairs + 1 ] {
wantUsage . PromptTokens += response . Usage . PromptTokens
wantUsage . CompletionTokens += response . Usage . CompletionTokens
wantUsage . TotalTokens += response . Usage . TotalTokens
wantUsage . CachedTokens += response . Usage . CachedTokens
wantUsage . CacheWriteTokens += response . Usage . CacheWriteTokens
}
if result . Usage != wantUsage {
t . Fatalf ( "cumulative usage = %+v, want %+v" , result . Usage , wantUsage )
}
} )
2026-07-29 17:10:34 +00:00
}
2026-07-28 04:33:30 +00:00
}
2026-07-29 21:11:08 +00:00
func TestRunnerSchedulesInitialAndRepairGenerationThroughOneBackendPool ( t * testing . T ) {
manager , err := capacity . NewManager ( map [ string ] domain . BackendCapacityPolicy {
"custom" : {
ConcurrencyLimit : 1 ,
QueueCapacity : 1 ,
} ,
} )
if err != nil {
t . Fatalf ( "construct capacity manager: %v" , err )
}
baseClient := & controlledRepairLLM {
events : make ( chan controlledGeneration , 4 ) ,
}
scheduledClient := capacity . NewClient ( manager , baseClient )
admitter := & recordingRunAdmitter { next : manager }
runner := NewRunnerWithRepairer (
staticPromptRepo { def : promptDef ( domain . FormatJSON , domain . ValidationJSON , 1 ) } ,
staticExecutionProfileRepo { profile : & domain . ExecutionProfile {
2026-09-30 04:18:27 +00:00
ID : "exec" , ResolvedTarget : & domain . ExecutionTarget { BackendID : "custom" , Endpoint : "http://backend.example/v1" , Model : "model" } ,
2026-07-29 21:11:08 +00:00
} } ,
2026-09-30 04:18:27 +00:00
2026-07-29 21:11:08 +00:00
staticArtifactReader { } ,
staticRenderer { } ,
scheduledClient ,
validate . NewStandardValidator ( "." ) ,
NewDefaultOutputRepairer ( scheduledClient ) ,
admitter ,
)
ctx , cancel := context . WithTimeout ( context . Background ( ) , 5 * time . Second )
defer cancel ( )
type runOutcome struct {
result * domain . RunResult
err error
}
outcomes := make ( chan runOutcome , 2 )
request := domain . RunRequest {
PromptID : "p" ,
ProfileID : "exec" ,
Inputs : singleInputRef ( ) ,
}
for i := 0 ; i < 2 ; i ++ {
go func ( ) {
result , runErr := runner . Run ( ctx , request )
outcomes <- runOutcome { result : result , err : runErr }
} ( )
}
for i := 0 ; i < 4 ; i ++ {
select {
case event := <- baseClient . events :
close ( event . release )
case <- ctx . Done ( ) :
t . Fatalf ( "timed out waiting for generation %d: %v" , i + 1 , ctx . Err ( ) )
}
}
for i := 0 ; i < 2 ; i ++ {
select {
case outcome := <- outcomes :
if outcome . err != nil || outcome . result == nil {
t . Fatalf ( "run outcome=(%+v, %v), want success" , outcome . result , outcome . err )
}
if outcome . result . Validation . Status != domain . ValidationPassed ||
outcome . result . Validation . RepairAttempts != 1 {
t . Fatalf ( "unexpected repaired result: %+v" , outcome . result . Validation )
}
case <- ctx . Done ( ) :
t . Fatalf ( "timed out waiting for repaired run: %v" , ctx . Err ( ) )
}
}
admitted := admitter . admittedBackendIDs ( )
if ! reflect . DeepEqual ( admitted , [ ] string { "custom" , "custom" } ) {
t . Fatalf ( "admission backend IDs=%#v, want one admission per run" , admitted )
}
peak , calls , repairCalls , backendIDs := baseClient . snapshot ( )
if peak != 1 || calls != 4 || repairCalls != 2 {
t . Fatalf (
"generation observations=(peak=%d calls=%d repairs=%d), want (1, 4, 2)" ,
peak ,
calls ,
repairCalls ,
)
}
if ! reflect . DeepEqual ( backendIDs , [ ] string { "custom" , "custom" , "custom" , "custom" } ) {
t . Fatalf ( "generation backend IDs=%#v, want custom for initial and repair calls" , backendIDs )
}
}
2026-07-28 04:33:30 +00:00
func TestBuildOutputArtifactDefaults ( t * testing . T ) {
tests := [ ] struct {
name string
format domain . OutputFormat
contentType string
} {
{ name : "text" , format : domain . FormatText , contentType : defaults . ContentTypeTextPlain } ,
{ name : "markdown" , format : domain . FormatMarkdown , contentType : defaults . ContentTypeTextMarkdown } ,
{ name : "json" , format : domain . FormatJSON , contentType : defaults . ContentTypeApplicationJSON } ,
}
for _ , tc := range tests {
t . Run ( tc . name , func ( t * testing . T ) {
art := buildOutputArtifact ( "body" , tc . format )
if art . Name != defaults . OutputArtifactName {
t . Fatalf ( "expected artifact name %q, got %q" , defaults . OutputArtifactName , art . Name )
}
if art . ContentType != tc . contentType {
t . Fatalf ( "expected content type %q, got %q" , tc . contentType , art . ContentType )
}
} )
}
}
func promptDef ( format domain . OutputFormat , mode domain . ValidationMode , attempts int ) * domain . PromptDefinition {
return & domain . PromptDefinition {
ID : "p" ,
2026-10-17 05:54:32 +00:00
Version : stringPtr ( "1" ) ,
2026-07-28 04:33:30 +00:00
DefaultProfile : "exec" ,
Inputs : [ ] domain . PromptInput { { Name : "transcript" , Required : true } } ,
Templates : [ ] domain . PromptMessageTemplate { { Role : "user" , Content : "x" } } ,
OutputFormat : format ,
Validation : domain . OutputContract {
ValidationMode : mode ,
RepairAttempts : attempts ,
Format : format ,
} ,
}
}
func hashString ( s string ) string {
sum := sha256 . Sum256 ( [ ] byte ( s ) )
return hex . EncodeToString ( sum [ : ] )
}
func defaultExecutionProfile ( ) * domain . ExecutionProfile {
return & domain . ExecutionProfile {
2026-09-30 04:18:27 +00:00
ID : "exec" , ResolvedTarget : & domain . ExecutionTarget { Endpoint : "http://llm/v1" ,
Model : "model-from-profile" , TimeoutSeconds : defaults . ExecutionDefaultTimeoutSeconds } ,
2026-07-29 17:10:34 +00:00
}
}
2026-09-30 04:18:27 +00:00
func TestRunnerPrepareCredentialPrecedence ( t * testing . T ) {
2026-07-29 17:10:34 +00:00
promptRepo := & fakePromptRepo { def : promptDef ( domain . FormatText , domain . ValidationNone , 0 ) }
t . Run ( "request environment wins" , func ( t * testing . T ) {
t . Setenv ( "REQUEST_KEY" , "request-secret" )
runner := NewRunner ( promptRepo , & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile {
2026-09-30 04:18:27 +00:00
"exec" : { ID : "exec" , ResolvedTarget : & domain . ExecutionTarget { BackendID : "custom" , Endpoint : "http://backend/v1" , Model : "model" , APIKeyEnv : "PROFILE_KEY" } } ,
} } , defaultArtifactReader ( ) , defaultRenderer ( ) , & fakeLLM { forbid : true } , nil , nil )
2026-07-29 21:01:37 +00:00
2026-07-29 17:10:34 +00:00
prepared , err := runner . Prepare ( context . Background ( ) , domain . RunRequest {
PromptID : "p" , ProfileID : "exec" , Inputs : singleInputRef ( ) ,
Execution : & domain . ExecutionTargetOverride { APIKeyEnv : "REQUEST_KEY" } ,
} )
if err != nil {
t . Fatalf ( "prepare: %v" , err )
}
if prepared . EffectiveModelParams . APIKeyEnv != "REQUEST_KEY" {
t . Fatalf ( "unexpected credential source: %+v" , prepared . EffectiveModelParams )
}
} )
t . Run ( "required direct key clears inherited environment" , func ( t * testing . T ) {
t . Setenv ( "BACKEND_KEY" , "backend-secret" )
runner := NewRunner ( promptRepo , & fakeExecutionProfileRepo { profiles : map [ string ] * domain . ExecutionProfile {
2026-09-30 04:18:27 +00:00
"exec" : { ID : "exec" , ResolvedTarget : & domain . ExecutionTarget { BackendID : "custom" , Endpoint : "http://backend/v1" , Model : "model" , APIKeyRequired : true } } ,
} } , defaultArtifactReader ( ) , defaultRenderer ( ) , & fakeLLM { forbid : true } , nil , nil )
2026-07-29 21:01:37 +00:00
2026-07-29 17:10:34 +00:00
_ , err := runner . Prepare ( context . Background ( ) , domain . RunRequest { PromptID : "p" , ProfileID : "exec" , Inputs : singleInputRef ( ) } )
if ! errors . Is ( err , ErrAPIKeyRequired ) {
t . Fatalf ( "expected ErrAPIKeyRequired, got %v" , err )
}
prepared , err := runner . Prepare ( context . Background ( ) , domain . RunRequest {
PromptID : "p" , ProfileID : "exec" , Inputs : singleInputRef ( ) , APIKey : "direct-secret" ,
} )
if err != nil {
t . Fatalf ( "prepare with direct key: %v" , err )
}
if prepared . EffectiveModelParams . APIKeyEnv != "" {
t . Fatalf ( "expected inherited environment name to be cleared, got %q" , prepared . EffectiveModelParams . APIKeyEnv )
}
} )
}
2026-07-28 04:33:30 +00:00
func defaultArtifactReader ( ) * fakeArtifactReader {
return & fakeArtifactReader { artifactsByURI : map [ string ] * domain . Artifact {
"a://ok" : { Body : [ ] byte ( "x" ) , Hash : hashString ( "x" ) } ,
} }
}
func defaultRenderer ( ) * fakeRenderer {
return & fakeRenderer { rendered : & domain . RenderedPrompt { Messages : [ ] domain . RenderedMessage { { Role : "user" , Content : "hello" } } } }
}
func singleInputRef ( ) map [ string ] domain . ArtifactRef {
return map [ string ] domain . ArtifactRef { "transcript" : { Type : domain . ArtifactRefFile , URI : "a://ok" } }
}
func float64Ptr ( v float64 ) * float64 {
return & v
}
2026-07-29 19:36:48 +00:00
func stringPtr ( v string ) * string {
return & v
}
2026-07-28 04:33:30 +00:00
func intPtr ( v int ) * int {
return & v
}
func newMinimalRunner ( promptRepo * fakePromptRepo , execRepo * fakeExecutionProfileRepo ) * Runner {
return NewRunner (
promptRepo ,
2026-09-30 04:18:27 +00:00
execRepo ,
2026-07-29 17:10:34 +00:00
2026-07-28 04:33:30 +00:00
defaultArtifactReader ( ) ,
defaultRenderer ( ) ,
& fakeLLM { resp : & domain . GenerateResponse { Content : "ok" } } ,
2026-07-29 21:01:37 +00:00
nil , nil )
2026-07-29 17:10:34 +00:00
2026-07-28 04:33:30 +00:00
}