feat(cli): pull latest LLM models dynamically in the crew wizard#6462
feat(cli): pull latest LLM models dynamically in the crew wizard#6462joaomdmoura wants to merge 13 commits into
Conversation
The JSON-crew creation wizard hardcoded a short model list per provider,
which goes stale as vendors ship new models every few weeks. Add a
three-tier resolver that prefers live data and falls back to a curated list.
- New `model_catalog.get_provider_models(provider, fallback)`:
1. Vendor API (openai/anthropic/gemini/groq/cerebras/ollama) when the
provider key is already in the environment — the only reliably-fresh
source (real release dates / display names).
2. Curated hardcoded fallback — hand-verified, used when no key is set.
3. LiteLLM feed — only for providers with no curated list; it lags real
releases, so it must never preempt the curated fallback.
- Rank by date/version parsed from model ids, humanize labels, 6h cache,
short timeouts, silent fallback on any error.
- Wire it into `create_json_crew._select_model()` (picker only).
- Refresh the curated fallback against each vendor's official model docs
(Anthropic Fable 5 / Opus 4.8 / Sonnet 5; OpenAI GPT-5.5(+pro); Gemini
3.5 Flash / 3.1 Pro preview / 3 Flash preview; Groq Llama 4 / GPT-OSS).
- Tests for ranking, chat filtering, caching, and the tier order (17 tests).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RBYGqJHC2TMC6fonFziuuh
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds dynamic provider model discovery for crew creation, wires it into the wizard, and updates one vulnerability scan ignore entry. ChangesModel catalog and wizard integration
Vulnerability scan workflow
Suggested reviewers: Sequence Diagram(s)sequenceDiagram
participant Wizard as create_json_crew
participant Catalog as get_provider_models
participant Cache as Catalog cache
participant Vendor as Vendor fetchers
participant LiteLLM as LiteLLM feed
Wizard->>Catalog: get_provider_models(provider_key, fallback)
Catalog->>Cache: read cached catalog
alt cache miss or stale
Catalog->>Vendor: fetch provider models
Vendor-->>Catalog: vendor models or none
alt no vendor models and fallback is empty
Catalog->>LiteLLM: load chat models
LiteLLM-->>Catalog: candidate models
end
Catalog->>Cache: write resolved catalog
end
Catalog-->>Wizard: model_id/label pairs
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@lib/cli/src/crewai_cli/model_catalog.py`:
- Around line 197-230: The Gemini model fetcher currently only reads the first
page from models.list, so it can miss models because the API is paginated and
not ordered newest-first. Update _fetch_gemini in model_catalog.py to loop
through all pages using nextPageToken (passing it back as pageToken on
subsequent _http_get_json calls), accumulate entries from each page, and stop
only when no nextPageToken remains.
- Around line 128-134: The fallback lookup in get_provider_models can crash when
a LiteLLM model entry has a null litellm_provider, because the code lowercases a
value that may not be a string. Update the LiteLLM parsing path in _from_litellm
to guard litellm_provider before calling strip/lower, treating missing or null
values as absent and skipping those entries so the existing fallback behavior in
get_provider_models still works.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: 5bed391e-f9cf-4cc3-848a-7f02e81992c1
📒 Files selected for processing (3)
lib/cli/src/crewai_cli/create_json_crew.pylib/cli/src/crewai_cli/model_catalog.pylib/cli/tests/test_model_catalog.py
- Key the Ollama catalog cache by its base URL so a changed OLLAMA_API_BASE / API_BASE no longer serves the previous host's models for up to the TTL. - Negatively cache the curated fallback after a failed/empty fetch (short _NEGATIVE_TTL) so the picker doesn't repeat a timeout-prone vendor/LiteLLM request on every call — most impactful for a down local Ollama server. - Guard _read_catalog_cache / _write_catalog_cache against a non-dict cache root (corrupt JSON array no longer raises AttributeError). - Replace the two empty `except OSError: pass` blocks with contextlib.suppress(OSError) plus an explanatory comment (CodeQL empty-except). - Tests: negative cache, base-keyed Ollama cache, corrupt-cache no-crash (20 total). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RBYGqJHC2TMC6fonFziuuh
- _from_litellm: coerce a present-but-null `litellm_provider` before string ops so it's skipped instead of raising AttributeError (keeps the documented "never raises" contract). - _fetch_gemini: walk models.list pages via nextPageToken (bounded to 10) — the API is paginated and not guaranteed newest-first, so a single page could drop models the ranking should consider. - Tests for both (22 total). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RBYGqJHC2TMC6fonFziuuh
Review round addressedAll bot review findings (Cursor Bugbot, CodeQL, CodeRabbit) are fixed — commits
Test count is now 22 (a regression test per finding);
|
pip-audit newly flags nltk 3.9.4 for PYSEC-2026-597 (CVE-2026-12243), a path traversal via percent-encoded `..%2f` in nltk.data.load()/find(). It affects all nltk versions <=3.9.4 with no patched release, so it can't be resolved by a version bump — same situation as the already-ignored PYSEC-2026-97. nltk is a transitive dependency (unstructured[local-inference, all-docs] in crewai-tools) used for text tokenization; we never pass untrusted resource URLs/paths to nltk.data, so the traversal is not reachable. Add it to the curated --ignore-vuln list with a justification, matching the existing pattern. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RBYGqJHC2TMC6fonFziuuh
|
- Cache ignores new API keys: include API-key presence in the cache key (`<provider>#key|#nokey`), so a key added after a no-key/negative-cached lookup triggers a fresh live fetch instead of serving the stale fallback. - Bad LiteLLM cache crashes picker: `_from_litellm` now requires a dict from `_load_litellm_data` (a non-mapping JSON root is skipped, not `.items()`'d). - Stale LiteLLM refetch loop: memoize the feed load once per process (`_litellm_memo` + `_reset_litellm_memo` test hook) so repeated uncurated- provider lookups don't each re-attempt a timed download when offline. - Tests: new-key bypass, corrupt-litellm-cache no-crash, one-fetch-per-process (25 total). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RBYGqJHC2TMC6fonFziuuh
_fetch_gemini paginates; a network/HTTP error on page 2+ previously raised out through _from_vendor, discarding models already parsed from earlier pages and forcing the curated fallback. Catch per-page fetch errors and return the partial set instead (a first-page failure still yields an empty list -> fallback). Test: test_vendor_gemini_keeps_partial_on_later_page_error (26 total). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RBYGqJHC2TMC6fonFziuuh
_fetch_litellm_data treated any truthy JSON root in a fresh provider_cache.json as the feed and returned it, so a non-mapping root (e.g. a JSON array) was memoized and the tier never re-downloaded until the file aged out — leaving uncurated providers with an empty picker despite a recoverable cache. Only short-circuit on a usable dict; otherwise fall through to the download. Test renamed to test_invalid_litellm_cache_falls_through_to_download (asserts recovery via refetch). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RBYGqJHC2TMC6fonFziuuh
- Ollama host mismatch: _ollama_base now also reads OLLAMA_HOST (the Ollama runtime convention) after OLLAMA_API_BASE/API_BASE, normalizing a scheme-less value (e.g. "127.0.0.1:11434" -> "http://127.0.0.1:11434"), so users who set only OLLAMA_HOST see models from the server the crew will actually use. - Empty vendor list: a successful vendor fetch returning no models is now authoritative instead of collapsing to the curated fallback. A reachable Ollama with nothing installed yields an empty list (the picker prompts for manual entry) rather than offering hardcoded models that aren't installed; a failed fetch still falls back. _from_vendor now returns [] on success-empty and None only when the tier is unavailable. - Tests: ollama empty->manual, ollama down->fallback, OLLAMA_HOST resolution (29 total). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RBYGqJHC2TMC6fonFziuuh
Interaction from the prior two fixes: _fetch_gemini swallowed a first-page error and returned [], which _from_vendor reported as a successful-empty result and get_provider_models treated as authoritative — skipping the curated Gemini fallback and jumping to manual entry. Now a first-page failure (nothing gathered yet) re-raises so _from_vendor returns None and the curated list is used; a later-page failure still keeps the partial results. Test: test_vendor_gemini_first_page_error_uses_fallback (30 total). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RBYGqJHC2TMC6fonFziuuh
- Gemini ignores GOOGLE_API_KEY: _PROVIDER_KEY_ENV now maps each provider to a tuple of accepted env vars; Gemini accepts GEMINI_API_KEY or GOOGLE_API_KEY (matching crewai's own Gemini provider). A new _provider_api_key() resolver is used by both _from_vendor and the cache key, so a GOOGLE_API_KEY user gets the live models API instead of the stale curated fallback. - Ollama recovery blocked by cache: skip the negative (fallback) cache for Ollama. It's a local, fast-failing server, so re-probing each call is cheap and lets the picker pick up real installed models as soon as the server comes up, instead of serving suggestions for the negative-cache TTL. - Tests: GOOGLE_API_KEY live fetch, Ollama down->recover (32 total). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RBYGqJHC2TMC6fonFziuuh
Add the blank line ruff format expects after _provider_api_key; no behavior change. Fixes the lint-run `ruff format --check lib/` step. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RBYGqJHC2TMC6fonFziuuh
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 1 potential issue.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 065a5a4. Configure here.
The 'search' entry in _NON_CHAT_MARKERS matched anywhere in a model id, dropping legitimate completion models like gpt-4o-search-preview and anything containing 'research' (e.g. o3-deep-research, since 'search' is a substring). Remove it; the remaining markers (embedding/audio/image/moderation/etc.) still filter genuine non-chat models. Test: test_search_substring_not_treated_as_non_chat (33). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RBYGqJHC2TMC6fonFziuuh
Do not suppress an unpatched security advisory to make CI green. Remove PYSEC-2026-597 from the pip-audit ignore list; leave the scan failing so it keeps surfacing the nltk path traversal (CVE-2026-12243). This PR should not be merged until nltk ships a fix (or the vulnerable transitive dep is otherwise resolved). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RBYGqJHC2TMC6fonFziuuh
Correction:
|

What & why
The JSON-crew creation wizard (
crewai create) hardcodes a short model list per provider. Vendors ship new models every few weeks, so that list goes stale fast. This adds a resolver that prefers live model data and keeps the hardcoded list only as a verified fallback.How it works — three tiers
model_catalog.get_provider_models(provider, fallback):/v1/modelsendpoint (openai,anthropic,gemini,groq,cerebras,ollama). This is the only source that reliably reflects the latest models, with real release dates / display names.model_prices_and_context_window.jsonthe CLI already caches, used only for providers with no curated list. The feed lags real releases (it can miss a vendor's newest models entirely), so it must never preempt the curated fallback.Results are ranked by date/version parsed from the model id, labels are humanized (curated labels win), results cache for 6h, network calls use a short timeout, and any failure degrades silently to the next tier.
Wired into
create_json_crew._select_model()only (the arrow-key picker). The non-interactive--providerdefault path stays on the deterministic hardcoded list.Curated fallback refresh
Refreshed each provider's fallback against the vendor's official model docs:
Tests
tests/test_model_catalog.py— 17 tests: vendor ranking + label precedence, chat-model filtering, version/date parsing, caching, full-failure fallback, and the tier order (curated fallback beats the lagging feed; feed only fills uncurated providers).ruff+mypyclean.Note
The LiteLLM feed is not a reliable "latest models" source — it lags, sometimes behind a hand-maintained list. Reliable freshness comes from the vendor API (needs a key), and the curated fallback has to be kept current. A follow-up build-time refresh script (regenerating the fallback from vendor APIs in CI) would remove the need to hand-edit model IDs — happy to add it if wanted.
🤖 Generated with Claude Code
Note
Low Risk
Changes are confined to CLI scaffolding and optional outbound HTTP during wizard model selection; no runtime crew execution or auth paths are modified.
Overview
Adds
model_catalog.get_provider_modelsso the JSON crew wizard’s interactive model picker can show up-to-date LLMs instead of only a frozen hardcoded list.Resolution order: vendor
/modelsAPIs when the matching env API key is set (OpenAI, Anthropic, Gemini, Groq, Cerebras, Ollama); otherwise the refreshed curated_PROVIDER_MODELSlist; LiteLLM’s cached feed only for providers with no curated fallback (e.g. Bedrock). Results are ranked newest-first, capped at 8, cached under~/.crewai, and failures degrade without blocking the wizard.Wizard wiring:
_select_model()calls the resolver;--provider/_default_model_for_providerstill use the static curated default only.Curated lists for OpenAI, Anthropic, Gemini, Groq, and Ollama are updated to current model IDs.
tests/test_model_catalog.pycovers vendors, LiteLLM, caching, and tier precedence.Reviewed by Cursor Bugbot for commit a275e6a. Bugbot is set up for automated code reviews on this repo. Configure here.