Reuse prepared execution snapshot ownership
This commit is contained in:
@@ -50,10 +50,12 @@ func (r *Runner) PrepareExecution(ctx context.Context, req domain.RunRequest) (*
|
||||
return nil, err
|
||||
}
|
||||
|
||||
executionSnapshot, err := clonePreparedRun(operation.run)
|
||||
executionSnapshot := operation.run
|
||||
extraParams, err := jsonvalue.CopyMap(executionSnapshot.EffectiveModelParams.ExtraParams)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: failed to copy prepared execution: %v", ErrInvalidRequest, err)
|
||||
}
|
||||
executionSnapshot.EffectiveModelParams.ExtraParams = extraParams
|
||||
|
||||
details, err := clonePreparedRun(executionSnapshot)
|
||||
if err != nil {
|
||||
|
||||
@@ -631,6 +631,124 @@ func TestRunnerPreparedExecutionOwnershipUseAndDiscard(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunnerPreparedExecutionDetachesTransferredSnapshotSources(t *testing.T) {
|
||||
newExtras := func(value string) map[string]any {
|
||||
return map[string]any{"provider_options": map[string]any{
|
||||
"provider": map[string]any{"settings": map[string]any{"labels": []any{value}}},
|
||||
}}
|
||||
}
|
||||
extraLabel := func(extraParams map[string]any) string {
|
||||
return extraParams["provider_options"].(map[string]any)["provider"].(map[string]any)["settings"].(map[string]any)["labels"].([]any)[0].(string)
|
||||
}
|
||||
mutateExtra := func(extraParams map[string]any, value string) {
|
||||
extraParams["provider_options"].(map[string]any)["provider"].(map[string]any)["settings"].(map[string]any)["labels"].([]any)[0] = value
|
||||
}
|
||||
|
||||
for _, test := range []struct {
|
||||
name string
|
||||
requestOverride bool
|
||||
}{
|
||||
{name: "profile target"},
|
||||
{name: "request override", requestOverride: true},
|
||||
} {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
profileExtras := newExtras("profile source")
|
||||
requestExtras := newExtras("request source")
|
||||
profile := defaultExecutionProfile()
|
||||
profile.ResolvedTarget.ExtraParams = profileExtras
|
||||
|
||||
schemaDocument := map[string]any{
|
||||
"type": "object",
|
||||
"properties": map[string]any{"value": map[string]any{"type": "string"}},
|
||||
}
|
||||
definition := promptDef(domain.FormatJSON, domain.ValidationJSONSchema, 0)
|
||||
definition.Validation.SchemaPath = "schema.json"
|
||||
control := &domain.CacheControl{Type: domain.CacheControlEphemeral, TTL: "1h"}
|
||||
rendered := &domain.RenderedPrompt{Messages: []domain.RenderedMessage{{
|
||||
Role: domain.RoleUser, Content: "captured rendering", CacheControl: control,
|
||||
}}}
|
||||
renderer := &fakeRenderer{rendered: rendered}
|
||||
sourceArtifact := &domain.Artifact{Body: []byte("captured input"), Hash: "captured-input-hash"}
|
||||
reader := &fakeArtifactReader{artifactsByURI: map[string]*domain.Artifact{"source": sourceArtifact}}
|
||||
llmClient := &fakeLLM{resp: &domain.GenerateResponse{Content: `{"value":"ok"}`}}
|
||||
validator := &recordingValidationPreparer{
|
||||
plan: &recordingPreparedValidation{schemaDocument: schemaDocument},
|
||||
}
|
||||
runner := NewRunner(
|
||||
&fakePromptRepo{def: definition},
|
||||
&fakeExecutionProfileRepo{profiles: map[string]*domain.ExecutionProfile{"exec": profile}},
|
||||
reader, renderer, llmClient, validator, nil,
|
||||
)
|
||||
request := domain.RunRequest{
|
||||
PromptID: "p", PromptVersion: "1", ProfileID: "exec",
|
||||
Inputs: map[string]domain.ArtifactRef{
|
||||
"transcript": {Type: domain.ArtifactRefFile, URI: "source"},
|
||||
},
|
||||
}
|
||||
wantLabel := "profile source"
|
||||
if test.requestOverride {
|
||||
request.Execution = &domain.ExecutionTargetOverride{ExtraParams: requestExtras}
|
||||
wantLabel = "request source"
|
||||
}
|
||||
|
||||
prepared, err := runner.PrepareExecution(context.Background(), request)
|
||||
if err != nil {
|
||||
t.Fatalf("prepare execution: %v", err)
|
||||
}
|
||||
mutateExtra(profileExtras, "mutated profile source")
|
||||
mutateExtra(requestExtras, "mutated request source")
|
||||
rendered.Messages[0].Content = "mutated renderer source"
|
||||
control.TTL = "mutated renderer cache metadata"
|
||||
schemaDocument["properties"].(map[string]any)["value"].(map[string]any)["type"] = "integer"
|
||||
sourceArtifact.Hash = "mutated source hash"
|
||||
|
||||
details := prepared.Details()
|
||||
if details == nil || len(details.Messages) != 1 || details.Messages[0].Content != "captured rendering" ||
|
||||
details.Messages[0].CacheControl == nil || details.Messages[0].CacheControl.TTL != "1h" ||
|
||||
details.InputHashes["transcript"] != "captured-input-hash" ||
|
||||
extraLabel(details.EffectiveModelParams.ExtraParams) != wantLabel ||
|
||||
details.StructuredOutput == nil || details.StructuredOutput.JSONSchema == nil ||
|
||||
details.StructuredOutput.JSONSchema.Schema.(map[string]any)["properties"].(map[string]any)["value"].(map[string]any)["type"] != "string" {
|
||||
t.Fatalf("prepared details retained a source alias: %#v", details)
|
||||
}
|
||||
|
||||
result, err := runner.RunPrepared(context.Background(), prepared)
|
||||
if err != nil || result == nil || !result.Validation.IsValid || result.InputHashes["transcript"] != "captured-input-hash" {
|
||||
t.Fatalf("run prepared snapshot=(%+v, %v)", result, err)
|
||||
}
|
||||
if len(llmClient.lastReq.Prompt.Messages) != 1 || llmClient.lastReq.StructuredOutput == nil ||
|
||||
llmClient.lastReq.StructuredOutput.JSONSchema == nil ||
|
||||
extraLabel(llmClient.lastReq.Target.ExtraParams) != wantLabel ||
|
||||
llmClient.lastReq.Prompt.Messages[0].Content != "captured rendering" ||
|
||||
llmClient.lastReq.Prompt.Messages[0].CacheControl == nil || llmClient.lastReq.Prompt.Messages[0].CacheControl.TTL != "1h" ||
|
||||
llmClient.lastReq.StructuredOutput.JSONSchema.Schema.(map[string]any)["properties"].(map[string]any)["value"].(map[string]any)["type"] != "string" {
|
||||
t.Fatalf("execution snapshot retained a source alias: %#v", llmClient.lastReq)
|
||||
}
|
||||
if completedDetails := prepared.Details(); completedDetails == nil ||
|
||||
len(completedDetails.Messages) != 1 || completedDetails.Messages[0].Content != "captured rendering" ||
|
||||
extraLabel(completedDetails.EffectiveModelParams.ExtraParams) != wantLabel {
|
||||
t.Fatalf("completed details changed after source mutation: %#v", completedDetails)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunnerPrepareExecutionClassifiesExtraCopyFailureAsInvalidRequest(t *testing.T) {
|
||||
profile := defaultExecutionProfile()
|
||||
profile.ResolvedTarget.ExtraParams = map[string]any{"unsupported": func() {}}
|
||||
runner := NewRunner(
|
||||
&fakePromptRepo{def: promptDef(domain.FormatText, domain.ValidationNone, 0)},
|
||||
&fakeExecutionProfileRepo{profiles: map[string]*domain.ExecutionProfile{"exec": profile}},
|
||||
defaultArtifactReader(), defaultRenderer(), &fakeLLM{forbid: true}, nil, nil,
|
||||
)
|
||||
prepared, err := runner.PrepareExecution(context.Background(), domain.RunRequest{
|
||||
PromptID: "p", ProfileID: "exec",
|
||||
})
|
||||
if prepared != nil || !errors.Is(err, ErrInvalidRequest) {
|
||||
t.Fatalf("prepared execution copy failure=(%v, %v), want ErrInvalidRequest", prepared, err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestRunnerPreparedExecutionWithoutValidatorSkipsValidation(t *testing.T) {
|
||||
runner := NewRunner(
|
||||
&fakePromptRepo{def: promptDef(domain.FormatJSON, domain.ValidationJSON, 0)},
|
||||
|
||||
Reference in New Issue
Block a user