ai-consultants 3.0.0 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,96 @@
1
+ # Release v3.2.0
2
+
3
+ **Date:** 2026-07-25
4
+ **Type:** Minor — Claude moves to Opus 5 with adaptive-thinking-safe transports and billing
5
+ **Previous:** v3.1.1
6
+
7
+ ## Highlights
8
+
9
+ - **Claude now uses `claude-opus-5` as its premium default** across direct configuration, model tiers, documentation, and cost tracking.
10
+ - **Claude CLI costs now come directly from the provider**, including adaptive thinking and cache charges that are absent from the visible answer.
11
+ - **Anthropic API thinking blocks are handled correctly**, and responses truncated by the shared thinking/output budget are rejected instead of synthesized as complete.
12
+ - **Existing generated Opus 4.8 defaults migrate to Opus 5**, while explicit model pins are recorded and preserved.
13
+ - **Opus 4.8 remains supported** for historical responses and intentional overrides.
14
+
15
+ ## What's New
16
+
17
+ ### Opus 5 premium default
18
+
19
+ The Claude consultant, premium/max/best quality tier, standalone adapter fallback, examples, and cost catalog now use the canonical `claude-opus-5` model ID. Standard and economy tiers remain on Claude Sonnet 4.6 and Haiku 4.5.
20
+
21
+ Opus 5 retains the previous $5 per million input tokens and $25 per million output tokens. The legacy Opus 4.8 rates remain available so historical sessions and pinned installations continue to be priced correctly.
22
+
23
+ ### Exact Claude CLI usage and cost
24
+
25
+ Claude CLI mode now requests its JSON result envelope. AI Consultants extracts:
26
+
27
+ - the visible answer from `.result`;
28
+ - measured input, cache, and output usage from `modelUsage`;
29
+ - the provider-reported `costUSD`.
30
+
31
+ The exact provider cost takes precedence over local token-rate reconstruction. This includes adaptive-thinking and cache charges even though those tokens do not appear in the visible answer.
32
+
33
+ ### Adaptive-thinking-safe API mode
34
+
35
+ Anthropic responses may place a thinking block before one or more visible text blocks. The parser now collects every visible `type=text` block instead of assuming the first content block contains the answer.
36
+
37
+ The new `CLAUDE_API_MAX_TOKENS` setting defaults to 16,384 tokens. Anthropic counts adaptive thinking and visible output against this shared budget. If the provider returns `stop_reason=max_tokens`, the consultation fails as truncated rather than entering synthesis as a complete response.
38
+
39
+ ### Managed configuration migration
40
+
41
+ Older `ai-consultants init` templates wrote the then-current Opus 4.8 default as an ordinary value. Running `ai-consultants configure` now recognizes that exact historical generated default, upgrades it to Opus 5, and records managed provenance.
42
+
43
+ Explicit model choices are written with an `# ai-consultants:pin` marker and survive subsequent configuration refreshes.
44
+
45
+ ## Breaking Changes
46
+
47
+ None — this release is backwards-compatible. Opus 4.8 remains selectable and priced.
48
+
49
+ If `CLAUDE_MODEL=claude-opus-4-8` was an intentional unmarked override rather than the generated default, reassert it once after upgrading:
50
+
51
+ ```bash
52
+ ai-consultants configure --set CLAUDE_MODEL=claude-opus-4-8
53
+ ```
54
+
55
+ ## Upgrade Guide
56
+
57
+ ```bash
58
+ # If installed via git clone
59
+ cd ~/.claude/skills/ai-consultants && git pull
60
+
61
+ # If installed via curl | bash
62
+ curl -fsSL https://raw.githubusercontent.com/matteoscurati/ai-consultants/main/scripts/install.sh | bash
63
+
64
+ # If used through npx
65
+ npx ai-consultants@latest "your question"
66
+ ```
67
+
68
+ Refresh persistent configuration so a historical generated Opus 4.8 value migrates:
69
+
70
+ ```bash
71
+ ai-consultants configure
72
+ ai-consultants doctor
73
+ ```
74
+
75
+ API users may override the shared thinking/output budget if needed:
76
+
77
+ ```bash
78
+ ai-consultants configure --set CLAUDE_API_MAX_TOKENS=32768
79
+ ```
80
+
81
+ ## Verification
82
+
83
+ - Full repository gate: 17/17 suites
84
+ - Core suite: 299/299 checks
85
+ - Claude CLI JSON/cost regression suite: 6/6 checks
86
+ - Anthropic transport regression suite: 48/48 checks
87
+ - Shellcheck and release-surface validation
88
+ - Live local Claude CLI JSON envelope verified with `claude-opus-5`
89
+
90
+ ## Commits
91
+
92
+ - `3963c3c` feat: upgrade Claude consultant to Opus 5
93
+
94
+ ## Contributors
95
+
96
+ - Matteo Scurati
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ai-consultants",
3
- "version": "3.0.0",
3
+ "version": "3.2.0",
4
4
  "description": "A harness for every question - a panel of up to 11 AI models that picks its own deliberation strategy per question (convergence, adversarial verification, tournament) and checks its work before answering",
