feat: dynamic model options from cli-registry.yaml#64
Conversation
…oint Remove hardcoded RegistryModelOptions from SpawnModal. Model options are now fetched from the server which sources them from @agent-relay/config (codegen from cli-registry.yaml). Adds support for OpenCode and Droid model selection. Generalizes per-CLI model state and UI into a single generic approach. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Use a ref to track when the modal freshly opens (isOpen transitions from false to true). Only reset all form fields on this transition, not when modelOptions finish loading while the modal is already open. This fixes a regression where async /api/models loading would cause the useEffect to re-fire and discard any user input the user had already entered. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add missing registerModelsRoutes call in proxy-server.ts to ensure the /api/models endpoint is available in proxy/standalone mode. Without this, the model selection dropdown was hidden when running in proxy mode because the fetch to /api/models returned 404. Addresses Devin review comment on PR #64. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Remove unused defaultModels from useModelOptions hook - Add runtime validation (isModelOption type guard) for API response - Expose error state and refetch callback from useModelOptions - Remove dead DEFAULT_MODEL_OPTIONS empty object and simplify fallback chains - Move MODEL_CLIS to module scope to avoid re-creation on every render - Fix codex default model to match cli-registry.yaml (gpt-5.4, not gpt-5.2-codex) - Use AbortController instead of manual cancelled flag Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Default models now come from @agent-relay/config via /api/models instead of being hardcoded. The fallback chain is: user setting > registry default > first model option in list. types.ts defaults are kept as last-resort offline fallback. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
| if (data.defaultModels && typeof data.defaultModels === 'object') { | ||
| setDefaultModels(data.defaultModels as DefaultModelsMap); | ||
| } |
There was a problem hiding this comment.
🟡 defaultModels keys not normalized to lowercase, causing lookup failures
In useModelOptions.ts, the modelOptions keys are explicitly normalized to lowercase (line 45: normalized[key.toLowerCase()]), because the codegen source (@agent-relay/config) uses PascalCase keys (e.g., Claude, Codex). However, defaultModels from the same codegen source is stored without any normalization (lines 51-53). All downstream consumers look up registryDefaultModels by lowercase CLI id (e.g., registryDefaultModels?.['claude'] at packages/dashboard/src/components/SpawnModal.tsx:177 and packages/dashboard/src/components/settings/SettingsPage.tsx:413), so the lookup returns undefined if the keys are PascalCase. This means the registry default model fallback silently fails, and the system falls through to either getModelsForCli(cli)[0]?.value or ''.
| if (data.defaultModels && typeof data.defaultModels === 'object') { | |
| setDefaultModels(data.defaultModels as DefaultModelsMap); | |
| } | |
| if (data.defaultModels && typeof data.defaultModels === 'object') { | |
| const normalizedDefaults: DefaultModelsMap = {}; | |
| for (const [key, value] of Object.entries(data.defaultModels)) { | |
| if (typeof value === 'string') { | |
| normalizedDefaults[key.toLowerCase()] = value; | |
| } | |
| } | |
| setDefaultModels(normalizedDefaults); | |
| } |
Was this helpful? React with 👍 or 👎 to provide feedback.
The modelOptions keys are normalized to lowercase (PascalCase from codegen → lowercase), but defaultModels keys weren't. Downstream lookups like registryDefaultModels['claude'] returned undefined when the key was 'Claude', causing the fallback to silently fail. Addresses: #64 (comment)
|
The last Devin comment (defaultModels keys not normalized) is addressed in #65. |
Summary
RegistryModelOptionsfrom SpawnModal — model options now fetched from/api/modelsserver endpoint@agent-relay/config(codegen fromcli-registry.yaml)opus-4.6-thinking, Gemini →gemini-3.1-pro-previewTest plan
/api/modelsendpoint returns correct data--modelflag correctly🤖 Generated with Claude Code