Commit Graph

13 Commits

Author SHA1 Message Date
teknium1
d364473620 refactor(model-providers): fetch_models stubs drop to the ABC; commandcode and AI Gateway catalog GETs go through open_credentialed_url
vertex, bedrock and copilot-acp each overrode ProviderProfile.fetch_models with an identical `return None`, and the overrides could not simply be deleted because the base implementation derives a URL from base_url and would GET e.g. bedrock-runtime.../models or acp://copilot/models. ProviderProfile now carries `supports_model_listing` (default True); the base fetch_models returns None before touching the network when it is False, and the three SDK/subprocess-backed profiles set it in their constructors instead of overriding. Separately, two catalog GETs still went through bare urllib.request.urlopen: commandcode's fetch_models and hermes_cli.models._fetch_ai_gateway_models (which sends the AI Gateway bearer). Both now use the redirect-safe open_credentialed_url path (_urlopen_model_catalog_request in models.py, also applied to the unauthenticated fetch_ai_gateway_models for consistency). This is a security behavior change: a cross-origin redirect from either endpoint no longer forwards the Authorization/attribution headers to the redirect target. The AI Gateway tests that patched the global urlopen are repointed at hermes_cli.models._urlopen_model_catalog_request (the seam tests/hermes_cli/test_models.py already uses), the commandcode test patches open_credentialed_url on the plugin module, and two invariant tests pin the no-network guard and the bearer routing.
2026-09-13 05:19:48 -07:00
teknium1
baf1200e0a refactor(commandcode): drop the deepseek ImportError guard, trim tests to two invariants
The deepseek plugin is bundled and always loads, so the try/except around
the delegation import was defense-in-depth for a path that cannot fail.
Tests reduced to the two contracts that matter: /reasoning none reaches
the wire as thinking.disabled, and DeepSeek ids produce exactly the native
DeepSeek profile's output while non-DeepSeek families stay a no-op.
2026-09-12 20:41:32 -07:00
liuhao1024
fbb3a244b7 fix(commandcode): degrade to no-op when the deepseek plugin shim is missing
The bundled-plugin loader pops half-registered modules when a plugin
fails to load, so the lazy 'from plugins.model_providers.deepseek import
deepseek' could raise ImportError on every DeepSeek-routed CommandCode
turn — turning the soft 'thinking uncontrollable' bug into a hard
crash. Catch ImportError, log, and return the pre-fix no-op (review
feedback on #95241).
2026-09-12 20:41:32 -07:00
liuhao1024
6f88fb030a fix(commandcode): forward DeepSeek reasoning controls through the wire
CommandCode fronts DeepSeek with vendor-prefixed ids
(deepseek/deepseek-v4-flash). DeepSeek V4+ defaults to thinking mode
when the thinking field is omitted, so /reasoning none changed the
Hermes session state but not the actual request -- the turn sat in
reflecting.../brainstorming... for minutes (#95232). Strip the vendor
prefix for DeepSeek-family ids and delegate to the native DeepSeek
profile's build_api_kwargs_extras (extra_body.thinking +
reasoning_effort mapping); other CommandCode model families keep the
base no-op behavior. The prior no-op tests codified the bug and are
rewritten to pin the new contract.
2026-09-12 20:41:32 -07:00
Teknium
48da317211 refactor(model-providers): tighten router/openrouter bodies, drop __future__ annotations (py>=3.11) 2026-09-02 21:58:26 -07:00
Teknium
40722b322c refactor(model-providers): pack keyword-only profile constructors (comments and multi-line values keep their lines) 2026-09-02 21:45:13 -07:00
Teknium
9338e21093 refactor(model-providers): compact reasoning-translation profiles (opencode, kimi, zai, minimax, nous, qwen, custom, upstage, nebius, meta-ai, deepseek, copilot, deepinfra, vertex, gemini), fold catalog tuples 2026-09-02 21:36:03 -07:00
Teknium
8c83b89dd4 refactor(model-providers): actual reuses base fetch_models + hermes_cli normalizer; commandcode anthropic subclasses chat profile; compact router/openrouter docstrings 2026-09-02 21:04:38 -07:00
Teknium
313b244e8f refactor(plugins/model-providers): reuse agent.reasoning_effort clamps, per-model dict tables, compact profiles 2026-09-02 13:30:28 -07:00
Teknium
c7d0f6c35f fix(providers): honor a custom base_url over models_url in fetch_models
Follow-up to the salvaged CommandCode signature fix: accepting base_url
but ignoring it left custom endpoints (user-configured model.base_url /
COMMANDCODE_BASE_URL proxies) fetching the public catalog instead of the
configured one. Reviewer dansigma flagged this on PR #88851.

Class-wide fix, not a CommandCode patch:

- providers/base.py: a caller base_url that DIFFERS from the profile's
  default now wins over models_url. Equality with the default means "not
  customised" (callers pass base_url unconditionally, defaulting to the
  profile's own URL) and keeps models_url as the endpoint, preserving the
  OpenRouter-style split-catalog behavior.
- commandcode: _fetch_commandcode_models() takes the endpoint override;
  both profile overrides forward base_url.
- Tests: base-class precedence (custom beats models_url, default does
  not), CommandCode redirect via live local HTTP server incl. claude-*
  filter, and default-echo hitting the canonical endpoint. All verified
  to fail against the pre-fix implementation (sabotage run).
2026-08-18 14:27:36 -07:00
greyvito
f5ea3fa9cb fix(commandcode): accept base_url kwarg in fetch_models overrides
The model picker's generic live-fetch path (hermes_cli/models.py
provider_model_ids) calls profile.fetch_models(api_key=..., base_url=...).
Both CommandCode overrides only accepted api_key/timeout, so every picker
open raised TypeError, which was silently swallowed, leaving the provider
with zero models.

