From ec68425bb4ca4b14277e57bef046a258d18a8be6 Mon Sep 17 00:00:00 2001 From: krishrathi1 Date: Thu, 23 Jul 2026 12:08:15 +0530 Subject: [PATCH 1/2] fix(grok): forward role-specific model config to the Grok Build CLI GetLaunchCommand and GetRestoreCommand never read cfg.Config.Model, so a project's per-role agentConfig.model was silently dropped and Grok Build always launched on its own global default model instead of the configured one. Mirrors the pattern used by the Codex (#2869), Cline (#2894), Goose (#2885), and Autohand (#2889) adapters: append a trimmed --model flag on both the launch and restore argv, and advertise the field via GetConfigSpec. Fixes #2886 --- backend/internal/adapters/agent/grok/grok.go | 28 ++++++++- .../internal/adapters/agent/grok/grok_test.go | 62 ++++++++++++++++++- 2 files changed, 86 insertions(+), 4 deletions(-) diff --git a/backend/internal/adapters/agent/grok/grok.go b/backend/internal/adapters/agent/grok/grok.go index ed09212a6f..021c00142b 100644 --- a/backend/internal/adapters/agent/grok/grok.go +++ b/backend/internal/adapters/agent/grok/grok.go @@ -105,6 +105,22 @@ func (p *Plugin) Manifest() adapters.Manifest { } } +// GetConfigSpec reports the per-project agent config keys Grok Build understands. +func (p *Plugin) GetConfigSpec(ctx context.Context) (ports.ConfigSpec, error) { + if err := ctx.Err(); err != nil { + return ports.ConfigSpec{}, err + } + return ports.ConfigSpec{ + Fields: []ports.ConfigField{ + { + Key: "model", + Type: ports.ConfigFieldString, + Description: "Model override passed to `grok --model`.", + }, + }, + }, nil +} + // GetLaunchCommand builds `grok --no-auto-update [--permission-mode ] [-- prompt]`. // Prompt is delivered positionally so Grok starts an interactive coding session. // @@ -118,6 +134,7 @@ func (p *Plugin) GetLaunchCommand(ctx context.Context, cfg ports.LaunchConfig) ( cmd = []string{binary, "--no-auto-update"} appendApprovalFlags(&cmd, cfg.Permissions) + appendModelFlag(&cmd, cfg.Config) systemPrompt, err := launchSystemPromptText(cfg) if err != nil { @@ -179,9 +196,10 @@ func (p *Plugin) GetRestoreCommand(ctx context.Context, cfg ports.RestoreConfig) return nil, false, err } - cmd = make([]string, 0, 4) + cmd = make([]string, 0, 6) cmd = append(cmd, binary, "--no-auto-update") appendApprovalFlags(&cmd, cfg.Permissions) + appendModelFlag(&cmd, cfg.Config) systemPrompt, err := restoreSystemPromptText(cfg) if err != nil { return nil, false, err @@ -228,6 +246,14 @@ func grokClaudeSettingsPath(workspacePath string) string { return filepath.Join(workspacePath, grokClaudeSettingsDirName, grokClaudeSettingsFileName) } +// appendModelFlag appends a trimmed --model flag when a model override is +// configured. +func appendModelFlag(cmd *[]string, cfg ports.AgentConfig) { + if model := strings.TrimSpace(cfg.Model); model != "" { + *cmd = append(*cmd, "--model", model) + } +} + func appendApprovalFlags(cmd *[]string, permissions ports.PermissionMode) { switch ports.NormalizePermissionMode(permissions) { case ports.PermissionModeDefault: diff --git a/backend/internal/adapters/agent/grok/grok_test.go b/backend/internal/adapters/agent/grok/grok_test.go index d11837e331..130657a501 100644 --- a/backend/internal/adapters/agent/grok/grok_test.go +++ b/backend/internal/adapters/agent/grok/grok_test.go @@ -33,13 +33,69 @@ func TestManifest(t *testing.T) { } } -func TestGetConfigSpecEmpty(t *testing.T) { +func TestGetConfigSpecReportsModelField(t *testing.T) { spec, err := (&Plugin{}).GetConfigSpec(context.Background()) if err != nil { t.Fatalf("err: %v", err) } - if len(spec.Fields) != 0 { - t.Fatalf("expected no fields, got %d", len(spec.Fields)) + want := []ports.ConfigField{ + { + Key: "model", + Type: ports.ConfigFieldString, + Description: "Model override passed to `grok --model`.", + }, + } + if !reflect.DeepEqual(spec.Fields, want) { + t.Fatalf("config fields\nwant: %#v\n got: %#v", want, spec.Fields) + } +} + +func TestGetLaunchCommandAppendsConfiguredModel(t *testing.T) { + plugin := &Plugin{resolvedBinary: "grok"} + cmd, err := plugin.GetLaunchCommand(context.Background(), ports.LaunchConfig{ + Config: ports.AgentConfig{Model: " grok-build "}, + }) + if err != nil { + t.Fatalf("err: %v", err) + } + want := []string{"grok", "--no-auto-update", "--model", "grok-build"} + if !reflect.DeepEqual(cmd, want) { + t.Fatalf("cmd = %#v, want %#v", cmd, want) + } +} + +func TestGetLaunchCommandOmitsBlankConfiguredModel(t *testing.T) { + plugin := &Plugin{resolvedBinary: "grok"} + cmd, err := plugin.GetLaunchCommand(context.Background(), ports.LaunchConfig{ + Config: ports.AgentConfig{Model: " \t "}, + }) + if err != nil { + t.Fatalf("err: %v", err) + } + if strings.Contains(strings.Join(cmd, " "), "--model") { + t.Fatalf("cmd = %#v contains --model for blank model", cmd) + } +} + +func TestGetRestoreCommandAppendsConfiguredModel(t *testing.T) { + plugin := &Plugin{resolvedBinary: "grok"} + cmd, ok, err := plugin.GetRestoreCommand(context.Background(), ports.RestoreConfig{ + Config: ports.AgentConfig{Model: " grok-build "}, + Session: ports.SessionRef{ + Metadata: map[string]string{ + ports.MetadataKeyAgentSessionID: "sess-abc123", + }, + }, + }) + if err != nil { + t.Fatalf("err: %v", err) + } + if !ok { + t.Fatal("ok=false, want true") + } + want := []string{"grok", "--no-auto-update", "--model", "grok-build", "-r", "sess-abc123"} + if !reflect.DeepEqual(cmd, want) { + t.Fatalf("cmd = %#v, want %#v", cmd, want) } } From fc612ee87a01dd5a8c775026bfdd342d4cd19a6d Mon Sep 17 00:00:00 2001 From: krishrathi1 Date: Thu, 23 Jul 2026 22:31:53 +0530 Subject: [PATCH 2/2] fix(grok): use the officially documented -m flag instead of --model Review feedback on #3004 pointed out --model had no citation, unlike the --permission-mode flags above it which cite `grok -h`. The only source for --model was a third-party CLI cheat sheet. docs.x.ai/build/overview documents -m as the flag to "pick the model in headless mode or in the TUI" (`grok -p "Hello" -m my-model`), with no --model long form mentioned. Switch to the officially documented flag and cite the source in the doc comment. --- backend/internal/adapters/agent/grok/grok.go | 10 ++++++---- backend/internal/adapters/agent/grok/grok_test.go | 12 +++++++----- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/backend/internal/adapters/agent/grok/grok.go b/backend/internal/adapters/agent/grok/grok.go index 021c00142b..8f2fc55f85 100644 --- a/backend/internal/adapters/agent/grok/grok.go +++ b/backend/internal/adapters/agent/grok/grok.go @@ -115,7 +115,7 @@ func (p *Plugin) GetConfigSpec(ctx context.Context) (ports.ConfigSpec, error) { { Key: "model", Type: ports.ConfigFieldString, - Description: "Model override passed to `grok --model`.", + Description: "Model override passed to `grok -m`.", }, }, }, nil @@ -246,11 +246,13 @@ func grokClaudeSettingsPath(workspacePath string) string { return filepath.Join(workspacePath, grokClaudeSettingsDirName, grokClaudeSettingsFileName) } -// appendModelFlag appends a trimmed --model flag when a model override is -// configured. +// appendModelFlag appends a trimmed -m flag when a model override is +// configured. -m is the documented model-selection flag for both headless +// and TUI launches (https://docs.x.ai/build/overview: "grok -p \"Hello\" -m +// my-model" / "pick the model in headless mode or in the TUI"). func appendModelFlag(cmd *[]string, cfg ports.AgentConfig) { if model := strings.TrimSpace(cfg.Model); model != "" { - *cmd = append(*cmd, "--model", model) + *cmd = append(*cmd, "-m", model) } } diff --git a/backend/internal/adapters/agent/grok/grok_test.go b/backend/internal/adapters/agent/grok/grok_test.go index 130657a501..4c052a2df2 100644 --- a/backend/internal/adapters/agent/grok/grok_test.go +++ b/backend/internal/adapters/agent/grok/grok_test.go @@ -42,7 +42,7 @@ func TestGetConfigSpecReportsModelField(t *testing.T) { { Key: "model", Type: ports.ConfigFieldString, - Description: "Model override passed to `grok --model`.", + Description: "Model override passed to `grok -m`.", }, } if !reflect.DeepEqual(spec.Fields, want) { @@ -58,7 +58,7 @@ func TestGetLaunchCommandAppendsConfiguredModel(t *testing.T) { if err != nil { t.Fatalf("err: %v", err) } - want := []string{"grok", "--no-auto-update", "--model", "grok-build"} + want := []string{"grok", "--no-auto-update", "-m", "grok-build"} if !reflect.DeepEqual(cmd, want) { t.Fatalf("cmd = %#v, want %#v", cmd, want) } @@ -72,8 +72,10 @@ func TestGetLaunchCommandOmitsBlankConfiguredModel(t *testing.T) { if err != nil { t.Fatalf("err: %v", err) } - if strings.Contains(strings.Join(cmd, " "), "--model") { - t.Fatalf("cmd = %#v contains --model for blank model", cmd) + for _, arg := range cmd { + if arg == "-m" { + t.Fatalf("cmd = %#v contains -m for blank model", cmd) + } } } @@ -93,7 +95,7 @@ func TestGetRestoreCommandAppendsConfiguredModel(t *testing.T) { if !ok { t.Fatal("ok=false, want true") } - want := []string{"grok", "--no-auto-update", "--model", "grok-build", "-r", "sess-abc123"} + want := []string{"grok", "--no-auto-update", "-m", "grok-build", "-r", "sess-abc123"} if !reflect.DeepEqual(cmd, want) { t.Fatalf("cmd = %#v, want %#v", cmd, want) }