Use the public engine for CLI run and render
This commit is contained in:
@@ -12,11 +12,11 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"gitea.maximumdirect.net/eric/scriptorium"
|
||||||
httpadapter "gitea.maximumdirect.net/eric/scriptorium/internal/adapter/http"
|
httpadapter "gitea.maximumdirect.net/eric/scriptorium/internal/adapter/http"
|
||||||
artifactadapter "gitea.maximumdirect.net/eric/scriptorium/internal/artifact"
|
artifactadapter "gitea.maximumdirect.net/eric/scriptorium/internal/artifact"
|
||||||
appconfig "gitea.maximumdirect.net/eric/scriptorium/internal/config"
|
appconfig "gitea.maximumdirect.net/eric/scriptorium/internal/config"
|
||||||
"gitea.maximumdirect.net/eric/scriptorium/internal/defaults"
|
"gitea.maximumdirect.net/eric/scriptorium/internal/defaults"
|
||||||
"gitea.maximumdirect.net/eric/scriptorium/internal/domain"
|
|
||||||
renderformat "gitea.maximumdirect.net/eric/scriptorium/internal/format"
|
renderformat "gitea.maximumdirect.net/eric/scriptorium/internal/format"
|
||||||
"gitea.maximumdirect.net/eric/scriptorium/internal/llm"
|
"gitea.maximumdirect.net/eric/scriptorium/internal/llm"
|
||||||
"gitea.maximumdirect.net/eric/scriptorium/internal/profile/builtin"
|
"gitea.maximumdirect.net/eric/scriptorium/internal/profile/builtin"
|
||||||
@@ -140,15 +140,13 @@ func runCommand(args []string, stdout, stderr io.Writer) int {
|
|||||||
return ExitRuntimeError
|
return ExitRuntimeError
|
||||||
}
|
}
|
||||||
|
|
||||||
llmClient, err := newOpenAIClient()
|
engine, err := newEngine(cfg)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(stderr, "llm client error: %v\n", err)
|
fmt.Fprintf(stderr, "engine error: %v\n", err)
|
||||||
return ExitRuntimeError
|
return ExitRuntimeError
|
||||||
}
|
}
|
||||||
|
|
||||||
runner := newRunner(cfg.promptDir, cfg.profileDir, cfg.schemaDir, llmClient)
|
res, runErr := engine.Run(context.Background(), req)
|
||||||
|
|
||||||
res, runErr := runner.Run(context.Background(), req)
|
|
||||||
if runErr != nil {
|
if runErr != nil {
|
||||||
fmt.Fprintf(stderr, "run error: %v\n", runErr)
|
fmt.Fprintf(stderr, "run error: %v\n", runErr)
|
||||||
return ExitRuntimeError
|
return ExitRuntimeError
|
||||||
@@ -176,9 +174,13 @@ func renderCommand(args []string, stdout, stderr io.Writer) int {
|
|||||||
return ExitRuntimeError
|
return ExitRuntimeError
|
||||||
}
|
}
|
||||||
|
|
||||||
runner := newRunner(cfg.promptDir, cfg.profileDir, cfg.schemaDir, nil)
|
engine, err := newEngine(&cfg.runConfig)
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(stderr, "engine error: %v\n", err)
|
||||||
|
return ExitRuntimeError
|
||||||
|
}
|
||||||
|
|
||||||
prepared, prepErr := runner.Prepare(context.Background(), req)
|
prepared, prepErr := engine.Prepare(context.Background(), req)
|
||||||
if prepErr != nil {
|
if prepErr != nil {
|
||||||
fmt.Fprintf(stderr, "render error: %v\n", prepErr)
|
fmt.Fprintf(stderr, "render error: %v\n", prepErr)
|
||||||
return ExitRuntimeError
|
return ExitRuntimeError
|
||||||
@@ -565,28 +567,36 @@ func newOpenAIClient() (*llm.OpenAICompatibleClient, error) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func buildRunRequestFromConfig(cfg *runConfig) (domain.RunRequest, error) {
|
func newEngine(cfg *runConfig, options ...scriptorium.Option) (*scriptorium.Engine, error) {
|
||||||
|
return scriptorium.NewEngine(scriptorium.Config{
|
||||||
|
PromptDir: cfg.promptDir,
|
||||||
|
ProfileDir: cfg.profileDir,
|
||||||
|
SchemaDir: cfg.schemaDir,
|
||||||
|
}, options...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildRunRequestFromConfig(cfg *runConfig) (scriptorium.RunRequest, error) {
|
||||||
inputMappings, err := parseMappings(cfg.inputRaw, false)
|
inputMappings, err := parseMappings(cfg.inputRaw, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.RunRequest{}, fmt.Errorf("input parse error: %w", err)
|
return scriptorium.RunRequest{}, fmt.Errorf("input parse error: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
varMappings := map[string]string{}
|
varMappings := map[string]string{}
|
||||||
if len(cfg.varRaw) > 0 {
|
if len(cfg.varRaw) > 0 {
|
||||||
varMappings, err = parseMappings(cfg.varRaw, false)
|
varMappings, err = parseMappings(cfg.varRaw, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return domain.RunRequest{}, fmt.Errorf("var parse error: %w", err)
|
return scriptorium.RunRequest{}, fmt.Errorf("var parse error: %w", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inputs := make(map[string]domain.ArtifactRef, len(inputMappings))
|
inputs := make(map[string]scriptorium.ArtifactRef, len(inputMappings))
|
||||||
for name, path := range inputMappings {
|
for name, path := range inputMappings {
|
||||||
inputs[name] = domain.ArtifactRef{Type: domain.ArtifactRefFile, URI: path}
|
inputs[name] = scriptorium.File(path)
|
||||||
}
|
}
|
||||||
|
|
||||||
var modelOverride *domain.ExecutionTargetOverride
|
var modelOverride *scriptorium.ExecutionTargetOverride
|
||||||
if cfg.llmBaseURLSet || cfg.modelSet || cfg.temperatureSet || cfg.maxTokensSet || cfg.topPSet || cfg.apiKeyEnvSet || cfg.timeoutSet {
|
if cfg.llmBaseURLSet || cfg.modelSet || cfg.temperatureSet || cfg.maxTokensSet || cfg.topPSet || cfg.apiKeyEnvSet || cfg.timeoutSet {
|
||||||
modelOverride = &domain.ExecutionTargetOverride{
|
modelOverride = &scriptorium.ExecutionTargetOverride{
|
||||||
Endpoint: cfg.llmBaseURL,
|
Endpoint: cfg.llmBaseURL,
|
||||||
Model: cfg.model,
|
Model: cfg.model,
|
||||||
APIKeyEnv: cfg.apiKeyEnv,
|
APIKeyEnv: cfg.apiKeyEnv,
|
||||||
@@ -606,7 +616,7 @@ func buildRunRequestFromConfig(cfg *runConfig) (domain.RunRequest, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return domain.RunRequest{
|
return scriptorium.RunRequest{
|
||||||
PromptID: cfg.promptID,
|
PromptID: cfg.promptID,
|
||||||
ProfileID: cfg.profileID,
|
ProfileID: cfg.profileID,
|
||||||
Inputs: inputs,
|
Inputs: inputs,
|
||||||
@@ -670,17 +680,17 @@ func writeOutput(stdout io.Writer, outputPath string, body []byte) error {
|
|||||||
return os.WriteFile(outputPath, body, 0644)
|
return os.WriteFile(outputPath, body, 0644)
|
||||||
}
|
}
|
||||||
|
|
||||||
func determineExitCode(runErr error, result *domain.RunResult) int {
|
func determineExitCode(runErr error, result *scriptorium.RunResult) int {
|
||||||
if runErr != nil {
|
if runErr != nil {
|
||||||
return ExitRuntimeError
|
return ExitRuntimeError
|
||||||
}
|
}
|
||||||
if result != nil && result.Validation.Status == domain.ValidationFailed {
|
if result != nil && result.Validation.Status == scriptorium.ValidationFailed {
|
||||||
return ExitValidationFailed
|
return ExitValidationFailed
|
||||||
}
|
}
|
||||||
return ExitOK
|
return ExitOK
|
||||||
}
|
}
|
||||||
|
|
||||||
func printSummary(stderr io.Writer, res *domain.RunResult) {
|
func printSummary(stderr io.Writer, res *scriptorium.RunResult) {
|
||||||
if res == nil {
|
if res == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"gitea.maximumdirect.net/eric/scriptorium"
|
||||||
appconfig "gitea.maximumdirect.net/eric/scriptorium/internal/config"
|
appconfig "gitea.maximumdirect.net/eric/scriptorium/internal/config"
|
||||||
"gitea.maximumdirect.net/eric/scriptorium/internal/defaults"
|
"gitea.maximumdirect.net/eric/scriptorium/internal/defaults"
|
||||||
"gitea.maximumdirect.net/eric/scriptorium/internal/domain"
|
|
||||||
renderformat "gitea.maximumdirect.net/eric/scriptorium/internal/format"
|
renderformat "gitea.maximumdirect.net/eric/scriptorium/internal/format"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -655,6 +655,40 @@ func TestRunAndRenderBuildEquivalentRuntimeOverrideRequestsForSharedFlags(t *tes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBuildRunRequestPreservesNumericOverridePresence(t *testing.T) {
|
||||||
|
omitted, err := buildRunRequestFromConfig(&runConfig{
|
||||||
|
promptID: "prompt-1",
|
||||||
|
inputRaw: []string{"transcript=./transcript.md"},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected omitted override request to build, got %v", err)
|
||||||
|
}
|
||||||
|
if omitted.Execution != nil {
|
||||||
|
t.Fatalf("expected omitted numeric flags to leave execution override nil, got %#v", omitted.Execution)
|
||||||
|
}
|
||||||
|
|
||||||
|
explicitZeros, err := buildRunRequestFromConfig(&runConfig{
|
||||||
|
promptID: "prompt-1",
|
||||||
|
inputRaw: []string{"transcript=./transcript.md"},
|
||||||
|
temperatureSet: true,
|
||||||
|
maxTokensSet: true,
|
||||||
|
topPSet: true,
|
||||||
|
timeoutSet: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("expected explicit zero override request to build, got %v", err)
|
||||||
|
}
|
||||||
|
if explicitZeros.Execution == nil {
|
||||||
|
t.Fatal("expected explicit numeric flags to create execution override")
|
||||||
|
}
|
||||||
|
if explicitZeros.Execution.Temperature == nil || explicitZeros.Execution.MaxTokens == nil || explicitZeros.Execution.TopP == nil || explicitZeros.Execution.TimeoutSeconds == nil {
|
||||||
|
t.Fatalf("expected explicit zero numeric overrides to remain non-nil, got %#v", explicitZeros.Execution)
|
||||||
|
}
|
||||||
|
if *explicitZeros.Execution.Temperature != 0 || *explicitZeros.Execution.MaxTokens != 0 || *explicitZeros.Execution.TopP != 0 || *explicitZeros.Execution.TimeoutSeconds != 0 {
|
||||||
|
t.Fatalf("expected explicit numeric overrides to retain zero values, got %#v", explicitZeros.Execution)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestParseRunArgsFailsClearlyWhenNoEffectivePromptDir(t *testing.T) {
|
func TestParseRunArgsFailsClearlyWhenNoEffectivePromptDir(t *testing.T) {
|
||||||
configPath := writeAppConfigFile(t, `
|
configPath := writeAppConfigFile(t, `
|
||||||
profile_dir: ./profiles
|
profile_dir: ./profiles
|
||||||
@@ -731,13 +765,13 @@ func TestDetermineExitCode(t *testing.T) {
|
|||||||
if got := determineExitCode(errors.New("boom"), nil); got != ExitRuntimeError {
|
if got := determineExitCode(errors.New("boom"), nil); got != ExitRuntimeError {
|
||||||
t.Fatalf("expected runtime exit code, got %d", got)
|
t.Fatalf("expected runtime exit code, got %d", got)
|
||||||
}
|
}
|
||||||
if got := determineExitCode(nil, &domain.RunResult{Validation: domain.ValidationResult{Status: domain.ValidationFailed}}); got != ExitValidationFailed {
|
if got := determineExitCode(nil, &scriptorium.RunResult{Validation: scriptorium.ValidationResult{Status: scriptorium.ValidationFailed}}); got != ExitValidationFailed {
|
||||||
t.Fatalf("expected validation exit code, got %d", got)
|
t.Fatalf("expected validation exit code, got %d", got)
|
||||||
}
|
}
|
||||||
if got := determineExitCode(nil, &domain.RunResult{Validation: domain.ValidationResult{Status: domain.ValidationPassed}}); got != ExitOK {
|
if got := determineExitCode(nil, &scriptorium.RunResult{Validation: scriptorium.ValidationResult{Status: scriptorium.ValidationPassed}}); got != ExitOK {
|
||||||
t.Fatalf("expected success exit code for passed validation, got %d", got)
|
t.Fatalf("expected success exit code for passed validation, got %d", got)
|
||||||
}
|
}
|
||||||
if got := determineExitCode(nil, &domain.RunResult{Validation: domain.ValidationResult{Status: domain.ValidationSkipped}}); got != ExitOK {
|
if got := determineExitCode(nil, &scriptorium.RunResult{Validation: scriptorium.ValidationResult{Status: scriptorium.ValidationSkipped}}); got != ExitOK {
|
||||||
t.Fatalf("expected success exit code for skipped validation, got %d", got)
|
t.Fatalf("expected success exit code for skipped validation, got %d", got)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1208,12 +1242,12 @@ func TestWriteOutputAndSummaryUseSeparateWriters(t *testing.T) {
|
|||||||
if err := writeOutput(&stdout, "", []byte("artifact-body")); err != nil {
|
if err := writeOutput(&stdout, "", []byte("artifact-body")); err != nil {
|
||||||
t.Fatalf("unexpected writeOutput error: %v", err)
|
t.Fatalf("unexpected writeOutput error: %v", err)
|
||||||
}
|
}
|
||||||
printSummary(&stderr, &domain.RunResult{
|
printSummary(&stderr, &scriptorium.RunResult{
|
||||||
PromptID: "p",
|
PromptID: "p",
|
||||||
PromptVersion: "1",
|
PromptVersion: "1",
|
||||||
SelectedProfileID: "exec",
|
SelectedProfileID: "exec",
|
||||||
ModelName: "m",
|
ModelName: "m",
|
||||||
Validation: domain.ValidationResult{Status: domain.ValidationPassed, Mode: domain.ValidationBasic},
|
Validation: scriptorium.ValidationResult{Status: scriptorium.ValidationPassed, Mode: scriptorium.ValidationBasic},
|
||||||
RenderedPromptHash: "h",
|
RenderedPromptHash: "h",
|
||||||
InputHashes: map[string]string{"in": "x"},
|
InputHashes: map[string]string{"in": "x"},
|
||||||
})
|
})
|
||||||
@@ -1232,15 +1266,15 @@ func TestWriteOutputAndSummaryUseSeparateWriters(t *testing.T) {
|
|||||||
func TestPrintSummaryIncludesCacheUsageWhenPresent(t *testing.T) {
|
func TestPrintSummaryIncludesCacheUsageWhenPresent(t *testing.T) {
|
||||||
var stderr bytes.Buffer
|
var stderr bytes.Buffer
|
||||||
|
|
||||||
printSummary(&stderr, &domain.RunResult{
|
printSummary(&stderr, &scriptorium.RunResult{
|
||||||
PromptID: "p",
|
PromptID: "p",
|
||||||
PromptVersion: "1",
|
PromptVersion: "1",
|
||||||
SelectedProfileID: "exec",
|
SelectedProfileID: "exec",
|
||||||
ModelName: "m",
|
ModelName: "m",
|
||||||
Validation: domain.ValidationResult{Status: domain.ValidationPassed, Mode: domain.ValidationBasic},
|
Validation: scriptorium.ValidationResult{Status: scriptorium.ValidationPassed, Mode: scriptorium.ValidationBasic},
|
||||||
RenderedPromptHash: "h",
|
RenderedPromptHash: "h",
|
||||||
InputHashes: map[string]string{"in": "x"},
|
InputHashes: map[string]string{"in": "x"},
|
||||||
Usage: domain.TokenUsage{
|
Usage: scriptorium.TokenUsage{
|
||||||
PromptTokens: 10,
|
PromptTokens: 10,
|
||||||
CompletionTokens: 5,
|
CompletionTokens: 5,
|
||||||
TotalTokens: 15,
|
TotalTokens: 15,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
// Package format formats already-prepared domain data for adapters.
|
// Package format formats already-prepared public data for adapters.
|
||||||
package format
|
package format
|
||||||
|
|
||||||
import (
|
import (
|
||||||
@@ -9,7 +9,7 @@ import (
|
|||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"gitea.maximumdirect.net/eric/scriptorium/internal/domain"
|
"gitea.maximumdirect.net/eric/scriptorium"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrUnknownPreparedRunFormat = errors.New("unknown prepared run format")
|
var ErrUnknownPreparedRunFormat = errors.New("unknown prepared run format")
|
||||||
@@ -26,7 +26,7 @@ const (
|
|||||||
|
|
||||||
// PreparedRunFormatter serializes a prepared run without performing use case work.
|
// PreparedRunFormatter serializes a prepared run without performing use case work.
|
||||||
type PreparedRunFormatter interface {
|
type PreparedRunFormatter interface {
|
||||||
Format(prepared *domain.PreparedRun) ([]byte, error)
|
Format(prepared *scriptorium.PreparedRun) ([]byte, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ParsePreparedRunOutputFormat parses a format name.
|
// ParsePreparedRunOutputFormat parses a format name.
|
||||||
@@ -56,7 +56,7 @@ func FormatterForPreparedRun(outputFormat PreparedRunOutputFormat) (PreparedRunF
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FormatPreparedRun formats a prepared run using the selected format.
|
// FormatPreparedRun formats a prepared run using the selected format.
|
||||||
func FormatPreparedRun(prepared *domain.PreparedRun, outputFormat PreparedRunOutputFormat) ([]byte, error) {
|
func FormatPreparedRun(prepared *scriptorium.PreparedRun, outputFormat PreparedRunOutputFormat) ([]byte, error) {
|
||||||
formatter, err := FormatterForPreparedRun(outputFormat)
|
formatter, err := FormatterForPreparedRun(outputFormat)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -65,7 +65,7 @@ func FormatPreparedRun(prepared *domain.PreparedRun, outputFormat PreparedRunOut
|
|||||||
}
|
}
|
||||||
|
|
||||||
// FormatPreparedRunByName parses a format name and formats a prepared run.
|
// FormatPreparedRunByName parses a format name and formats a prepared run.
|
||||||
func FormatPreparedRunByName(prepared *domain.PreparedRun, rawFormat string) ([]byte, error) {
|
func FormatPreparedRunByName(prepared *scriptorium.PreparedRun, rawFormat string) ([]byte, error) {
|
||||||
outputFormat, err := ParsePreparedRunOutputFormat(rawFormat)
|
outputFormat, err := ParsePreparedRunOutputFormat(rawFormat)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -75,7 +75,7 @@ func FormatPreparedRunByName(prepared *domain.PreparedRun, rawFormat string) ([]
|
|||||||
|
|
||||||
type jsonPreparedRunFormatter struct{}
|
type jsonPreparedRunFormatter struct{}
|
||||||
|
|
||||||
func (jsonPreparedRunFormatter) Format(prepared *domain.PreparedRun) ([]byte, error) {
|
func (jsonPreparedRunFormatter) Format(prepared *scriptorium.PreparedRun) ([]byte, error) {
|
||||||
if prepared == nil {
|
if prepared == nil {
|
||||||
return nil, errors.New("prepared run is nil")
|
return nil, errors.New("prepared run is nil")
|
||||||
}
|
}
|
||||||
@@ -84,7 +84,7 @@ func (jsonPreparedRunFormatter) Format(prepared *domain.PreparedRun) ([]byte, er
|
|||||||
|
|
||||||
type textPreparedRunFormatter struct{}
|
type textPreparedRunFormatter struct{}
|
||||||
|
|
||||||
func (textPreparedRunFormatter) Format(prepared *domain.PreparedRun) ([]byte, error) {
|
func (textPreparedRunFormatter) Format(prepared *scriptorium.PreparedRun) ([]byte, error) {
|
||||||
if prepared == nil {
|
if prepared == nil {
|
||||||
return nil, errors.New("prepared run is nil")
|
return nil, errors.New("prepared run is nil")
|
||||||
}
|
}
|
||||||
@@ -146,7 +146,7 @@ func (textPreparedRunFormatter) Format(prepared *domain.PreparedRun) ([]byte, er
|
|||||||
|
|
||||||
fmt.Fprintln(&b, "messages:")
|
fmt.Fprintln(&b, "messages:")
|
||||||
roleOrder := make([]string, 0)
|
roleOrder := make([]string, 0)
|
||||||
byRole := make(map[string][]domain.RenderedMessage)
|
byRole := make(map[string][]scriptorium.RenderedMessage)
|
||||||
for _, msg := range prepared.Messages {
|
for _, msg := range prepared.Messages {
|
||||||
if _, exists := byRole[msg.Role]; !exists {
|
if _, exists := byRole[msg.Role]; !exists {
|
||||||
roleOrder = append(roleOrder, msg.Role)
|
roleOrder = append(roleOrder, msg.Role)
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gitea.maximumdirect.net/eric/scriptorium/internal/domain"
|
"gitea.maximumdirect.net/eric/scriptorium"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestTextFormatterIncludesPreparedRunDetails(t *testing.T) {
|
func TestTextFormatterIncludesPreparedRunDetails(t *testing.T) {
|
||||||
@@ -94,9 +94,8 @@ func TestTextFormatterDoesNotIncludeResolvedAPIKeyValue(t *testing.T) {
|
|||||||
|
|
||||||
func TestTextFormatterDoesNotIncludeDirectAPIKeyValue(t *testing.T) {
|
func TestTextFormatterDoesNotIncludeDirectAPIKeyValue(t *testing.T) {
|
||||||
const directKey = "direct-format-key"
|
const directKey = "direct-format-key"
|
||||||
|
// PreparedRun intentionally has no field for direct API keys.
|
||||||
prepared := samplePreparedRun()
|
prepared := samplePreparedRun()
|
||||||
prepared.EffectiveModelParams.APIKey = directKey
|
|
||||||
|
|
||||||
out, err := FormatPreparedRun(prepared, PreparedRunFormatText)
|
out, err := FormatPreparedRun(prepared, PreparedRunFormatText)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected no error, got %v", err)
|
t.Fatalf("expected no error, got %v", err)
|
||||||
@@ -108,12 +107,12 @@ func TestTextFormatterDoesNotIncludeDirectAPIKeyValue(t *testing.T) {
|
|||||||
|
|
||||||
func TestTextFormatterIncludesMessageCacheControlBeforeContent(t *testing.T) {
|
func TestTextFormatterIncludesMessageCacheControlBeforeContent(t *testing.T) {
|
||||||
prepared := samplePreparedRun()
|
prepared := samplePreparedRun()
|
||||||
prepared.Messages = []domain.RenderedMessage{
|
prepared.Messages = []scriptorium.RenderedMessage{
|
||||||
{
|
{
|
||||||
Role: "system",
|
Role: "system",
|
||||||
Content: "System guidance.",
|
Content: "System guidance.",
|
||||||
CacheControl: &domain.CacheControl{
|
CacheControl: &scriptorium.CacheControl{
|
||||||
Type: domain.CacheControlEphemeral,
|
Type: scriptorium.CacheControlEphemeral,
|
||||||
TTL: "1h",
|
TTL: "1h",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -148,12 +147,12 @@ func TestTextFormatterIncludesSessionIDWhenPresent(t *testing.T) {
|
|||||||
|
|
||||||
func TestTextFormatterOmitsEmptyCacheControlTTL(t *testing.T) {
|
func TestTextFormatterOmitsEmptyCacheControlTTL(t *testing.T) {
|
||||||
prepared := samplePreparedRun()
|
prepared := samplePreparedRun()
|
||||||
prepared.Messages = []domain.RenderedMessage{
|
prepared.Messages = []scriptorium.RenderedMessage{
|
||||||
{
|
{
|
||||||
Role: "system",
|
Role: "system",
|
||||||
Content: "System guidance.",
|
Content: "System guidance.",
|
||||||
CacheControl: &domain.CacheControl{
|
CacheControl: &scriptorium.CacheControl{
|
||||||
Type: domain.CacheControlEphemeral,
|
Type: scriptorium.CacheControlEphemeral,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -231,12 +230,12 @@ func TestJSONFormatterEmitsValidJSONAndIncludesPreparedRunFields(t *testing.T) {
|
|||||||
|
|
||||||
func TestJSONFormatterIncludesMessageCacheControlOnlyWhenPresent(t *testing.T) {
|
func TestJSONFormatterIncludesMessageCacheControlOnlyWhenPresent(t *testing.T) {
|
||||||
prepared := samplePreparedRun()
|
prepared := samplePreparedRun()
|
||||||
prepared.Messages = []domain.RenderedMessage{
|
prepared.Messages = []scriptorium.RenderedMessage{
|
||||||
{
|
{
|
||||||
Role: "system",
|
Role: "system",
|
||||||
Content: "System guidance.",
|
Content: "System guidance.",
|
||||||
CacheControl: &domain.CacheControl{
|
CacheControl: &scriptorium.CacheControl{
|
||||||
Type: domain.CacheControlEphemeral,
|
Type: scriptorium.CacheControlEphemeral,
|
||||||
TTL: "1h",
|
TTL: "1h",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
@@ -262,7 +261,7 @@ func TestJSONFormatterIncludesMessageCacheControlOnlyWhenPresent(t *testing.T) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
t.Fatalf("expected first message cache_control, got %#v", decoded.Messages[0])
|
t.Fatalf("expected first message cache_control, got %#v", decoded.Messages[0])
|
||||||
}
|
}
|
||||||
if cacheControl["type"] != string(domain.CacheControlEphemeral) || cacheControl["ttl"] != "1h" {
|
if cacheControl["type"] != string(scriptorium.CacheControlEphemeral) || cacheControl["ttl"] != "1h" {
|
||||||
t.Fatalf("unexpected cache_control payload: %#v", cacheControl)
|
t.Fatalf("unexpected cache_control payload: %#v", cacheControl)
|
||||||
}
|
}
|
||||||
if _, ok := decoded.Messages[1]["cache_control"]; ok {
|
if _, ok := decoded.Messages[1]["cache_control"]; ok {
|
||||||
@@ -285,9 +284,8 @@ func TestJSONFormatterDoesNotIncludeResolvedAPIKeyValue(t *testing.T) {
|
|||||||
|
|
||||||
func TestJSONFormatterDoesNotIncludeDirectAPIKeyValue(t *testing.T) {
|
func TestJSONFormatterDoesNotIncludeDirectAPIKeyValue(t *testing.T) {
|
||||||
const directKey = "direct-format-key"
|
const directKey = "direct-format-key"
|
||||||
|
// PreparedRun intentionally has no field for direct API keys.
|
||||||
prepared := samplePreparedRun()
|
prepared := samplePreparedRun()
|
||||||
prepared.EffectiveModelParams.APIKey = directKey
|
|
||||||
|
|
||||||
out, err := FormatPreparedRun(prepared, PreparedRunFormatJSON)
|
out, err := FormatPreparedRun(prepared, PreparedRunFormatJSON)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("expected no error, got %v", err)
|
t.Fatalf("expected no error, got %v", err)
|
||||||
@@ -342,13 +340,13 @@ func TestFormatPreparedRunByNameUnknownFailsClearly(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func samplePreparedRun() *domain.PreparedRun {
|
func samplePreparedRun() *scriptorium.PreparedRun {
|
||||||
return &domain.PreparedRun{
|
return &scriptorium.PreparedRun{
|
||||||
PromptID: "prompt.id",
|
PromptID: "prompt.id",
|
||||||
PromptVersion: "v1",
|
PromptVersion: "v1",
|
||||||
PromptHash: "prompt-hash",
|
PromptHash: "prompt-hash",
|
||||||
SelectedProfileID: "local-fast",
|
SelectedProfileID: "local-fast",
|
||||||
EffectiveModelParams: domain.ExecutionTarget{
|
EffectiveModelParams: scriptorium.ExecutionTarget{
|
||||||
Endpoint: "http://llm/v1",
|
Endpoint: "http://llm/v1",
|
||||||
Model: "gpt-test",
|
Model: "gpt-test",
|
||||||
Temperature: 0.4,
|
Temperature: 0.4,
|
||||||
@@ -364,7 +362,7 @@ func samplePreparedRun() *domain.PreparedRun {
|
|||||||
"glossary": "hash-glossary",
|
"glossary": "hash-glossary",
|
||||||
},
|
},
|
||||||
RenderedPromptHash: "rendered-hash",
|
RenderedPromptHash: "rendered-hash",
|
||||||
Messages: []domain.RenderedMessage{
|
Messages: []scriptorium.RenderedMessage{
|
||||||
{Role: "system", Content: "System guidance."},
|
{Role: "system", Content: "System guidance."},
|
||||||
{Role: "user", Content: "Summarize the transcript.\nInclude key entities."},
|
{Role: "user", Content: "Summarize the transcript.\nInclude key entities."},
|
||||||
{Role: "user", Content: "Second user message."},
|
{Role: "user", Content: "Second user message."},
|
||||||
|
|||||||
Reference in New Issue
Block a user