fix(ui): model/eval picker shows no list when CLI model discovery fails#78
Conversation
Co-authored-by: digitarald <8599+digitarald@users.noreply.github.com> Agent-Logs-Url: https://github.com/microsoft/agentrc/sessions/8ccb0fcd-8f79-407e-bac7-b09e5b806fdb
There was a problem hiding this comment.
Pull request overview
Fixes the TUI model/eval picker getting stuck with an empty (non-rendering) model list when Copilot CLI model discovery returns an empty list or fails, by adding safer fallbacks and improving Copilot CLI --help parsing.
Changes:
- Ensure the TUI always has a non-empty
availableModelslist by falling back toPREFERRED_MODELSon empty discovery results and on errors. - Make
listCopilotModels()resilient to CLIs that write help text tostderrand/or exit non-zero for--help. - Export
extractModelChoices()and add unit tests for multiple help-output formats and edge cases.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/ui/tui.tsx | Adds fallback to PREFERRED_MODELS so the model picker always renders a list. |
| packages/core/src/services/copilot.ts | Captures/parses both stdout and stderr for --help, exports the parser helper. |
| src/services/tests/copilot.test.ts | Adds unit coverage for extractModelChoices() across common formats/edge cases. |
| try { | ||
| const result = await execFileAsync(cmd, args, { timeout: 5000 }); | ||
| stdout = result.stdout; | ||
| stderr = result.stderr; | ||
| } catch (err) { | ||
| // Some CLIs exit with a non-zero code for --help; try to extract from stderr | ||
| const e = err as { stderr?: string; stdout?: string }; | ||
| stdout = e.stdout ?? ""; | ||
| stderr = e.stderr ?? ""; | ||
| } | ||
| const fromStdout = extractModelChoices(stdout); | ||
| return fromStdout.length > 0 ? fromStdout : extractModelChoices(stderr); |
There was a problem hiding this comment.
In listCopilotModels(), the catch currently swallows all execFileAsync failures and then returns [] if parsing yields no choices. That changes behavior for real execution failures (timeout, EACCES, broken binary, etc.): callers like eval --list-models will now report “No models detected” instead of surfacing the underlying error.
Consider only falling back to parsing stdout/stderr for expected non-zero --help exits, and if no models can be extracted, rethrow the original error (or throw a new error that includes the original failure) so genuine failures aren’t silently converted into an empty list.
| try { | |
| const result = await execFileAsync(cmd, args, { timeout: 5000 }); | |
| stdout = result.stdout; | |
| stderr = result.stderr; | |
| } catch (err) { | |
| // Some CLIs exit with a non-zero code for --help; try to extract from stderr | |
| const e = err as { stderr?: string; stdout?: string }; | |
| stdout = e.stdout ?? ""; | |
| stderr = e.stderr ?? ""; | |
| } | |
| const fromStdout = extractModelChoices(stdout); | |
| return fromStdout.length > 0 ? fromStdout : extractModelChoices(stderr); | |
| let execError: unknown = null; | |
| try { | |
| const result = await execFileAsync(cmd, args, { timeout: 5000 }); | |
| stdout = result.stdout; | |
| stderr = result.stderr; | |
| } catch (err) { | |
| // Some CLIs exit with a non-zero code for --help; try to extract from stderr | |
| execError = err; | |
| const e = err as { stderr?: string; stdout?: string }; | |
| stdout = e.stdout ?? ""; | |
| stderr = e.stderr ?? ""; | |
| } | |
| const fromStdout = extractModelChoices(stdout); | |
| if (fromStdout.length > 0) return fromStdout; | |
| const fromStderr = extractModelChoices(stderr); | |
| if (fromStderr.length > 0) return fromStderr; | |
| if (execError) { | |
| const e = execError as Error & { stderr?: string; stdout?: string }; | |
| const details = e.stderr || e.stdout; | |
| const detailMsg = details ? `\nCopilot CLI output:\n${details}` : ""; | |
| throw new Error(`Failed to list Copilot models: ${e.message}${detailMsg}`); | |
| } | |
| return []; |
Address review feedback: only fall back to parsing stdout/stderr for expected non-zero --help exits. If no models can be extracted and an exec error occurred, rethrow with details instead of silently returning an empty list.
- Add model/eval picker blank screen fix to CHANGELOG [Unreleased] (from #78) - Update agentrc init description in docs/commands.md to clarify agentrc.config.json is always created (not just for monorepos) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add missing changelog entries and documentation for: - Config status in TUI with [C] keybinding (PR #74) - Workspace Status tree view in VS Code extension (PR #74) - TUI model/eval picker blank screen fix (PR #78) - TUI terminal resize artifacts fix (PR #76) - @github/copilot-sdk 0.1.32 -> 0.2.0 bump (PR #73) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
When
listCopilotModels()returns[]or throws (CLI not found, changed--helpformat, or help written tostderr),availableModelsstayed empty and the model picker rendered nothing — leaving users stuck inmodel-pickstate with a blank screen.Changes
tui.tsx— always populateavailableModelsFall back to
PREFERRED_MODELSin both the empty-result and error cases, so the list always renders when enteringmodel-pickstate (affects bothMeval-model andJjudge-model pickers).copilot.ts— handlestderrand non-zero exits inlistCopilotModelsSome CLI builds write
--helptostderrand/or exit non-zero. Now captures both streams, triesstdoutfirst, falls back tostderr(including from thrownExecFileException).extractModelChoicesexported + unit testedAdded 6 tests covering single-line, multi-line, missing
choices:, empty string, and stderr-sourced help text.Original prompt
Created from VS Code.
⌨️ Start Copilot coding agent tasks without leaving your editor — available in VS Code, Visual Studio, JetBrains IDEs and Eclipse.