package adapters import ( "testing" "google.golang.org/protobuf/types/known/structpb" iop "iop/proto/gen/iop" ) func TestCLIConfFromProto_ProfileRuntimeOptions(t *testing.T) { m := &iop.CLIAdapterConfig{ Profiles: map[string]*iop.CLIProfileConfig{ "claude": { Command: "claude", Args: []string{"-p"}, OutputFormat: "claude-json", }, }, } cfg := cliConfFromProto(m) prof, ok := cfg.Profiles["claude"] if !ok { t.Fatal("expected claude profile") } if prof.Command != "claude" { t.Fatalf("command: got %q", prof.Command) } if len(prof.Args) != 1 || prof.Args[0] != "-p" { t.Fatalf("args: got %#v", prof.Args) } if prof.OutputFormat != "claude-json" { t.Fatalf("output_format: got %q", prof.OutputFormat) } } func TestCLIConfFromProto_ClaudeHeadlessBypassProfile(t *testing.T) { m := &iop.CLIAdapterConfig{ Profiles: map[string]*iop.CLIProfileConfig{ "claude": { Command: "claude", Args: []string{"-p", "--dangerously-skip-permissions"}, }, }, } cfg := cliConfFromProto(m) prof, ok := cfg.Profiles["claude"] if !ok { t.Fatal("expected claude profile") } if len(prof.Args) != 2 || prof.Args[0] != "-p" || prof.Args[1] != "--dangerously-skip-permissions" { t.Fatalf("args: got %#v", prof.Args) } if prof.Persistent || prof.Terminal { t.Fatalf("expected persistent/terminal=false") } } func TestCLIConfFromProto_AntigravityHeadlessProfile(t *testing.T) { m := &iop.CLIAdapterConfig{ Profiles: map[string]*iop.CLIProfileConfig{ "antigravity": { Command: "agy", Args: []string{"--dangerously-skip-permissions", "--print"}, }, }, } cfg := cliConfFromProto(m) prof, ok := cfg.Profiles["antigravity"] if !ok { t.Fatal("expected antigravity profile") } if len(prof.Args) != 2 || prof.Args[0] != "--dangerously-skip-permissions" || prof.Args[1] != "--print" { t.Fatalf("args: got %#v", prof.Args) } } func TestCLIConfFromProto_ClineConfigProfile(t *testing.T) { m := &iop.CLIAdapterConfig{ Profiles: map[string]*iop.CLIProfileConfig{ "cline-dgx": { Command: "/config/.npm-global/bin/cline", Args: []string{"-y", "--json", "--config", "/config/.cline/profiles/ollama-dgx"}, OutputFormat: "cline-json", }, }, } cfg := cliConfFromProto(m) prof, ok := cfg.Profiles["cline-dgx"] if !ok { t.Fatal("expected cline-dgx profile") } if prof.Command != "/config/.npm-global/bin/cline" { t.Fatalf("command: got %q", prof.Command) } if len(prof.Args) != 4 { t.Fatalf("args: got %#v", prof.Args) } if prof.OutputFormat != "cline-json" { t.Fatalf("output_format: got %q", prof.OutputFormat) } } func TestCLIConfFromProto_ProfileCompletionMarker(t *testing.T) { m := &iop.CLIAdapterConfig{ Profiles: map[string]*iop.CLIProfileConfig{ "codex": { Command: "codex", Persistent: true, CompletionMarker: &iop.CLICompletionMarker{ Line: "[[DONE]]", Regex: `^\[\[DONE\]\]$`, }, }, }, } cfg := cliConfFromProto(m) prof := cfg.Profiles["codex"] if prof.CompletionMarker.Line != "[[DONE]]" { t.Fatalf("line: got %q", prof.CompletionMarker.Line) } if prof.CompletionMarker.Regex != `^\[\[DONE\]\]$` { t.Fatalf("regex: got %q", prof.CompletionMarker.Regex) } } func TestCLIConfFromProto_PersistentAndIdleTimeouts(t *testing.T) { m := &iop.CLIAdapterConfig{ Profiles: map[string]*iop.CLIProfileConfig{ "codex": { Command: "codex", Persistent: true, ResponseIdleTimeoutMs: 1500, StartupIdleTimeoutMs: 300, }, }, } cfg := cliConfFromProto(m) prof := cfg.Profiles["codex"] if !prof.Persistent { t.Fatal("persistent") } if prof.ResponseIdleTimeoutMS != 1500 { t.Fatalf("response_idle_timeout_ms: got %d", prof.ResponseIdleTimeoutMS) } if prof.StartupIdleTimeoutMS != 300 { t.Fatalf("startup_idle_timeout_ms: got %d", prof.StartupIdleTimeoutMS) } } func TestCLIConfFromProto_NilSettings(t *testing.T) { cfg := cliConfFromProto(&iop.CLIAdapterConfig{}) if !cfg.Enabled { t.Fatal("expected enabled=true") } if cfg.Profiles == nil { t.Fatal("profiles map should be initialized") } } func TestCLIConfFromProto_OpencodeSSEMode(t *testing.T) { m := &iop.CLIAdapterConfig{ Profiles: map[string]*iop.CLIProfileConfig{ "opencode": { Command: "/usr/local/bin/opencode", Args: []string{"--model", "m1", "--dangerously-skip-permissions"}, Mode: "opencode-sse", }, }, } cfg := cliConfFromProto(m) prof, ok := cfg.Profiles["opencode"] if !ok { t.Fatal("expected opencode profile") } if prof.Mode != "opencode-sse" { t.Errorf("mode: got %q", prof.Mode) } if len(prof.Args) != 3 { t.Fatalf("args: got %#v", prof.Args) } } func TestCLIConfFromStruct_OpencodeSSEModeLegacy(t *testing.T) { st, err := structpb.NewStruct(map[string]any{ "profiles": map[string]any{ "opencode": map[string]any{ "command": "/usr/local/bin/opencode", "args": []any{"--model", "m1"}, "mode": "opencode-sse", }, }, }) if err != nil { t.Fatalf("structpb: %v", err) } cfg := cliConfFromStruct(st) prof, ok := cfg.Profiles["opencode"] if !ok { t.Fatal("expected opencode profile") } if prof.Mode != "opencode-sse" { t.Errorf("mode: got %q", prof.Mode) } } // Legacy structpb fallback regression tests — these exercise the path taken // when an older edge sends AdapterConfig.settings instead of the typed oneof. func TestOllamaConfFromStruct_LegacyPayload(t *testing.T) { st, err := structpb.NewStruct(map[string]any{ "base_url": "http://legacy:11434", "context_size": float64(262144), }) if err != nil { t.Fatalf("structpb: %v", err) } cfg := ollamaConfFromStruct(st) if !cfg.Enabled { t.Fatal("expected enabled=true") } if cfg.BaseURL != "http://legacy:11434" { t.Fatalf("base_url: got %q", cfg.BaseURL) } if cfg.ContextSize != 262144 { t.Fatalf("context_size: got %d", cfg.ContextSize) } } func TestVllmConfFromStruct_LegacyPayload(t *testing.T) { st, err := structpb.NewStruct(map[string]any{"endpoint": "http://legacy:8000"}) if err != nil { t.Fatalf("structpb: %v", err) } cfg := vllmConfFromStruct(st) if !cfg.Enabled { t.Fatal("expected enabled=true") } if cfg.Endpoint != "http://legacy:8000" { t.Fatalf("endpoint: got %q", cfg.Endpoint) } } func TestCLIConfFromStruct_LegacyPayload(t *testing.T) { st, err := structpb.NewStruct(map[string]any{ "profiles": map[string]any{ "codex": map[string]any{ "command": "codex", "args": []any{"--legacy"}, "env": []any{"K=V"}, "persistent": true, "terminal": false, "response_idle_timeout_ms": 1500, "startup_idle_timeout_ms": 300, "output_format": "codex-json", "completion_marker": map[string]any{ "line": "[[DONE]]", "regex": `^\[\[DONE\]\]$`, }, }, }, }) if err != nil { t.Fatalf("structpb: %v", err) } cfg := cliConfFromStruct(st) prof, ok := cfg.Profiles["codex"] if !ok { t.Fatal("expected codex profile") } if prof.Command != "codex" { t.Fatalf("command: got %q", prof.Command) } if len(prof.Args) != 1 || prof.Args[0] != "--legacy" { t.Fatalf("args: got %#v", prof.Args) } if len(prof.Env) != 1 || prof.Env[0] != "K=V" { t.Fatalf("env: got %#v", prof.Env) } if !prof.Persistent { t.Fatal("persistent") } if prof.ResponseIdleTimeoutMS != 1500 { t.Fatalf("response_idle_timeout_ms: got %d", prof.ResponseIdleTimeoutMS) } if prof.StartupIdleTimeoutMS != 300 { t.Fatalf("startup_idle_timeout_ms: got %d", prof.StartupIdleTimeoutMS) } if prof.OutputFormat != "codex-json" { t.Fatalf("output_format: got %q", prof.OutputFormat) } if prof.CompletionMarker.Line != "[[DONE]]" || prof.CompletionMarker.Regex != `^\[\[DONE\]\]$` { t.Fatalf("completion_marker: got %+v", prof.CompletionMarker) } } // End-to-end fallback through BuildFromPayload: oneof empty, settings populated. func TestBuildFromPayload_LegacySettingsFallback(t *testing.T) { ollamaSt, _ := structpb.NewStruct(map[string]any{"base_url": "http://legacy:11434"}) cliSt, _ := structpb.NewStruct(map[string]any{ "profiles": map[string]any{ "codex": map[string]any{ "command": "codex", "args": []any{"--legacy"}, }, }, }) payload := &iop.NodeConfigPayload{ Adapters: []*iop.AdapterConfig{ {Type: "ollama", Enabled: true, Settings: ollamaSt}, {Type: "cli", Enabled: true, Settings: cliSt}, }, } reg, err := BuildFromPayload(payload, nil) if err != nil { t.Fatalf("build: %v", err) } for _, name := range []string{"ollama", "cli"} { if _, ok := reg.Get(name); !ok { t.Fatalf("expected %s adapter registered from legacy settings", name) } } } func TestBuildFromPayload_LegacyVllmSettingsRegistered(t *testing.T) { vllmSt, _ := structpb.NewStruct(map[string]any{"endpoint": "http://legacy:8000"}) reg, err := BuildFromPayload(&iop.NodeConfigPayload{ Adapters: []*iop.AdapterConfig{ {Type: "vllm", Enabled: true, Settings: vllmSt}, }, }, nil) if err != nil { t.Fatalf("build from payload: %v", err) } if _, ok := reg.Get("vllm"); !ok { t.Fatal("expected vllm adapter registered from legacy settings") } } func TestBuildFromPayload_TypedMockConfig(t *testing.T) { reg, err := BuildFromPayload(&iop.NodeConfigPayload{ Adapters: []*iop.AdapterConfig{ { Type: "mock", Enabled: true, Config: &iop.AdapterConfig_Mock{Mock: &iop.MockAdapterConfig{}}, }, }, }, nil) if err != nil { t.Fatalf("build: %v", err) } if _, ok := reg.Get("mock"); !ok { t.Fatal("expected mock adapter registered from typed MockAdapterConfig") } }