feat(agents): wizard E2E — /agents/models endpoint + live model combobox #553

Merged
charles merged 1 commit from feat/m26-wizard-e2e into main 2026-04-29 14:48:57 +00:00
Collaborator

Summary

Closes the M26-2 follow-up gap: the wizard's per-tier model input was free-text only because the HTTP route for the model catalogue had never been registered. Handler in sdk-adapter.ts::SdkClaudeAgent.listModels has existed since PR #547 — this PR just exposes it over HTTP and consumes it from the wizard.

Changes

Server:

  • app.get("/agents/models", ...) registered. Validates ?provider= against the closed enum (anthropic | deepseek | ollama); 400s on unknown values.
  • Reuses the adapter's existing 24 h per-provider cache + hardcoded fallback so the endpoint is cheap on every render.

Web:

  • fetchAgentModels(provider) helper in lib/api.ts. React-query cache (5 min staleTime) shares one fetch across every wizard tier on the same page.
  • New <ModelCombobox /> in config.tsx<datalist>-backed input. Autocomplete when the catalogue is reachable; free-text fallback for custom Ollama tags or models the upstream snapshot doesn't carry.
  • Replaces the per-row free-text input in the provider chain editor.

Test plan

  • just typecheck clean across all 4 packages.
  • Server tests: 2597 pass / 4 fail (all pre-existing on main: session JSONL pruning + foreman session CRUD). 3 new cases for the endpoint.
  • Web tests: ProviderSection 10/10 pass. New combobox-renders test confirms the list attribute wires the input to the sibling <datalist>.
  • Manual: open /config → pick a type with a 3-tier chain → confirm tier-1 model dropdown autocompletes Anthropic catalogue, tier-2 deepseek, tier-3 ollama (or fallback list when the env vars are absent).

🤖 Generated with Claude Code

## Summary Closes the M26-2 follow-up gap: the wizard's per-tier model input was free-text only because the HTTP route for the model catalogue had never been registered. Handler in `sdk-adapter.ts::SdkClaudeAgent.listModels` has existed since PR #547 — this PR just exposes it over HTTP and consumes it from the wizard. ## Changes **Server:** - `app.get("/agents/models", ...)` registered. Validates `?provider=` against the closed enum (`anthropic` | `deepseek` | `ollama`); 400s on unknown values. - Reuses the adapter's existing 24 h per-provider cache + hardcoded fallback so the endpoint is cheap on every render. **Web:** - `fetchAgentModels(provider)` helper in `lib/api.ts`. React-query cache (5 min `staleTime`) shares one fetch across every wizard tier on the same page. - New `<ModelCombobox />` in `config.tsx` — `<datalist>`-backed input. Autocomplete when the catalogue is reachable; free-text fallback for custom Ollama tags or models the upstream snapshot doesn't carry. - Replaces the per-row free-text input in the provider chain editor. ## Test plan - [x] `just typecheck` clean across all 4 packages. - [x] Server tests: 2597 pass / 4 fail (all pre-existing on `main`: session JSONL pruning + foreman session CRUD). 3 new cases for the endpoint. - [x] Web tests: ProviderSection 10/10 pass. New combobox-renders test confirms the `list` attribute wires the input to the sibling `<datalist>`. - [ ] Manual: open `/config` → pick a type with a 3-tier chain → confirm tier-1 model dropdown autocompletes Anthropic catalogue, tier-2 deepseek, tier-3 ollama (or fallback list when the env vars are absent). 🤖 Generated with [Claude Code](https://claude.com/claude-code)
feat(agents): wire /agents/models endpoint + live model combobox in wizard
All checks were successful
qa / qa (pull_request) Successful in 14m30s
qa / dockerfile (pull_request) Successful in 10s
d8b9995d90
Closes the M26-2 follow-up gap: the wizard's per-tier model input was
free-text only because the HTTP route for the model catalogue had never
been registered. Handler in `sdk-adapter.ts::SdkClaudeAgent.listModels`
existed since PR #547 — this commit just exposes it over HTTP and
consumes it from the web wizard.

Server:
- `app.get("/agents/models", ...)` registered. Validates `?provider=`
  against the closed enum (anthropic | deepseek | ollama); 400s on
  unknown values rather than silently falling back.
- Per-provider 24 h cache + hardcoded fallback (already in adapter)
  means the endpoint is cheap on every render.

Web:
- `fetchAgentModels(provider)` helper in `lib/api.ts`; per-provider
  react-query cache (5 min staleTime) lets every wizard tier on the
  same page share one fetch.
- New `<ModelCombobox />` in `config.tsx` — `<datalist>`-backed input
  so operators get autocomplete when the catalogue is reachable, and
  free-text fallback for custom Ollama tags / models that aren't in
  the upstream snapshot.
- Replaces the per-row free-text `<input type="text">` in the
  ProviderSection chain editor.

Tests:
- `main-agents.test.ts` — 3 cases: default provider returns fallback,
  ?provider=deepseek returns DeepSeek fallback, ?provider=openai 400s.
- `config.test.tsx` — combobox renders with the entry's model value
  and is `list`-wired to its sibling `<datalist>`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
charles deleted branch feat/m26-wizard-e2e 2026-04-29 14:48:57 +00:00
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
charles/claude-hooks!553
No description provided.