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) } }