Add Scriptorium-backed LLM runtime
This commit is contained in:
@@ -8,6 +8,7 @@ import (
|
||||
"mime"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -57,8 +58,7 @@ type RunOutput struct {
|
||||
OutputFiles []contracts.OutputFile `json:"-"`
|
||||
}
|
||||
|
||||
func (r *Runner) Run(ctx context.Context, input RunInput) (RunOutput, error) {
|
||||
var output RunOutput
|
||||
func (r *Runner) Run(ctx context.Context, input RunInput) (output RunOutput, err error) {
|
||||
if r == nil {
|
||||
return output, fmt.Errorf("runner must not be nil")
|
||||
}
|
||||
@@ -69,8 +69,11 @@ func (r *Runner) Run(ctx context.Context, input RunInput) (RunOutput, error) {
|
||||
return output, err
|
||||
}
|
||||
|
||||
output.Warnings = append(output.Warnings, cloneWarnings(input.Warnings)...)
|
||||
output.Manifest = manifestFromPipeline(input)
|
||||
defer func() {
|
||||
output.Manifest.LLMProfiles = mergeLLMProfileManifests(input.LLMProfiles, llmProfileManifests(input.LLMClient))
|
||||
}()
|
||||
output.Warnings = append(output.Warnings, cloneWarnings(input.Warnings)...)
|
||||
|
||||
adapter, err := r.registries.Inputs.Build(input.Pipeline.Input.Module)
|
||||
if err != nil {
|
||||
@@ -524,6 +527,47 @@ func cloneLLMProfiles(profiles []artifacts.LLMProfileManifest) []artifacts.LLMPr
|
||||
return append([]artifacts.LLMProfileManifest(nil), profiles...)
|
||||
}
|
||||
|
||||
func llmProfileManifests(client contracts.StructuredLLMClient) []artifacts.LLMProfileManifest {
|
||||
provider, ok := client.(contracts.LLMProfileManifestProvider)
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
return provider.LLMProfileManifests()
|
||||
}
|
||||
|
||||
func mergeLLMProfileManifests(sources ...[]artifacts.LLMProfileManifest) []artifacts.LLMProfileManifest {
|
||||
merged := make(map[string]artifacts.LLMProfileManifest)
|
||||
for _, source := range sources {
|
||||
for _, profile := range source {
|
||||
id := strings.TrimSpace(profile.ID)
|
||||
provider := strings.TrimSpace(profile.Provider)
|
||||
model := strings.TrimSpace(profile.Model)
|
||||
key := id + "\x00" + provider + "\x00" + model
|
||||
if _, exists := merged[key]; exists {
|
||||
continue
|
||||
}
|
||||
merged[key] = artifacts.LLMProfileManifest{
|
||||
ID: id,
|
||||
Provider: provider,
|
||||
Model: model,
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(merged) == 0 {
|
||||
return nil
|
||||
}
|
||||
keys := make([]string, 0, len(merged))
|
||||
for key := range merged {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
out := make([]artifacts.LLMProfileManifest, 0, len(keys))
|
||||
for _, key := range keys {
|
||||
out = append(out, merged[key])
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func sourceInputMaterial(inputPath string, content []byte) contracts.LLMInputMaterial {
|
||||
return contracts.NewLLMInputMaterial(
|
||||
"source",
|
||||
|
||||
@@ -1212,6 +1212,28 @@ func TestRunManifestIncludesRunTimingAndLLMProfiles(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunManifestIncludesProfilesReportedByLLMClient(t *testing.T) {
|
||||
output, err := New(newRunnerRegistries(t, nil)).Run(context.Background(), RunInput{
|
||||
Pipeline: resolvedPipeline(),
|
||||
LLMClient: manifestReportingLLMClient{profiles: []artifacts.LLMProfileManifest{
|
||||
{ID: "profile-b", Provider: "openai-compatible", Model: "model-b"},
|
||||
{ID: "profile-a", Provider: "openai-compatible", Model: "model-a"},
|
||||
{ID: "profile-b", Provider: "openai-compatible", Model: "model-b"},
|
||||
}},
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("Run() error = %v, want nil", err)
|
||||
}
|
||||
|
||||
want := []artifacts.LLMProfileManifest{
|
||||
{ID: "profile-a", Provider: "openai-compatible", Model: "model-a"},
|
||||
{ID: "profile-b", Provider: "openai-compatible", Model: "model-b"},
|
||||
}
|
||||
if !reflect.DeepEqual(output.Manifest.LLMProfiles, want) {
|
||||
t.Fatalf("LLMProfiles = %#v, want %#v", output.Manifest.LLMProfiles, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunManifestGeneratesRunIDAndTimestamps(t *testing.T) {
|
||||
output, err := New(newRunnerRegistries(t, nil)).Run(context.Background(), RunInput{Pipeline: resolvedPipeline()})
|
||||
if err != nil {
|
||||
@@ -1693,6 +1715,15 @@ func (client fakeLLMClient) CompleteStructured(ctx context.Context, req contract
|
||||
return contracts.StructuredCompletionResponse{}, nil
|
||||
}
|
||||
|
||||
type manifestReportingLLMClient struct {
|
||||
fakeLLMClient
|
||||
profiles []artifacts.LLMProfileManifest
|
||||
}
|
||||
|
||||
func (client manifestReportingLLMClient) LLMProfileManifests() []artifacts.LLMProfileManifest {
|
||||
return append([]artifacts.LLMProfileManifest(nil), client.profiles...)
|
||||
}
|
||||
|
||||
func approveAll(candidates []artifacts.ArtifactCandidate) []contracts.ValidationDecision {
|
||||
decisions := make([]contracts.ValidationDecision, 0, len(candidates))
|
||||
for _, candidate := range candidates {
|
||||
|
||||
Reference in New Issue
Block a user