5
5
  "bin": {
6
6
  "ai-consultants": "bin/ai-consultants"
@@ -54,6 +54,11 @@ ai-consultants configure --dry-run
54
54
  Use the hidden interactive credential prompts (or exported environment variables)
55
55
  for API keys; command-line arguments may be visible in shell history and process
56
56
  inspection.
57
+ Model defaults carry an `# ai-consultants:default` marker. On rewrite,
58
+ `configure` upgrades the historical unmarked
59
+ `CLAUDE_MODEL=claude-opus-4-8` generated default to Opus 5. An explicit model
60
+ override supplied with `--set` is stored with `# ai-consultants:pin`, so
61
+ `--set CLAUDE_MODEL=claude-opus-4-8` keeps the legacy model intentionally.
57
62
  The exhaustive parameter contract is [`.env.example`](../.env.example); the
58
63
  configurator derives its accepted keys from that template, while
59
64
  [`scripts/config.sh`](../scripts/config.sh) remains the runtime source of truth.
@@ -182,7 +187,7 @@ override it.
182
187
 
183
188
  ## CLI/API Mode Switching (v2.6+)
184
189
 
185
- Six consultants support switching between CLI and API mode. **The default is the CLI** for every consultant that has one — API mode is opt-in (for CLI-less models or an explicit choice). When API mode is enabled, the CLI is not used.
190
+ Seven consultants support switching between CLI and API mode. **The default is the CLI** for every consultant that has one. Grok additionally falls back to the xAI API after a failed CLI launch when a key is available. When API mode is explicitly enabled, the CLI is not used.
186
191
 
187
192
  **Gemini auto-resolution (v2.15.1):** leave `GEMINI_USE_API` unset and the mode is chosen for you — API mode when `GEMINI_API_KEY` is present (no `agy` install or OAuth needed; ideal for `npx`), CLI mode (`agy`) otherwise. Set `GEMINI_USE_API` explicitly only to force a mode (an explicit value disables auto-detection).
188
193
 
@@ -193,6 +198,7 @@ CODEX_USE_API=false # Use OpenAI API instead of codex CLI
193
198
  CLAUDE_USE_API=false # Use Anthropic API instead of claude CLI
194
199
  MISTRAL_USE_API=false # Use Mistral API instead of vibe CLI
195
200
  QWEN3_USE_API=false # Use qwen CLI (default) or DashScope API
201
+ GROK_USE_API=false # Use Grok Build (default); API is fallback
196
202
  MINIMAX_USE_API=false # Use mmx CLI (default) or MiniMax API
197
203
  ```
198
204
 
@@ -207,7 +213,7 @@ MINIMAX_USE_API=false # Use mmx CLI (default) or MiniMax API
207
213
  | Qwen3 | `QWEN3_API_KEY` | DashScope API key |
208
214
  | MiniMax | `MINIMAX_API_KEY` | MiniMax API key (API mode only; the mmx CLI uses OAuth) |
209
215
  | GLM | `GLM_API_KEY` | Required when `ENABLE_GLM=true` |
210
- | Grok | `GROK_API_KEY` | Required when `ENABLE_GROK=true` |
216
+ | Grok | `GROK_API_KEY` | xAI API fallback key; Grok Build CLI uses its own login |
211
217
  | DeepSeek | `DEEPSEEK_API_KEY` | Required when `ENABLE_DEEPSEEK=true` |
212
218
 
213
219
  ## Consultant Toggles and Models
@@ -220,12 +226,12 @@ ENABLE_MISTRAL=true
220
226
  ENABLE_CURSOR=true
221
227
  ENABLE_KIMI=true # Kimi CLI - The Eastern Sage
222
228
  ENABLE_QWEN3=true # Qwen CLI/API - The Analyst
229
+ ENABLE_GROK=true # Grok Build CLI/API fallback - The Provocateur
223
230
  ENABLE_MINIMAX=true # MiniMax CLI/API (mmx) - The Pragmatic Optimizer
224
231
  ENABLE_CLAUDE=true # Claude CLI - The Synthesizer (auto-excluded under Claude Code)
225
232
 
226
233
  # API-only consultants (off by default - require API keys)
227
234
  ENABLE_GLM=false
228
- ENABLE_GROK=false
229
235
  ENABLE_DEEPSEEK=false
230
236
  ```
231
237
 
@@ -234,7 +240,8 @@ ENABLE_DEEPSEEK=false
234
240
  ```bash
235
241
  GEMINI_MODEL=Gemini 3.1 Pro (High) # agy CLI display name; API mode uses GEMINI_API_MODEL
236
242
  CODEX_MODEL=gpt-5.5
237
- CLAUDE_MODEL=claude-opus-4-8
243
+ CLAUDE_MODEL=claude-opus-5
244
+ CLAUDE_API_MAX_TOKENS=16384 # API only: adaptive thinking + visible output
238
245
  MISTRAL_MODEL=mistral-large-3
239
246
  CURSOR_MODEL=composer-2.5
240
247
  KIMI_MODEL=kimi-code/k3
@@ -245,6 +252,19 @@ DEEPSEEK_MODEL=deepseek-v4-pro
245
252
  MINIMAX_MODEL=MiniMax-M2.7
246
253
  ```
247
254
 
255
+ Anthropic counts adaptive thinking and visible response tokens against the same
256
+ `CLAUDE_API_MAX_TOKENS` limit. The default is 16,384; a response that reaches
257
+ that limit is rejected as truncated instead of entering synthesis as a complete
258
+ answer.
259
+
260
+ `GROK_MODEL` is passed explicitly to `grok -m`. The default transport is the
261
+ headless Grok Build CLI using a private `--prompt-file` inside an isolated,
262
+ tool-free strict sandbox. If the CLI is missing, cannot execute, or has no
263
+ usable authentication, the same query and model fall back to `GROK_API_URL`
264
+ when `GROK_API_KEY` is set. Failures after a request launches (including
265
+ timeouts, model errors, and empty output) are returned without API fallback.
266
+ Set `GROK_USE_API=true` only to force the API path.
267
+
248
268
  `KIMI_MODEL` is passed directly to `kimi --model`, so `kimi-code/k3` overrides
249
269
  any older default stored in the user's Kimi CLI configuration.
250
270
 
package/scripts/config.sh CHANGED
@@ -64,12 +64,12 @@ DEFAULT_OUTPUT_DIR_BASE="${DEFAULT_OUTPUT_DIR_BASE:-${_AI_CONSULTANTS_XDG_CACHE}
64
64
  # =============================================================================
65
65
  # For agents that support both CLI and API mode, set USE_API=true to use API mode.
66
66
  # When API mode is enabled, CLI mode is automatically disabled (mutual exclusivity).
67
- # 6 agents support switching: Gemini, Codex, Claude, Mistral, Qwen3, MiniMax
67
+ # 7 agents support switching: Gemini, Codex, Claude, Mistral, Qwen3, Grok, MiniMax
68
68
 
69
69
  # Mode switching (true = API, false = CLI). DEFAULT IS CLI — when a consultant
70
70
  # has a CLI, the tool uses it; the CLIs are the primary transport (OAuth /
71
71
  # subscription, no API key needed). API mode is opt-in only: for CLI-less models
72
- # (GLM/Grok/DeepSeek are API-only anyway) or an explicit per-run user
72
+ # (GLM/DeepSeek are API-only) or an explicit per-run user
73
73
  # choice. Set a switch to true (with its API key) to force API for that agent.
74
74
  # GEMINI_USE_API is intentionally NOT defaulted here: it is auto-resolved in the
75
75
  # Gemini configuration section below (needs GEMINI_API_KEY / GEMINI_CMD), so an
@@ -78,6 +78,8 @@ CODEX_USE_API="${CODEX_USE_API:-false}"
78
78
  CLAUDE_USE_API="${CLAUDE_USE_API:-false}"
79
79
  MISTRAL_USE_API="${MISTRAL_USE_API:-false}"
80
80
  QWEN3_USE_API="${QWEN3_USE_API:-false}" # Default false to use qwen CLI
81
+ # GROK_USE_API is intentionally resolved in the Grok section: it is CLI-first,
82
+ # but must preserve an API-only installation when Grok Build is unavailable.
81
83
  # MINIMAX_USE_API is intentionally NOT defaulted here: it is auto-resolved in the
82
84
  # MiniMax configuration section below (needs MINIMAX_API_KEY), so an explicit
83
85
  # unset stays distinguishable from an explicit "false" (back-compat for pre-v2.21
@@ -186,14 +188,32 @@ GLM_FORMAT="${GLM_FORMAT:-openai}"
186
188
  # API key: Set GLM_API_KEY environment variable
187
189
 
188
190
  # =============================================================================
189
- # GROK CONFIGURATION - The Provocateur (API-based)
191
+ # GROK CONFIGURATION - The Provocateur (Grok Build CLI + API fallback)
190
192
  # =============================================================================
191
193
 
194
+ GROK_CMD="${GROK_CMD:-grok}"
192
195
  GROK_MODEL="${GROK_MODEL:-grok-4.5}"
193
196
  GROK_TIMEOUT_SECONDS="${GROK_TIMEOUT:-180}"
194
197
  GROK_API_URL="${GROK_API_URL:-https://api.x.ai/v1/chat/completions}"
195
198
  GROK_FORMAT="${GROK_FORMAT:-openai}"
196
- # API key: Set GROK_API_KEY environment variable
199
+ # Grok Build's official credential name is XAI_API_KEY. Keep the historical
200
+ # GROK_API_KEY public contract and accept XAI_API_KEY as its fallback alias.
201
+ GROK_API_KEY="${GROK_API_KEY:-${XAI_API_KEY:-}}"
202
+ export GROK_API_KEY
203
+
204
+ # CLI-first auto-resolution. Existing users can still pin GROK_USE_API=true,
205
+ # while an unpinned setup uses the CLI whenever it is installed and falls back
206
+ # to the API when only a key is available.
207
+ if [[ -z "${GROK_USE_API+x}" ]]; then
208
+ if command -v "$GROK_CMD" >/dev/null 2>&1; then
209
+ GROK_USE_API=false
210
+ elif [[ -n "$GROK_API_KEY" ]]; then
211
+ GROK_USE_API=true
212
+ else
213
+ GROK_USE_API=false
214
+ fi
215
+ fi
216
+ export GROK_USE_API
197
217
 
198
218
  # =============================================================================
199
219
  # DEEPSEEK CONFIGURATION - The Methodologist (API-based)
@@ -251,7 +271,8 @@ KIMI_CMD="${KIMI_CMD:-kimi}"
251
271
  # CLAUDE CONFIGURATION - The Synthesizer (v2.2)
252
272
  # =============================================================================
253
273
 
254
- CLAUDE_MODEL="${CLAUDE_MODEL:-claude-opus-4-8}"
274
+ CLAUDE_MODEL="${CLAUDE_MODEL:-claude-opus-5}"
275
+ CLAUDE_API_MAX_TOKENS="${CLAUDE_API_MAX_TOKENS:-16384}"
255
276
  CLAUDE_TIMEOUT_SECONDS="${CLAUDE_TIMEOUT:-240}"
256
277
  CLAUDE_CMD="${CLAUDE_CMD:-claude}"
257
278
 
@@ -265,10 +286,10 @@ CLAUDE_CMD="${CLAUDE_CMD:-claude}"
265
286
  ALL_CONSULTANTS=("Gemini" "Codex" "Mistral" "Cursor" "Kimi" "Claude" "Qwen3" "GLM" "Grok" "DeepSeek" "MiniMax")
266
287
 
267
288
  # CLI-based consultants (use CLI tools, some support CLI/API switching)
268
- CLI_CONSULTANTS=("Gemini" "Codex" "Mistral" "Cursor" "Kimi" "Claude" "Qwen3" "MiniMax")
289
+ CLI_CONSULTANTS=("Gemini" "Codex" "Mistral" "Cursor" "Kimi" "Claude" "Qwen3" "Grok" "MiniMax")
269
290
 
270
291
  # API-only consultants (use HTTP API directly, no CLI available)
271
- API_CONSULTANTS=("GLM" "Grok" "DeepSeek")
292
+ API_CONSULTANTS=("GLM" "DeepSeek")
272
293
 
273
294
  # =============================================================================
274
295
  # ENABLED CONSULTANTS
@@ -283,11 +304,11 @@ ENABLE_CURSOR="${ENABLE_CURSOR:-true}"
283
304
  ENABLE_KIMI="${ENABLE_KIMI:-true}" # Kimi Code (v2.9)
284
305
  ENABLE_CLAUDE="${ENABLE_CLAUDE:-true}" # Auto-disabled when invoked by Claude Code
285
306
  ENABLE_QWEN3="${ENABLE_QWEN3:-true}" # qwen-code CLI (v2.7); API opt-in
307
+ ENABLE_GROK="${ENABLE_GROK:-true}" # Grok Build CLI; API fallback
286
308
  ENABLE_MINIMAX="${ENABLE_MINIMAX:-true}" # mmx CLI (v2.21); API opt-in
287
309
 
288
310
  # API-only consultants (disabled by default - require API keys)
289
311
  ENABLE_GLM="${ENABLE_GLM:-false}"
290
- ENABLE_GROK="${ENABLE_GROK:-false}"
291
312
  ENABLE_DEEPSEEK="${ENABLE_DEEPSEEK:-false}"
292
313
 
293
314
  # =============================================================================
@@ -561,7 +582,7 @@ get_model_for_tier() {
561
582
  case "$tier" in
562
583
  premium|max|best)
563
584
  case "$consultant" in
564
- claude) echo "claude-opus-4-8" ;;
585
+ claude) echo "claude-opus-5" ;;
565
586
  gemini) echo "Gemini 3.1 Pro (High)" ;;
