iop/apps/edge/internal/bootstrap/runtime_execution_preset_test.go

179 lines
7.6 KiB
Go

package bootstrap
import (
"context"
"testing"
"iop/apps/edge/internal/configrefresh"
"iop/packages/go/config"
)
func TestRuntimeRefreshReplacesExecutionPresetGeneration(t *testing.T) {
initialPreset := config.ExecutionPreset{
ID: "preset-alpha",
Selector: config.ExecutionModelBinding{
Model: "gpt-4o",
Options: map[string]any{
"temp": 0.7,
"nested_map": map[string]string{"key1": "val1"},
"nested_slice": []string{"opt1", "opt2"},
},
},
AllowedModes: []string{config.ModeDirect, config.ModeLight},
Routes: map[string]config.ExecutionRoute{
config.ModeDirect: {Stages: []config.ExecutionRouteStage{}},
config.ModeLight: {
Stages: []config.ExecutionRouteStage{
{Role: "local", Model: "gpt-4o", Options: map[string]any{"stage_map": map[string]int{"a": 10}}},
{Role: "review", Model: "gpt-4o", Options: map[string]any{"stage_slice": []int{1, 2}}},
},
},
},
WorkspaceTools: []config.ExecutionWorkspaceToolAlternative{
{
Name: "default",
Operations: map[string]config.ExecutionWorkspaceOperation{
"read": {
ToolName: "file_read",
SchemaMatcher: map[string]any{"sm_map": map[string]bool{"read_ok": true}},
ArgumentMap: map[string]any{"arg_slice": []string{"path"}},
ResultMatcher: map[string]any{"res_map": map[string]any{"status": 200}},
},
"write": {
ToolName: "file_write",
CreatesParents: true,
SchemaMatcher: map[string]any{"sm": "w"},
ArgumentMap: map[string]any{"arg": "w"},
ResultMatcher: map[string]any{"res": "w"},
},
"delete": {
ToolName: "file_delete",
SchemaMatcher: map[string]any{"sm": "d"},
ArgumentMap: map[string]any{"arg": "d"},
ResultMatcher: map[string]any{"res": "d"},
},
},
},
},
}
cfg := newTestConfig()
cfg.ExecutionPresets = []config.ExecutionPreset{initialPreset}
rt, err := NewRuntime(cfg)
if err != nil {
t.Fatalf("NewRuntime: %v", err)
}
// Immutability test: mutate input slice and nested map after setting
cfg.ExecutionPresets[0].ID = "mutated-preset"
cfg.ExecutionPresets[0].Selector.Options["temp"] = 1.9
cfg.ExecutionPresets[0].Selector.Options["nested_map"].(map[string]string)["key1"] = "mutated_val"
cfg.ExecutionPresets[0].Selector.Options["nested_slice"].([]string)[0] = "mutated_opt"
cfg.ExecutionPresets[0].Routes[config.ModeLight].Stages[0].Options["stage_map"].(map[string]int)["a"] = 999
cfg.ExecutionPresets[0].WorkspaceTools[0].Operations["read"].SchemaMatcher["sm_map"].(map[string]bool)["read_ok"] = false
cfg.ExecutionPresets[0].WorkspaceTools[0].Operations["read"].ArgumentMap["arg_slice"].([]string)[0] = "mutated_path"
preRefreshSnap := rt.Input.OpenAI.ExecutionPresetsSnapshot()
if len(preRefreshSnap) != 1 || preRefreshSnap[0].ID != "preset-alpha" {
t.Fatalf("expected preRefreshSnap to retain preset-alpha, got: %+v", preRefreshSnap)
}
if preRefreshSnap[0].Selector.Options["temp"] != 0.7 {
t.Fatalf("expected preRefreshSnap options temp=0.7, got %v", preRefreshSnap[0].Selector.Options["temp"])
}
if val := preRefreshSnap[0].Selector.Options["nested_map"].(map[string]string)["key1"]; val != "val1" {
t.Fatalf("expected nested_map key1=val1, got %v", val)
}
if val := preRefreshSnap[0].Selector.Options["nested_slice"].([]string)[0]; val != "opt1" {
t.Fatalf("expected nested_slice[0]=opt1, got %v", val)
}
if val := preRefreshSnap[0].Routes[config.ModeLight].Stages[0].Options["stage_map"].(map[string]int)["a"]; val != 10 {
t.Fatalf("expected stage_map a=10, got %v", val)
}
if val := preRefreshSnap[0].WorkspaceTools[0].Operations["read"].SchemaMatcher["sm_map"].(map[string]bool)["read_ok"]; !val {
t.Fatalf("expected sm_map read_ok=true, got %v", val)
}
if val := preRefreshSnap[0].WorkspaceTools[0].Operations["read"].ArgumentMap["arg_slice"].([]string)[0]; val != "path" {
t.Fatalf("expected arg_slice[0]=path, got %v", val)
}
// Mutate preRefreshSnap read output and verify internal server snapshot is unchanged
preRefreshSnap[0].Selector.Options["temp"] = 99.0
preRefreshSnap[0].Selector.Options["nested_map"].(map[string]string)["key1"] = "snap_mutated"
preRefreshSnap[0].Selector.Options["nested_slice"].([]string)[0] = "snap_mutated"
preRefreshSnap[0].Routes[config.ModeLight].Stages[0].Options["stage_map"].(map[string]int)["a"] = 888
preRefreshSnap[0].WorkspaceTools[0].Operations["read"].SchemaMatcher["sm_map"].(map[string]bool)["read_ok"] = false
preRefreshSnap2, _ := rt.Input.OpenAI.ExecutionPreset("preset-alpha")
if preRefreshSnap2.Selector.Options["temp"] != 0.7 {
t.Fatalf("expected internal snapshot options temp=0.7, got %v", preRefreshSnap2.Selector.Options["temp"])
}
if val := preRefreshSnap2.Selector.Options["nested_map"].(map[string]string)["key1"]; val != "val1" {
t.Fatalf("expected internal snapshot nested_map key1=val1, got %v", val)
}
if val := preRefreshSnap2.Selector.Options["nested_slice"].([]string)[0]; val != "opt1" {
t.Fatalf("expected internal snapshot nested_slice[0]=opt1, got %v", val)
}
if val := preRefreshSnap2.Routes[config.ModeLight].Stages[0].Options["stage_map"].(map[string]int)["a"]; val != 10 {
t.Fatalf("expected internal snapshot stage_map a=10, got %v", val)
}
if val := preRefreshSnap2.WorkspaceTools[0].Operations["read"].SchemaMatcher["sm_map"].(map[string]bool)["read_ok"]; !val {
t.Fatalf("expected internal snapshot sm_map read_ok=true, got %v", val)
}
// Perform refresh to replace generation
candidatePreset1 := config.ExecutionPreset{
ID: "preset-alpha",
Selector: config.ExecutionModelBinding{Model: "gpt-4o-mini", Options: map[string]any{"temp": 0.2}},
AllowedModes: []string{config.ModeDirect},
Routes: map[string]config.ExecutionRoute{
config.ModeDirect: {Stages: []config.ExecutionRouteStage{}},
},
}
candidatePreset2 := config.ExecutionPreset{
ID: "preset-beta",
Selector: config.ExecutionModelBinding{Model: "claude-3-5-sonnet"},
AllowedModes: []string{config.ModeDirect},
Routes: map[string]config.ExecutionRoute{
config.ModeDirect: {Stages: []config.ExecutionRouteStage{}},
},
}
candidateCfg := newTestConfig()
candidateCfg.ExecutionPresets = []config.ExecutionPreset{candidatePreset1, candidatePreset2}
// Manually invoke applyMutableConfig
changes := []configrefresh.Change{
{Path: `execution_presets["preset-alpha"].selector`, Class: configrefresh.StatusApplied},
{Path: `execution_presets["preset-beta"]`, Class: configrefresh.StatusApplied},
}
_, err = rt.applyMutableConfig(context.Background(), candidateCfg, changes, "req-preset-refresh")
if err != nil {
t.Fatalf("applyMutableConfig: %v", err)
}
// Assert retained preRefreshSnap2 is still unchanged
if preRefreshSnap2.Selector.Model != "gpt-4o" {
t.Fatalf("retained pre-refresh snapshot mutated! expected gpt-4o, got %s", preRefreshSnap2.Selector.Model)
}
if val := preRefreshSnap2.Selector.Options["nested_map"].(map[string]string)["key1"]; val != "val1" {
t.Fatalf("retained pre-refresh snapshot mutated! expected key1=val1, got %v", val)
}
// Assert post-refresh read sees new generation
postRefreshSnap := rt.Input.OpenAI.ExecutionPresetsSnapshot()
if len(postRefreshSnap) != 2 {
t.Fatalf("expected 2 presets post refresh, got %d", len(postRefreshSnap))
}
pAlpha, okAlpha := rt.Input.OpenAI.ExecutionPreset("preset-alpha")
if !okAlpha || pAlpha.Selector.Model != "gpt-4o-mini" {
t.Fatalf("post-refresh preset-alpha model: got %s, want gpt-4o-mini", pAlpha.Selector.Model)
}
pBeta, okBeta := rt.Input.OpenAI.ExecutionPreset("preset-beta")
if !okBeta || pBeta.Selector.Model != "claude-3-5-sonnet" {
t.Fatalf("post-refresh preset-beta model: got %s, want claude-3-5-sonnet", pBeta.Selector.Model)
}
}