From 2580524421cb6b590778b7aaec4f854dc8cbf308 Mon Sep 17 00:00:00 2001 From: gsxdsm Date: Thu, 9 Jul 2026 00:05:19 -0700 Subject: [PATCH] FN-7712: fix Grok CLI model list parsing for real grok models output Fixes the Grok CLI model picker showing raw prompt/preamble text instead of real model names by rewriting parseModelLines to match the actual verified `grok models` output shape. - Rewrote parseModelLines in process-manager.ts to strip the login/"Default model:"/"Available models:" preamble - Strip `*`/`-` bullet markers and the `(default)` annotation from each model line - Preserve existing legacy `id - Label`, columnar, and JSON parsing paths - Added regression tests covering the real grok models output shape - Added changeset (patch) documenting the fix Files changed: .changeset/fn-7712-grok-model-parse.md | 7 ++++ .../src/__tests__/process-manager.test.ts | 39 ++++++++++++++++++++++ .../src/process-manager.ts | 34 ++++++++++++------- 3 files changed, 68 insertions(+), 12 deletions(-) Fusion-Task-Id: FN-7712 Fusion-Task-Lineage: 93e34513-07b9-41b3-8b8b-ecdb763b4208 Co-authored-by: Fusion (runfusion.ai) --- .changeset/fn-7712-grok-model-parse.md | 7 ++++ .../src/__tests__/process-manager.test.ts | 39 +++++++++++++++++++ .../src/process-manager.ts | 34 ++++++++++------ 3 files changed, 68 insertions(+), 12 deletions(-) create mode 100644 .changeset/fn-7712-grok-model-parse.md diff --git a/.changeset/fn-7712-grok-model-parse.md b/.changeset/fn-7712-grok-model-parse.md new file mode 100644 index 0000000000..9d012a240c --- /dev/null +++ b/.changeset/fn-7712-grok-model-parse.md @@ -0,0 +1,7 @@ +--- +"@runfusion/fusion": patch +--- + +summary: Fix Grok CLI model picker showing prompt text instead of real model names. +category: fix +dev: Rewrote parseModelLines in fusion-plugin-grok-runtime/process-manager.ts to strip the login/"Default model:"/"Available models:" preamble and `*`/`-` bullet markers plus the `(default)` annotation from verified `grok models` output; legacy `id - Label`, columnar, and JSON paths preserved. diff --git a/plugins/fusion-plugin-grok-runtime/src/__tests__/process-manager.test.ts b/plugins/fusion-plugin-grok-runtime/src/__tests__/process-manager.test.ts index 4ac8c7298e..82f4868d8e 100644 --- a/plugins/fusion-plugin-grok-runtime/src/__tests__/process-manager.test.ts +++ b/plugins/fusion-plugin-grok-runtime/src/__tests__/process-manager.test.ts @@ -16,6 +16,20 @@ const DASH_MODELS_OUTPUT = [ const COLUMN_MODELS_OUTPUT = ["grok-4 $5.00/M in", "grok-4-fast $0.20/M in"].join("\n"); +// FN-7712: verified real `grok models` output shape (attachment 1871.png) — +// login/session preamble, "Default model:" line, "Available models:" header, +// then a bulleted list with `* (default)` for the active model and +// `- ` for the rest. +const REAL_BULLETED_OUTPUT = [ + "You are logged in with grok-cli v1.2.3", + "Default model: grok-4.5", + "Available models:", + "* grok-4.5 (default)", + "- grok-composer-2.5-fast", + "- grok-4-fast-reasoning", + "- grok-3-mini", +].join("\n"); + describe("discoverGrokModels", () => { beforeEach(() => { vi.clearAllMocks(); @@ -39,6 +53,31 @@ describe("discoverGrokModels", () => { expect(result.fallbackUsed).toBe(false); }); + it("extracts clean model ids from the verified real bulleted output, dropping preamble and markers", async () => { + vi.mocked(runGrokCommand).mockResolvedValueOnce({ code: 0, stdout: REAL_BULLETED_OUTPUT, stderr: "" }); + const result = await discoverGrokModels("grok"); + + expect(result.models).toEqual(["grok-4.5", "grok-composer-2.5-fast", "grok-4-fast-reasoning", "grok-3-mini"]); + expect(result.source).toBe("models-text"); + expect(result.fallbackUsed).toBe(false); + for (const model of result.models) { + expect(model).not.toMatch(/^[*-]/); + expect(model).not.toMatch(/\(default\)/i); + } + expect(result.models.some((m) => /logged in|default model|available models/i.test(m))).toBe(false); + }); + + it("strips the ` (default)` suffix marker from a bulleted default-model line", async () => { + vi.mocked(runGrokCommand).mockResolvedValueOnce({ + code: 0, + stdout: ["Available models:", "* grok-4.5 (default)"].join("\n"), + stderr: "", + }); + const result = await discoverGrokModels("grok"); + + expect(result.models).toEqual(["grok-4.5"]); + }); + it("extracts bare ids from columnar/pricing-separated output", async () => { vi.mocked(runGrokCommand).mockResolvedValueOnce({ code: 0, stdout: COLUMN_MODELS_OUTPUT, stderr: "" }); const result = await discoverGrokModels("grok"); diff --git a/plugins/fusion-plugin-grok-runtime/src/process-manager.ts b/plugins/fusion-plugin-grok-runtime/src/process-manager.ts index fe6b681552..923d11e36d 100644 --- a/plugins/fusion-plugin-grok-runtime/src/process-manager.ts +++ b/plugins/fusion-plugin-grok-runtime/src/process-manager.ts @@ -1,28 +1,38 @@ import { runGrokCommand } from "./cli-spawn.js"; /* -FNXC:GrokCli 2026-07-08-00:00: -FN-7705: the exact `grok models` output line shape is -`upstream-pending-verification` — the upstream README documents the command -lists available Grok models "with pricing hints" but does not pin an exact -column/separator format. We parse CONSERVATIVELY: strip obvious header/tip/ -empty-state lines, then take the leading token before a ` - ` label -separator (mirroring the Cursor CLI's ` -