feat(advisor): require explicit <provider>:<model> syntax (multi-provider rewrite) - #192
Merged
Merged
Conversation
…ider rewrite)
clawcodex is multi-provider (not Claude-specific). The previous /advisor
command silently inferred the provider from the model name's prefix —
`claude-*` always routed to anthropic, regardless of which provider
config the user actually wanted to use. That broke the realistic case
where `claude-opus-4-7` is configured in the openai provider entry
(pointing at litellm.singula.ai) while the anthropic entry has no
credits. The advisor call would hit api.anthropic.com and 400 with
'credit balance too low'.
## What landed
* New `Settings.advisor_provider` + `AppState.advisor_provider`
fields. Both required alongside `advisor_model` for the advisor
to be considered active.
* `/advisor` requires `<provider>:<model>` syntax. Examples:
/advisor anthropic:claude-opus-4-7 (direct Anthropic)
/advisor openai:claude-opus-4-7 (via litellm/proxy)
/advisor openrouter:anthropic/claude-opus-4.1
/advisor gemini:gemini-2.5-pro
Splits on the first colon so model names with slashes/colons
round-trip cleanly. Validates the provider key against
~/.clawcodex/config.json's `providers` map.
* `execute_client_advisor` takes `advisor_provider` and uses it
directly — no inference, no "reuse main provider if it has a
custom endpoint" heuristic. Empty provider → fail-fast with a
clear error.
* `decide_advisor_mode` requires `advisor_provider`. Server-side
needs `advisor_provider == "anthropic"` since that's the only
path with the API beta. Anything else → client-side or INACTIVE.
* Status bar: `advisor: openai:opus-4-7 (client)` — colon-separated
so the user can copy-paste back into /advisor verbatim.
* Dead code removed: `infer_provider_for_model` and
`_provider_is_using_custom_endpoint` are no longer called by the
advisor path. Also dropped from __all__ + the corresponding
TestInferProviderForModel test class.
## Critic-driven fixes applied (single round, all addressed)
* C1: partial-config status now surfaces `advisor_client_mode`
when ON, so the user sees stored state that would silently
activate once both fields are filled.
* C2: `--client alone` checks both `current_advisor` AND
`current_provider` before enabling; the half-config case is no
longer accepted as 'I'm forcing client mode' followed by silent
INACTIVE at runtime.
* C3: stale `/advisor <model>` syntax hint in one error message
replaced with the new `/advisor <provider>:<model>` form.
* S1: status bar uses colon (`anthropic:opus-4-7`) instead of
slash, matching the /advisor input syntax. The user can copy
the status segment directly into the command.
* S3: dropped `if configured` fragile guard in /advisor provider
validation — corrupt-config silent-skip turned into a loud error.
## Breaking change
Existing users with `settings.advisor_model = "claude-opus-4-7"`
(no `advisor_provider` set) will see the advisor as INACTIVE
until they run `/advisor anthropic:claude-opus-4-7` (or whatever
provider they actually want). The status bar shows
`advisor: ?/opus-4-7 (inactive)` and `/advisor` (no args) prints
a clear migration hint pointing at the new syntax.
## Verified
* 677 tests passed across the full advisor + adapter + TUI + helpers
+ smoke + headless suites.
* Live: with the user's actual scenario (deepseek-v4-pro worker via
openrouter, claude-opus-4-7 advisor via openai/litellm,
`advisor_model=claude-opus-4-7 advisor_provider=openai`), the
advisor call SUCCEEDED via litellm with real opus-4-7 advice:
"use heapq.nlargest(k, nums) for O(n log k) time. Handle edge
cases: k <= 0 returns [], k >= len(nums) returns sorted...".
The previous 400-credit-balance error is gone.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
singlaamitesh
pushed a commit
to singlaamitesh/clawcodex
that referenced
this pull request
Jul 7, 2026
…cit-provider feat(advisor): require explicit <provider>:<model> syntax (multi-provider rewrite)
singlaamitesh
pushed a commit
to singlaamitesh/clawcodex
that referenced
this pull request
Jul 7, 2026
…fficient /advisor) Two new entries at the top of the README News section: 1. Codebase stats: 890 files / 183,768 lines (up from 894 / 177,428 on 2026-05-16; net +6.3k lines / -4 files in five days). The file delta is the agent_loop.py consolidation; the line additions are the /advisor multi-provider rewrite + status-bar cost work. 2. /advisor mode as a token-efficient coding agent — narrates the PR agentforce314#181 → agentforce314#193 arc as one story: - Cheap worker (haiku-4-5) + expensive reviewer (opus-4-7) only at decision points ≈ 6× cheaper than opus-only on typical sessions - Explicit <provider>:<model> syntax (agentforce314#192) - Cross-provider routing verified (deepseek worker + opus advisor via litellm, agentforce314#182/agentforce314#184/agentforce314#192) - Reviewer-quality prompt (agentforce314#188) — Gaps/Risks/Do-next format - Live cost + token visibility in status bar (agentforce314#190/agentforce314#191/agentforce314#193) - /advisor slash command + dedicated TUI row (agentforce314#181) Docs-only — no code or test changes. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Breaking change. The
/advisorcommand no longer infers the provider from the model name. clawcodex is multi-provider —claude-opus-4-7can live behindanthropic(direct),openai(litellm proxy),openrouter,bedrock, etc. Name-based inference silently routed to the wrong endpoint.The user's test case surfaced this concretely: with
claude-opus-4-7configured in the openai provider entry (pointing at litellm.singula.ai) but the anthropic entry having no credits,/advisor claude-opus-4-7would hitapi.anthropic.comand 400 withcredit balance too low.New syntax
```
/advisor anthropic:claude-opus-4-7 # direct Anthropic
/advisor openai:claude-opus-4-7 # via litellm/proxy
/advisor openrouter:anthropic/claude-opus-4.1
/advisor gemini:gemini-2.5-pro
```
Splits on the first colon so model names with slashes/colons round-trip cleanly. Validates the provider key against
~/.clawcodex/config.json'sprovidersmap.What changed
src/settings/types.pyadvisor_provider: str = ""field.src/state/app_state.pyAppState.advisor_provider+_on_advisor_provider_changesubscription.src/command_system/builtins.py/advisorrequires<provider>:<model>syntax. New helpers_read_current_advisor_provider,_write_advisor_provider,_list_configured_providers.src/utils/advisor.pyexecute_client_advisortakesadvisor_provider(no inference).decide_advisor_moderequiresadvisor_provider.format_advisor_statusshowsopenai:opus-4-7(colon, matches /advisor input).src/query/query.pysettings.advisor_providerand forwards todecide_advisor_mode.src/tool_system/tools/advisor.pyadvisor_modeloradvisor_provideris empty./advisorinvocations rewritten, fixtures set both fields, new tests fortest_rejects_missing_colonandtest_rejects_unknown_provider.Dead code removed
infer_provider_for_model(the model→provider prefix inference)_provider_is_using_custom_endpoint(the "reuse main provider if it has a custom endpoint" heuristic)TestInferProviderForModeltest class__all__These were the inference layer that the rewrite explicitly drops.
Critic-driven fixes (one round, all addressed)
advisor_client_modewhen ON so users see stored state that would silently activate once both fields are filled.--client alonechecks BOTHcurrent_advisorANDcurrent_providerbefore enabling.<model>syntax hint in an error message replaced with<provider>:<model>.anthropic:opus-4-7) matching/advisorinput syntax. User can copy from bar to command verbatim.if configuredguard — corrupt-config silent-skip turned into a loud error.Breaking change migration
Existing users with
settings.advisor_model = "claude-opus-4-7"(noadvisor_providerset) will see:advisor: ?/opus-4-7 (inactive)/advisorno-args:Advisor: not set\n(Found advisor_model='claude-opus-4-7' but no advisor_provider — clear with /advisor unset then re-run with the explicit syntax.)\nUse "/advisor <provider>:<model>" to enable, e.g.:\n /advisor anthropic:claude-opus-4-7 (direct Anthropic)\n /advisor openai:claude-opus-4-7 (via openai-compat, e.g. litellm)\n /advisor openrouter:anthropic/claude-opus-4.1No silent failures; clear migration path.
Tests
Live verified
The user's exact scenario:
```
~/.clawcodex/config.json:
settings:
advisor_model: claude-opus-4-7
advisor_provider: openai # was missing — now required
providers.openai.base_url: https://litellm.singula.ai
clawcodex --provider openrouter --model deepseek/deepseek-v4-pro -p "..."
```
Result: deepseek worker called advisor, the advisor request went via openai/litellm (NOT direct Anthropic), opus-4-7 returned real advice — "use heapq.nlargest(k, nums) for O(n log k) time. Handle edge cases: k <= 0 returns [], k >= len(nums) returns sorted...". The previous 400-credit-balance error is gone. Files created, exit 0, num_turns=6.
🤖 Generated with Claude Code