Match the base ProviderProfile.fetch_models signature (base_url kwarg) and
add a regression test asserting both profiles accept it.
2026-08-18 14:27:36 -07:00
Teknium
9adc607190 fix(providers): give each CommandCode profile its own base-URL var for desktop parity
The provider-parity contract requires every CANONICAL provider to render a
card on the desktop Keys tab. /api/env rows are keyed by env var, and both
CommandCode profiles shared the single COMMANDCODE_API_KEY — so the
commandcode-anthropic profile had no row of its own and
test_provider_parity failed on CI (slice 6/12).

Fix: both profiles keep the shared API key, but each declares its own
base-URL override var (COMMANDCODE_BASE_URL / COMMANDCODE_ANTHROPIC_BASE_URL),
matching the sibling-provider pattern, so each renders its own card.

Verified: test_provider_parity.py + commandcode + providers suites green
locally (86 passed); PROVIDER_REGISTRY splits key vs base-URL vars correctly
for both profiles.
2026-08-17 02:56:17 -07:00
Johann
26d8bf567c feat: add CommandCode provider plugin
Add first-class CommandCode provider with dual API mode support:

profile commandcode (chat_completions):
  20+ models via OpenAI-compatible endpoint
  DeepSeek, Qwen, Kimi, GLM, MiniMax, StepFun, Mimo, Gemini, GPT
  Default: deepseek/deepseek-v4-pro (1M context)

profile commandcode-anthropic (anthropic_messages):
  Claude models via Anthropic Messages-compatible endpoint
  Default: claude-sonnet-4-6 (1M context)

Changes:
- plugins/model-providers/commandcode/ — provider plugin
  - __init__.py: dual ProviderProfile classes with fetch_models
  - plugin.yaml: manifest
- agent/anthropic_adapter.py: recognize api.commandcode.ai as Bearer auth
- tests/plugins/model_providers/test_commandcode_profile.py: 28 tests
- tests/providers/test_plugin_discovery.py: bump profile count 34→36

171 provider tests pass (28 new, 0 regressions)
2026-08-17 02:56:17 -07:00