566
587
  codex) echo "gpt-5.5" ;;
567
588
  mistral) echo "mistral-large-3" ;;
@@ -758,4 +779,4 @@ EOF
758
779
  # VERSION
759
780
  # =============================================================================
760
781
 
761
- AI_CONSULTANTS_VERSION="3.0.0"
782
+ AI_CONSULTANTS_VERSION="3.2.0"
@@ -181,6 +181,25 @@ set_value() {
181
181
  }
182
182
 
183
183
  AUTO_MARKER="# ai-consultants:auto"
184
+ DEFAULT_MARKER="# ai-consultants:default"
185
+ PIN_MARKER="# ai-consultants:pin"
186
+
187
+ has_value_marker() {
188
+ local file="$1" key="$2" marker="$3" line normalized
189
+ [[ -r "$file" ]] || return 1
190
+ while IFS= read -r line || [[ -n "$line" ]]; do
191
+ line="${line%$'\r'}"
192
+ [[ "$line" =~ ^[[:space:]]*# ]] && continue
193
+ normalized="${line#"${line%%[![:space:]]*}"}"
194
+ if [[ "$normalized" =~ ^export[[:space:]]+ ]]; then
195
+ normalized="${normalized#export}"
196
+ normalized="${normalized#"${normalized%%[![:space:]]*}"}"
197
+ fi
198
+ [[ "$normalized" == "$key="* ]] || continue
199
+ [[ "$normalized" == *"$marker"* ]] && return 0
200
+ done < "$file"
201
+ return 1
202
+ }
184
203
 
185
204
  is_auto_managed_value() {
186
205
  local file="$1" key="$2" line normalized raw="" seen=false
@@ -239,13 +258,33 @@ set_auto_value() {
239
258
  # Merge existing persistent values first, then current environment overrides.
240
259
  while IFS= read -r key; do
241
260
  if [[ -f "$OUTPUT_FILE" ]] && value=$(read_value "$OUTPUT_FILE" "$key"); then
242
- set_value "$key" "$value"
261
+ if has_value_marker "$OUTPUT_FILE" "$key" "$DEFAULT_MARKER"; then
262
+ set_value "$key" "$value $DEFAULT_MARKER"
263
+ elif has_value_marker "$OUTPUT_FILE" "$key" "$PIN_MARKER"; then
264
+ set_value "$key" "$value $PIN_MARKER"
265
+ else
266
+ set_value "$key" "$value"
267
+ fi
243
268
  fi
244
269
  if [[ -n "${!key+x}" ]]; then
245
- set_value "$key" "${!key}"
270
+ if [[ "$key" == *_MODEL ]]; then
271
+ set_value "$key" "${!key} $PIN_MARKER"
272
+ else
273
+ set_value "$key" "${!key}"
274
+ fi
246
275
  fi
247
276
  done < <(list_parameters)
248
277
 
278
+ # Before model defaults had provenance markers, `init` copied the then-current
279
+ # Claude default as an ordinary-looking value. Refresh that exact historical
280
+ # default when configure rewrites the file. A real legacy pin is preserved by
281
+ # `--set CLAUDE_MODEL=claude-opus-4-8`, which records the pin marker.
282
+ if [[ "$(read_value "$WORK_FILE" CLAUDE_MODEL 2>/dev/null || true)" == "claude-opus-4-8" ]] \
283
+ && ! has_value_marker "$WORK_FILE" CLAUDE_MODEL "$PIN_MARKER"; then
284
+ set_value CLAUDE_MODEL "claude-opus-5 $DEFAULT_MARKER"
285
+ echo "Migrated managed Claude default: claude-opus-4-8 -> claude-opus-5" >&2
286
+ fi
287
+
249
288
  configure_cli_only() {
250
289
  local enable_key="$1" cmd_key="$2" cmd enabled=false
251
290
  cmd=$(effective_input_value "$cmd_key")
@@ -307,9 +346,9 @@ run_auto_detection() {
307
346
  configure_cli_only ENABLE_KIMI KIMI_CMD
308
347
  configure_switchable ENABLE_CLAUDE CLAUDE_CMD CLAUDE_USE_API ANTHROPIC_API_KEY
309
348
  configure_switchable ENABLE_QWEN3 QWEN3_CMD QWEN3_USE_API QWEN3_API_KEY
349
+ configure_switchable ENABLE_GROK GROK_CMD GROK_USE_API GROK_API_KEY
310
350
  configure_switchable ENABLE_MINIMAX MINIMAX_CMD MINIMAX_USE_API MINIMAX_API_KEY
311
351
  configure_api_only ENABLE_GLM GLM_API_KEY
312
- configure_api_only ENABLE_GROK GROK_API_KEY
313
352
  configure_api_only ENABLE_DEEPSEEK DEEPSEEK_API_KEY
314
353
  }
315
354
 
@@ -327,7 +366,11 @@ prompt_value() {
327
366
  else
328
367
  read -r -p "$key [$current]: " reply
329
368
  if [[ -n "$reply" ]]; then
330
- set_value "$key" "$reply"
369
+ if [[ "$key" == *_MODEL ]]; then
370
+ set_value "$key" "$reply $PIN_MARKER"
371
+ else
372
+ set_value "$key" "$reply"
373
+ fi
331
374
  fi
332
375
  fi
333
376
  }
@@ -346,7 +389,7 @@ if [[ "$MODE" == "interactive" ]]; then
346
389
  for key in ENABLE_GEMINI ENABLE_CODEX ENABLE_MISTRAL ENABLE_CURSOR ENABLE_KIMI ENABLE_CLAUDE ENABLE_QWEN3 ENABLE_GLM ENABLE_GROK ENABLE_DEEPSEEK ENABLE_MINIMAX; do
347
390
  prompt_value "$key"
348
391
  done
349
- for key in GEMINI_USE_API CODEX_USE_API MISTRAL_USE_API CLAUDE_USE_API QWEN3_USE_API MINIMAX_USE_API; do
392
+ for key in GEMINI_USE_API CODEX_USE_API MISTRAL_USE_API CLAUDE_USE_API QWEN3_USE_API GROK_USE_API MINIMAX_USE_API; do
350
393
  prompt_value "$key"
351
394
  done
352
395
 
@@ -359,7 +402,7 @@ if [[ "$MODE" == "interactive" ]]; then
359
402
  # parameter name as the user's answer instead.
360
403
  while IFS= read -r key <&3; do
361
404
  case "$key" in
362
- ENABLE_GEMINI|ENABLE_CODEX|ENABLE_MISTRAL|ENABLE_CURSOR|ENABLE_KIMI|ENABLE_CLAUDE|ENABLE_QWEN3|ENABLE_GLM|ENABLE_GROK|ENABLE_DEEPSEEK|ENABLE_MINIMAX|GEMINI_USE_API|CODEX_USE_API|MISTRAL_USE_API|CLAUDE_USE_API|QWEN3_USE_API|MINIMAX_USE_API|GEMINI_API_KEY|OPENAI_API_KEY|MISTRAL_API_KEY|ANTHROPIC_API_KEY|QWEN3_API_KEY|MINIMAX_API_KEY|GLM_API_KEY|GROK_API_KEY|DEEPSEEK_API_KEY) continue ;;
405
+ ENABLE_GEMINI|ENABLE_CODEX|ENABLE_MISTRAL|ENABLE_CURSOR|ENABLE_KIMI|ENABLE_CLAUDE|ENABLE_QWEN3|ENABLE_GLM|ENABLE_GROK|ENABLE_DEEPSEEK|ENABLE_MINIMAX|GEMINI_USE_API|CODEX_USE_API|MISTRAL_USE_API|CLAUDE_USE_API|QWEN3_USE_API|GROK_USE_API|MINIMAX_USE_API|GEMINI_API_KEY|OPENAI_API_KEY|MISTRAL_API_KEY|ANTHROPIC_API_KEY|QWEN3_API_KEY|MINIMAX_API_KEY|GLM_API_KEY|GROK_API_KEY|DEEPSEEK_API_KEY) continue ;;
363
406
  esac
364
407
  prompt_value "$key"
365
408
  done 3< <(list_parameters)
@@ -368,7 +411,11 @@ fi
368
411
 
369
412
  # Explicit command-line overrides have final precedence.
370
413
  for ((i=0; i<${#SET_KEYS[@]}; i++)); do
371
- set_value "${SET_KEYS[$i]}" "${SET_VALUES[$i]}"
414
+ if [[ "${SET_KEYS[$i]}" == *_MODEL ]]; then
415
+ set_value "${SET_KEYS[$i]}" "${SET_VALUES[$i]} $PIN_MARKER"
416
+ else
417
+ set_value "${SET_KEYS[$i]}" "${SET_VALUES[$i]}"
418
+ fi
372
419
  done
373
420
 
374
421
  enabled_count=0
package/scripts/doctor.sh CHANGED
@@ -219,10 +219,9 @@ check_cli_consultant() {
219
219
  return 0
220
220
  fi
221
221
 
222
- # Skip the CLI install check when the consultant runs in API mode. For the
223
- # 6 switchable agents (Gemini, Codex, Claude, Mistral, Qwen3, MiniMax) a missing CLI
224
- # is irrelevant once API mode is on -- the API key is validated separately
225
- # by check_api_mode. This matters most for Gemini, which auto-resolves to
222
+ # Switchable agents skip the CLI requirement while explicitly in API mode;
223
+ # the API key is validated separately by check_api_mode. This matters most
224
+ # for Gemini, which auto-resolves to
226
225
  # API mode whenever GEMINI_API_KEY is set (the npm-friendly path).
227
226
  local use_api_var="${env_var}_USE_API"
228
227
  if [[ "${!use_api_var:-false}" == "true" ]]; then
@@ -238,7 +237,9 @@ check_cli_consultant() {
238
237
  fi
239
238
  add_issue "consultant" "$name CLI not found" "$install_cmd"
240
239
  check_fail
241
- return 1
240
+ # A failed health check is data for the final diagnosis, not a reason
241
+ # to abort the diagnostic pipeline under `set -e`.
242
+ return 0
242
243
  fi
243
244
 
244
245
  # Get version (--version is standard and fast, no timeout needed)
@@ -265,6 +266,7 @@ check_cli_consultants() {
265
266
  check_cli_consultant "Kimi" "$KIMI_CMD" "curl -L code.kimi.com/install.sh | bash" "KIMI"
266
267
  check_cli_consultant "Claude" "$CLAUDE_CMD" "See https://docs.anthropic.com/claude-code" "CLAUDE"
267
268
  check_cli_consultant "Qwen" "$QWEN3_CMD" "npm install -g @qwen-code/qwen-code@latest" "QWEN3"
269
+ check_cli_consultant "Grok Build" "$GROK_CMD" "curl -fsSL https://x.ai/cli/install.sh | bash" "GROK"
268
270
  check_cli_consultant "MiniMax" "$MINIMAX_CMD" "npm install -g mmx-cli" "MINIMAX"
269
271
  }
270
272
 
@@ -291,7 +293,7 @@ check_api_mode() {
291
293
  _print " ✗ $name: API mode enabled but $api_key_var not set"
292
294
  add_issue "api_mode" "$name API mode enabled but API key missing" "export ${api_key_var}='your-api-key'"
293
295
  check_fail
294
- return 1
296
+ return 0
295
297
  else
296
298
  local masked_key="${api_key:0:4}...${api_key: -4}"
297
299
  _print " ✓ $name: API mode (key: $masked_key)"
@@ -308,7 +310,7 @@ check_api_mode_switching() {
308
310
  local has_api_mode=false
309
311
 
310
312
  # Check switchable consultants
311
- for agent in GEMINI CODEX CLAUDE MISTRAL QWEN3 MINIMAX; do
313
+ for agent in GEMINI CODEX CLAUDE MISTRAL QWEN3 GROK MINIMAX; do
312
314
  local enabled_var="ENABLE_${agent}"
313
315
  local use_api_var="${agent}_USE_API"
314
316
  local is_enabled="${!enabled_var:-false}"
@@ -326,6 +328,7 @@ check_api_mode_switching() {
326
328
  check_api_mode "Claude" "CLAUDE_USE_API" "ANTHROPIC_API_KEY" "ENABLE_CLAUDE"
327
329
  check_api_mode "Mistral" "MISTRAL_USE_API" "MISTRAL_API_KEY" "ENABLE_MISTRAL"
328
330
  check_api_mode "Qwen3" "QWEN3_USE_API" "QWEN3_API_KEY" "ENABLE_QWEN3"
331
+ check_api_mode "Grok" "GROK_USE_API" "GROK_API_KEY" "ENABLE_GROK"
329
332
  check_api_mode "MiniMax" "MINIMAX_USE_API" "MINIMAX_API_KEY" "ENABLE_MINIMAX"
330
333
  else
331
334
  _print " ○ All switchable consultants using CLI mode"
@@ -357,7 +360,7 @@ check_api_consultant() {
357
360
  _print " ✗ $name: API key not set"
358
361
  add_issue "api" "$name API key not configured" "export ${api_key_var}='your-api-key'"
359
362
  check_fail
360
- return 1
363
+ return 0
361
364
  fi
362
365
 
363
366
  # Mask API key for display
@@ -383,7 +386,6 @@ check_api_consultants() {
383
386
  print_section "Checking API-only Consultants"
384
387
 
385
388
  check_api_consultant "GLM" "GLM_API_KEY" "GLM_API_URL" "ENABLE_GLM"
386
- check_api_consultant "Grok" "GROK_API_KEY" "GROK_API_URL" "ENABLE_GROK"
387
389
  check_api_consultant "DeepSeek" "DEEPSEEK_API_KEY" "DEEPSEEK_API_URL" "ENABLE_DEEPSEEK"
388
390
  }
389
391
 
@@ -773,6 +775,7 @@ suggest_configuration() {
773
775
  "ENABLE_KIMI:${KIMI_CMD:-kimi}"
774
776
  "ENABLE_CLAUDE:${CLAUDE_CMD:-claude}"
775
777
  "ENABLE_QWEN3:${QWEN3_CMD:-qwen}"
778
+ "ENABLE_GROK:${GROK_CMD:-grok}"
776
779
  "ENABLE_MINIMAX:${MINIMAX_CMD:-mmx}"
777
780
  )
778
781
 
@@ -781,7 +784,8 @@ suggest_configuration() {
781
784
  for entry in "${consultant_clis[@]}"; do
782
785
  local flag="${entry%%:*}"
783
786
  local cmd="${entry##*:}"
784
- if command -v "$cmd" >/dev/null 2>&1; then
787
+ if command -v "$cmd" >/dev/null 2>&1 || \
788
+ [[ "$flag" == "ENABLE_GROK" && -n "${GROK_API_KEY:-}" ]]; then
785
789
  lines+=("${flag}=true")
786
790
  ((available_count++)) || true
787
791
  else
@@ -792,7 +796,6 @@ suggest_configuration() {
792
796
  # API-only consultants: enable if API key is set
793
797
  local api_consultants=(
794
798
  "ENABLE_GLM:GLM_API_KEY"
795
- "ENABLE_GROK:GROK_API_KEY"
796
799
  "ENABLE_DEEPSEEK:DEEPSEEK_API_KEY"
797
800
  )
798
801
  for entry in "${api_consultants[@]}"; do
@@ -856,13 +859,15 @@ _count_available_consultants() {
856
859
  "KIMI|ENABLE_KIMI|${KIMI_CMD:-kimi}"
857
860
  "CLAUDE|ENABLE_CLAUDE|${CLAUDE_CMD:-claude}"
858
861
  "QWEN3|ENABLE_QWEN3|${QWEN3_CMD:-qwen}"
862
+ "GROK|ENABLE_GROK|${GROK_CMD:-grok}"
859
863
  "MINIMAX|ENABLE_MINIMAX|${MINIMAX_CMD:-mmx}"
860
864
  )
861
865
  for entry in "${entries[@]}"; do
862
866
  IFS='|' read -r name flag cmd <<<"$entry"
863
867
  local enabled="${!flag:-false}"
864
868
  [[ "$enabled" != "true" ]] && continue
865
- if command -v "$cmd" >/dev/null 2>&1; then
869
+ if command -v "$cmd" >/dev/null 2>&1 || \
870
+ [[ "$name" == "GROK" && -n "${GROK_API_KEY:-}" ]]; then
866
871
  [[ "$name" == "$invoker_consultant" ]] && continue
867
872
  ((count++)) || true
868
873
  fi
@@ -871,7 +876,6 @@ _count_available_consultants() {
871
876
  # API-only consultants: enabled flag + API key both required
872
877
  local api_entries=(
873
878
  "GLM|ENABLE_GLM|GLM_API_KEY"
874
- "GROK|ENABLE_GROK|GROK_API_KEY"
875
879
  "DEEPSEEK|ENABLE_DEEPSEEK|DEEPSEEK_API_KEY"
876
880
  )
877
881
  for entry in "${api_entries[@]}"; do
@@ -249,7 +249,7 @@ build_openai_request() {
249
249
  build_anthropic_request() {
250
250
  local prompt="$1"
251
251
  local model="${2:-claude-sonnet-4-6}"
252
- local max_tokens="${3:-4096}"
252
+ local max_tokens="${3:-16384}"
253
253
 
254
254
  jq -n \
255
255
  --arg model "$model" \
@@ -327,7 +327,11 @@ parse_anthropic_response() {
327
327
  local response="$1"
328
328
 
329
329
  local content
330
- content=$(echo "$response" | jq -r '.content[0].text // empty' 2>/dev/null)
330
+ # Opus 5 may put a thinking block before the visible text block. Select
331
+ # every text block instead of assuming content[0] is user-visible output.
332
+ content=$(echo "$response" | jq -r \
333
+ '[.content[]? | select(.type == "text") | (.text // "")] | join("\n")' \
334
+ 2>/dev/null)
331
335
 
332
336
  if [[ -n "$content" && "$content" != "null" ]]; then
333
337
  echo "$content"
@@ -94,7 +94,14 @@ run_api_mode_query() {
94
94
  if [[ -n "$effort" ]]; then
95
95
  log_warn "[$consultant_name] $effort_var is not supported on the 'anthropic' wire format and is ignored."
96
96
  fi
97
- request_body=$(build_anthropic_request "$query" "$model")
97
+ local max_tokens_var api_max_tokens
98
+ max_tokens_var="$(to_upper "$consultant_name")_API_MAX_TOKENS"
99
+ api_max_tokens="${!max_tokens_var:-16384}"
100
+ if ! [[ "$api_max_tokens" =~ ^[1-9][0-9]*$ ]]; then
101
+ log_error "[$consultant_name] $max_tokens_var must be a positive integer (got: $api_max_tokens)"
102
+ return 1
103
+ fi
104
+ request_body=$(build_anthropic_request "$query" "$model" "$api_max_tokens")
98
105
  auth_style="anthropic"
99
106
  ;;
100
107
  qwen)
@@ -134,6 +141,16 @@ run_api_mode_query() {
134
141
  local raw_response
135
142
  raw_response=$(cat "$temp_response")
136
143
 
144
+ # Anthropic counts adaptive thinking and visible output against the same
145
+ # max_tokens budget. A max_tokens stop is therefore an incomplete answer,
146
+ # not a successful partial response suitable for synthesis.
147
+ if [[ "$api_format" == "anthropic" ]] \
148
+ && [[ "$(jq -r '.stop_reason // empty' <<<"$raw_response" 2>/dev/null)" == "max_tokens" ]]; then
149
+ log_error "[$consultant_name] API response was truncated at ${api_max_tokens:-the configured} max tokens"
150
+ rm -f "$temp_response"
151
+ return 1
152
+ fi
153
+
137
154
  local parsed_content
138
155
  case "$api_format" in
139
156
  google_ai)