feat(advisor): client-side mode for 3P providers (any provider, any model) - #182
Merged
Conversation
Extends `/advisor` to work on any provider by adding a client-side
execution path. Server-side (Anthropic beta) stays the default when
applicable; client-side activates for 3P providers, non-server-side
advisor models, or when forced via `--client`.
## What changes
- New activation predicate `decide_advisor_mode` returns one of
`server_side`/`client_side`/`inactive` per turn.
- Client-side path registers `advisor` as a hidden tool in the
registry. When active, `_call_model_sync` appends its schema +
injects `ADVISOR_TOOL_INSTRUCTIONS` to the system prompt (both
Anthropic and 3P branches). Dispatcher routes the call to
`AdvisorTool.call`, which forwards stripped conversation history
to whatever provider routes the configured advisor model.
- `/advisor` command:
- Accepts any resolvable model (drops strict
`is_valid_advisor_model` rejection — now routes via
`infer_provider_for_model`).
- Parses `--client` / `--no-client` flags.
- Status output shows the actual mode picked.
- New settings field `advisor_client_mode: bool = False` (force
client-side even on 1P).
- `AppState.advisor_client_mode` with persistence + cache
invalidation handler.
- TUI: `_emit_advisor_events` extended to detect client-side
`tool_use(name=advisor)` + matching user-side `tool_result`.
- `can_user_configure_advisor` loosened to env-only (was 1P-only) —
/advisor is now valid on any provider.
## Test plan
- [x] tests/test_advisor_helpers.py — 32 passed (1 updated)
- [x] tests/test_advisor_orphan_pairing.py — 6 passed
- [x] tests/test_advisor_chat_response_roundtrip.py — 6 passed
- [x] tests/test_advisor_command.py — 14 passed (4 updated)
- [x] tests/test_advisor_request_wiring.py — 13 passed (3 updated)
- [x] tests/test_advisor_client_side.py — **30 new tests**
- [x] tests/test_app_state.py — 16 passed
- [x] tests/integration/test_advisor_smoke.py — 3 passed
- [x] tests/test_tool_system_tools.py + test_tool_registry_pipeline.py — 99 passed (regression)
- [x] tests/test_settings*.py + tests/test_query*.py — 70 passed (regression)
- **Total: 120 advisor tests + 169 collateral tests passed**
## Design choices
Documented in `my-docs/advisor-mode.md` (local). Key calls:
1. Server-side stays the optimized path (1 roundtrip, cache-friendly)
when applicable. Client-side is the fallback for everything else.
2. Cache stability: schema + instructions appended at the end of
both tool list and system prompt — toggling `/advisor` doesn't
churn the cached prefix.
3. AdvisorTool is hidden (`is_enabled=False`), not absent.
`_call_model_sync` injects the schema only when client-side mode
is active for the request.
4. Reviewer doesn't see its own prior consultations
(`build_advisor_forwarded_messages` strips advisor blocks).
5. Failure mode is degradation: `execute_client_advisor` catches
every exception and surfaces as a tool_result error rather than
killing the turn.
6. Reuses existing provider config — no new API keys/env vars.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 20, 2026
singlaamitesh
pushed a commit
to singlaamitesh/clawcodex
that referenced
this pull request
Jul 7, 2026
…ient-mode feat(advisor): client-side mode for 3P providers (any provider, any model)
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
/advisorto work on any provider (GLM, Gemini, OpenAI, OpenRouter, Bedrock-shimmed Anthropic, etc.) by adding a client-side execution path. The server-side Anthropic beta stays the optimized default when applicable; client-side activates for 3P providers, non-server-side advisor models, or when forced via--client./advisor <model> --client(force client-side),/advisor --no-client(clear),/advisor unset(clear all).Mode-decision table
--clientWhat changes
Activation
decide_advisor_mode(provider, main_model, advisor_model, force_client_mode)returnsserver_side/client_side/inactive.infer_provider_for_model(model)does exact-match inPROVIDER_INFO, then well-known prefix fallback (claude-*→ anthropic,gemini-*→ gemini,zai/*→ glm,<vendor>/*→ openrouter, etc.). Rejects ambiguous strings rather than guessing.Client-side path
AdvisorToolregistered insrc/tool_system/tools/advisor.pywithis_enabled=lambda: False(hidden from/toolslistings; registry still finds it for dispatch)._call_model_syncinjects the regular-tool-shape schema only when client-side mode is active for the request. Cache-friendly: appended after the regular tools and after the cached system blocks.AdvisorTool.call(input, ctx)readsctx.messages, strips prior advisor blocks viabuild_advisor_forwarded_messages, callsexecute_client_advisor.execute_client_advisorresolves the advisor's provider via the existingget_provider_class+get_provider_config(reuses user-configured API keys), makes one non-streamingchat()call with the advisor's own system prompt and empty tools, returns(ok, text_or_error). Never raises — degrades to a tool_result error on failure./advisorcommandis_valid_advisor_modelrejection (the opus-4-6/sonnet-4-6 server-side gate). Now only requires the model to route viainfer_provider_for_model.--client/--no-clientflags (order-insensitive).Advisor: <model> — active (server-side|client-side|inactive) [--client forced?].Settings + state
SettingsSchema.advisor_client_mode: bool = FalseAppState.advisor_client_modewith_on_advisor_client_mode_change(persists to global settings + invalidates cache, matches the existing advisor_model handler pattern).TUI
AgentBridge._emit_advisor_eventsextended: also detects client-sidetool_use(name=\"advisor\")on assistant messages plus the matchingtool_resulton subsequent user messages. Emits the sameAdvisorEventMessagetypes so the existing widget renders both flavors.Loosened gates
can_user_configure_advisor: was 1P-only, now env-only./advisorworks on any provider.Test plan
Verified locally (
/Users/ericlee2/workspace/clawcodex/.venv/bin/pytest):Design choices
/advisordoesn't churn the cached prefix.build_advisor_forwarded_messagesstrips advisor blocks before forwarding. Each consultation is independent.execute_client_advisorcatches every exception and surfaces asis_error=Truetool_result. The turn doesn't die.🤖 Generated with Claude Code