ai-consultants 4.0.2 → 4.0.4

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.
Files changed (71) hide show
  1. package/.env.example +8 -11
  2. package/CLAUDE.md +18 -2
  3. package/README.md +13 -118
  4. package/SKILL.md +7 -3
  5. package/docs/COST_RATES.md +7 -4
  6. package/docs/JSON_SCHEMA.md +1 -1
  7. package/docs/SETUP.md +10 -25
  8. package/docs/SMART_ROUTING.md +8 -50
  9. package/docs/cost_rates.json +10 -5
  10. package/package.json +2 -1
  11. package/references/configuration.md +1 -1
  12. package/scripts/config.sh +9 -22
  13. package/scripts/configure.sh +8 -5
  14. package/scripts/consult_all.sh +3 -3
  15. package/scripts/doctor.sh +4 -4
  16. package/scripts/install.sh +2 -2
  17. package/scripts/lib/api.sh +0 -55
  18. package/scripts/lib/cache.sh +0 -24
  19. package/scripts/lib/code_optimizer.sh +0 -53
  20. package/scripts/lib/common.sh +1 -57
  21. package/scripts/lib/costs.sh +0 -17
  22. package/scripts/lib/personas.sh +0 -18
  23. package/scripts/lib/reliability.sh +0 -23
  24. package/scripts/lib/routing.sh +18 -119
  25. package/scripts/lib/session.sh +0 -81
  26. package/scripts/query_glm.sh +1 -1
  27. package/docs/releases/v2.10.1.md +0 -84
  28. package/docs/releases/v2.10.2.md +0 -40
  29. package/docs/releases/v2.10.3.md +0 -63
  30. package/docs/releases/v2.10.4.md +0 -63
  31. package/docs/releases/v2.10.5.md +0 -57
  32. package/docs/releases/v2.10.6.md +0 -59
  33. package/docs/releases/v2.10.7.md +0 -53
  34. package/docs/releases/v2.10.8.md +0 -58
  35. package/docs/releases/v2.10.9.md +0 -123
  36. package/docs/releases/v2.11.0.md +0 -163
  37. package/docs/releases/v2.12.0.md +0 -182
  38. package/docs/releases/v2.13.0.md +0 -179
  39. package/docs/releases/v2.13.1.md +0 -133
  40. package/docs/releases/v2.14.0.md +0 -124
  41. package/docs/releases/v2.14.1.md +0 -70
  42. package/docs/releases/v2.14.2.md +0 -77
  43. package/docs/releases/v2.15.0.md +0 -72
  44. package/docs/releases/v2.15.1.md +0 -80
  45. package/docs/releases/v2.16.0.md +0 -71
  46. package/docs/releases/v2.17.0.md +0 -62
  47. package/docs/releases/v2.17.1.md +0 -46
  48. package/docs/releases/v2.17.2.md +0 -51
  49. package/docs/releases/v2.18.0.md +0 -63
  50. package/docs/releases/v2.19.0.md +0 -66
  51. package/docs/releases/v2.19.1.md +0 -44
  52. package/docs/releases/v2.19.2.md +0 -54
  53. package/docs/releases/v2.20.0.md +0 -65
  54. package/docs/releases/v2.21.0.md +0 -65
  55. package/docs/releases/v2.21.1.md +0 -84
  56. package/docs/releases/v2.22.0.md +0 -82
  57. package/docs/releases/v2.23.0.md +0 -75
  58. package/docs/releases/v2.24.0.md +0 -88
  59. package/docs/releases/v2.25.0.md +0 -101
  60. package/docs/releases/v2.25.1.md +0 -77
  61. package/docs/releases/v2.25.2.md +0 -53
  62. package/docs/releases/v3.0.0.md +0 -71
  63. package/docs/releases/v3.1.0.md +0 -95
  64. package/docs/releases/v3.1.1.md +0 -54
  65. package/docs/releases/v3.2.0.md +0 -96
  66. package/docs/releases/v3.3.0.md +0 -80
  67. package/docs/releases/v3.4.0.md +0 -102
  68. package/docs/releases/v3.5.0.md +0 -129
  69. package/docs/releases/v4.0.0.md +0 -107
  70. package/docs/releases/v4.0.1.md +0 -57
  71. package/docs/releases/v4.0.2.md +0 -98
package/scripts/config.sh CHANGED
@@ -186,7 +186,7 @@ QWEN3_FORMAT="${QWEN3_FORMAT:-qwen}"
186
186
  # GLM CONFIGURATION - The Code Specialist (API-based)
187
187
  # =============================================================================
188
188
 
189
- GLM_MODEL="${GLM_MODEL:-glm-5.3}"
189
+ GLM_MODEL="${GLM_MODEL:-glm-5.3-flash}"
190
190
  GLM_TIMEOUT_SECONDS="${GLM_TIMEOUT:-180}"
191
191
  GLM_API_MAX_TOKENS="${GLM_API_MAX_TOKENS:-16384}"
192
192
  GLM_API_URL="${GLM_API_URL:-https://api.z.ai/api/coding/paas/v4/chat/completions}"
@@ -304,12 +304,6 @@ CLAUDE_CMD="${CLAUDE_CMD:-claude}"
304
304
  # All available consultants (ordered by typical usage)
305
305
  ALL_CONSULTANTS=("Gemini" "Codex" "Mistral" "Kimi" "Claude" "Qwen3" "GLM" "Grok" "DeepSeek" "MiniMax")
306
306
 
307
- # CLI-based consultants (use CLI tools, some support CLI/API switching)
308
- CLI_CONSULTANTS=("Gemini" "Codex" "Mistral" "Kimi" "Claude" "Qwen3" "Grok" "MiniMax")
309
-
310
- # API-only consultants (use HTTP API directly, no CLI available)
311
- API_CONSULTANTS=("GLM" "DeepSeek")
312
-
313
307
  # =============================================================================
314
308
  # ENABLED CONSULTANTS
315
309
  # =============================================================================
@@ -435,17 +429,11 @@ BUDGET_ACTION="${BUDGET_ACTION:-warn}"
435
429
  # (persistent across reboots; sessions enable follow-up queries).
436
430
  SESSION_DIR="${SESSION_DIR:-${_AI_CONSULTANTS_XDG_STATE}/sessions}"
437
431
 
438
- # Days after which to clean old sessions
432
+ # Deprecated no-op; retained through v4.x for configuration compatibility.
439
433
  SESSION_CLEANUP_DAYS="${SESSION_CLEANUP_DAYS:-7}"
440
434
 
441
- # =============================================================================
442
- # INTERACTIVE MODE (v2.0)
443
- # =============================================================================
444
-
445
- # Enable interactive progress bars
435
+ # Deprecated no-ops; retained through v4.x for configuration compatibility.
446
436
  ENABLE_PROGRESS_BARS="${ENABLE_PROGRESS_BARS:-true}"
447
-
448
- # Enable early termination (Ctrl+C to stop with partial responses)
449
437
  ENABLE_EARLY_TERMINATION="${ENABLE_EARLY_TERMINATION:-true}"
450
438
 
451
439
  # =============================================================================
@@ -485,7 +473,7 @@ ENABLE_SEMANTIC_CHUNKING="${ENABLE_SEMANTIC_CHUNKING:-true}"
485
473
  # Maximum tokens per chunk (for chunking mode)
486
474
  CHUNK_MAX_TOKENS="${CHUNK_MAX_TOKENS:-500}"
487
475
 
488
- # Use compact prompts (shorter personas and output format)
476
+ # Deprecated no-op; retained through v4.x for configuration compatibility.
489
477
  USE_COMPACT_PROMPTS="${USE_COMPACT_PROMPTS:-true}"
490
478
 
491
479
  # Extract only essential fields for synthesis (instead of full JSON)
@@ -525,8 +513,7 @@ USE_ECONOMIC_MODELS_FOR_SIMPLE="${USE_ECONOMIC_MODELS_FOR_SIMPLE:-true}"
525
513
  COMPLEXITY_THRESHOLD_SIMPLE="${COMPLEXITY_THRESHOLD_SIMPLE:-3}"
526
514
  COMPLEXITY_THRESHOLD_MEDIUM="${COMPLEXITY_THRESHOLD_MEDIUM:-6}"
527
515
 
528
- # --- Selective Context ---
529
- # Send only relevant files to each consultant
516
+ # Deprecated no-ops; retained through v4.x for configuration compatibility.
530
517
  ENABLE_SELECTIVE_CONTEXT="${ENABLE_SELECTIVE_CONTEXT:-false}"
531
518
  MAX_FILES_PER_CONSULTANT="${MAX_FILES_PER_CONSULTANT:-5}"
532
519
 
@@ -623,7 +610,7 @@ get_model_for_tier() {
623
610
  codex) echo "gpt-5.6-sol" ;;
624
611
  mistral) [[ "$transport" == "api" ]] && echo "mistral-large-3" || echo "mistral-medium-3.5" ;;
625
612
  deepseek) echo "deepseek-v4-pro" ;;
626
- glm) echo "glm-5.3" ;;
613
+ glm) echo "glm-5.3-flash" ;;
627
614
  grok) echo "grok-4.6" ;;
628
615
  qwen3) echo "qwen3.8-max" ;;
629
616
  kimi) echo "kimi-code/k3-256k" ;;
@@ -638,7 +625,7 @@ get_model_for_tier() {
638
625
  codex) echo "gpt-5.6-sol" ;;
639
626
  mistral) [[ "$transport" == "api" ]] && echo "mistral-large-3" || echo "mistral-medium-3.5" ;;
640
627
  deepseek) echo "deepseek-v4-pro" ;;
641
- glm) echo "glm-5.3" ;;
628
+ glm) echo "glm-5.3-flash" ;;
642
629
  grok) echo "grok-4.6" ;;
643
630
  qwen3) echo "qwen3.7-max" ;;
644
631
  kimi) echo "kimi-code/k3" ;;
@@ -653,7 +640,7 @@ get_model_for_tier() {
653
640
  codex) echo "gpt-5.6-terra" ;;
654
641
  mistral) [[ "$transport" == "api" ]] && echo "mistral-large-3" || echo "mistral-medium-3.5" ;;
655
642
  deepseek) echo "deepseek-v4-flash" ;;
656
- glm) echo "glm-5.3" ;; # Same as premium (no mid-tier GLM)
643
+ glm) echo "glm-5.3-flash" ;; # Same as premium (no mid-tier GLM)
657
644
  grok) echo "grok-4.5" ;;
658
645
  qwen3) echo "qwen3.6-35b-a3b" ;; # Open-weight MoE (35B total, 3B active)
659
646
  kimi) echo "kimi-code/k3" ;;
@@ -1011,4 +998,4 @@ EOF
1011
998
  # VERSION
1012
999
  # =============================================================================
1013
1000
 
1014
- AI_CONSULTANTS_VERSION="4.0.2"
1001
+ AI_CONSULTANTS_VERSION="4.0.4"
@@ -307,11 +307,14 @@ if [[ "$(read_value "$WORK_FILE" GEMINI_MODEL 2>/dev/null || true)" == "Gemini 3
307
307
  echo "Migrated managed Gemini CLI default: Gemini 3.1 Pro (High) -> Gemini 3.7 Flash (High)" >&2
308
308
  fi
309
309
 
310
- if [[ "$(read_value "$WORK_FILE" GLM_MODEL 2>/dev/null || true)" == "glm-5.2" ]] \
311
- && ! has_value_marker "$WORK_FILE" GLM_MODEL "$PIN_MARKER"; then
312
- set_value GLM_MODEL "glm-5.3 $DEFAULT_MARKER"
313
- echo "Migrated managed GLM default: glm-5.2 -> glm-5.3" >&2
314
- fi
310
+ case "$(read_value "$WORK_FILE" GLM_MODEL 2>/dev/null || true)" in
311
+ glm-5.2|glm-5.3)
312
+ if ! has_value_marker "$WORK_FILE" GLM_MODEL "$PIN_MARKER"; then
313
+ set_value GLM_MODEL "glm-5.3-flash $DEFAULT_MARKER"
314
+ echo "Migrated managed GLM default to glm-5.3-flash" >&2
315
+ fi
316
+ ;;
317
+ esac
315
318
 
316
319
  if [[ "$(read_value "$WORK_FILE" GROK_MODEL 2>/dev/null || true)" == "grok-4.5" ]] \
317
320
  && ! has_value_marker "$WORK_FILE" GROK_MODEL "$PIN_MARKER"; then
@@ -489,12 +489,12 @@ if [[ ${#SELECTED_CONSULTANTS[@]} -eq 0 ]]; then
489
489
  exit 1
490
490
  fi
491
491
 
492
- # Minimum 2 consultants required for meaningful comparison
492
+ # Minimum 2 consultants required for a coverage panel
493
493
  if [[ ${#SELECTED_CONSULTANTS[@]} -lt 2 ]]; then
494
- log_error "At least 2 consultants required for meaningful comparison."
494
+ log_error "At least 2 consultants are required for a coverage panel."
495
495
  log_error "Currently enabled: ${#SELECTED_CONSULTANTS[@]} (${SELECTED_CONSULTANTS[*]})"
496
496
  echo "" >&2
497
- log_info "Run ./scripts/setup_wizard.sh to configure additional consultants"
497
+ log_info "Run \"$SCRIPT_DIR/../bin/ai-consultants\" configure to configure additional consultants"
498
498
  log_info "Or manually enable more:"
499
499
  log_info " ENABLE_GEMINI=true ENABLE_CODEX=true ./scripts/consult_all.sh \"query\""
500
500
  exit 1
package/scripts/doctor.sh CHANGED
@@ -413,11 +413,11 @@ check_configuration() {
413
413
  check_pass
414
414
  elif [[ $enabled_count -eq 1 ]]; then
415
415
  _print " ✗ Enabled consultants: $enabled_count (need at least 2)"
416
- add_issue "config" "Only 1 consultant enabled, need at least 2" "Run: ./scripts/setup_wizard.sh"
416
+ add_issue "config" "Only 1 consultant enabled, need at least 2" "Run: \"$SCRIPT_DIR/../bin/ai-consultants\" configure"
417
417
  check_fail
418
418
  else
419
419
  _print " ✗ Enabled consultants: 0 (need at least 2)"
420
- add_issue "config" "No consultants enabled" "Run: ./scripts/setup_wizard.sh"
420
+ add_issue "config" "No consultants enabled" "Run: \"$SCRIPT_DIR/../bin/ai-consultants\" configure"
421
421
  check_fail
422
422
  fi
423
423
 
@@ -825,8 +825,8 @@ suggest_configuration() {
825
825
  if (( available_count < 2 )); then
826
826
  echo ""
827
827
  echo "# WARNING: Less than 2 consultants available."
828
- echo "# AI Consultants requires at least 2 to deliberate."
829
- echo "# Install more CLIs or run ./scripts/setup_wizard.sh"
828
+ echo "# AI Consultants requires at least 2 for a coverage panel."
829
+ echo "# Install more CLIs or run \"$SCRIPT_DIR/../bin/ai-consultants\" configure"
830
830
  fi
831
831
  }
832
832
 
@@ -348,8 +348,8 @@ echo "━━━━━━━━━━━━━━━━━━━━━━━━
348
348
  echo ""
349
349
  log_info "Option B: Configure via Bash"
350
350
  echo ""
351
- echo " 1. Run the setup wizard:"
352
- echo " $INSTALL_DIR/scripts/setup_wizard.sh"
351
+ echo " 1. Configure available consultants:"
352
+ echo " $INSTALL_DIR/bin/ai-consultants configure"
353
353
  echo ""
354
354
  echo " 2. Run a consultation:"
355
355
  echo " $INSTALL_DIR/scripts/consult_all.sh \"Your question\""
@@ -38,46 +38,6 @@ sanitize_error_message() {
38
38
  -e 's/([a-zA-Z0-9_-]{32,})/[POSSIBLE_KEY]/g'
39
39
  }
40
40
 
41
- # =============================================================================
42
- # API KEY VALIDATION
43
- # =============================================================================
44
-
45
- # Check if an API key environment variable is set
46
- # Usage: check_api_key "QWEN3_API_KEY" "Qwen3"
47
- check_api_key() {
48
- local key_var_name="$1"
49
- local consultant_name="$2"
50
-
51
- # Get the value of the environment variable by name
52
- local key_value="${!key_var_name:-}"
53
-
54
- if [[ -z "$key_value" ]]; then
55
- log_error "[$consultant_name] API key not set: $key_var_name"
56
- log_info "Set the $key_var_name environment variable to use $consultant_name"
57
- return 1
58
- fi
59
-
60
- # Basic validation: key should be non-empty and not contain obvious placeholders
61
- if [[ "$key_value" == *"your_"* ]] || [[ "$key_value" == *"YOUR_"* ]] || [[ "$key_value" == "xxx"* ]]; then
62
- log_error "[$consultant_name] API key appears to be a placeholder: $key_var_name"
63
- return 1
64
- fi
65
-
66
- # Validate key format (minimum length, no whitespace)
67
- if [[ ${#key_value} -lt 10 ]]; then
68
- log_error "[$consultant_name] API key too short: $key_var_name"
69
- return 1
70
- fi
71
-
72
- if [[ "$key_value" =~ [[:space:]] ]]; then
73
- log_error "[$consultant_name] API key contains whitespace: $key_var_name"
74
- return 1
75
- fi
76
-
77
- log_debug "[$consultant_name] API key validated"
78
- return 0
79
- }
80
-
81
41
  # =============================================================================
82
42
  # HTTP ERROR HANDLING
83
43
  # =============================================================================
@@ -724,18 +684,3 @@ check_rate_limit() {
724
684
 
725
685
  return 0
726
686
  }
727
-
728
- # Clear rate limit state for a consultant (useful for testing)
729
- # Usage: clear_rate_limit <consultant_name>
730
- clear_rate_limit() {
731
- local consultant_name="$1"
732
- local safe_name=$(echo "$consultant_name" | tr '[:upper:]' '[:lower:]' | tr -cs '[:alnum:]' '_')
733
- local state_file="${RATE_LIMIT_DIR}/${safe_name}_ratelimit"
734
-
735
- rm -f "$state_file" 2>/dev/null || true
736
- }
737
-
738
- # Clear all rate limit state
739
- clear_all_rate_limits() {
740
- rm -rf "$RATE_LIMIT_DIR" 2>/dev/null || true
741
- }
@@ -228,30 +228,6 @@ store_cache() {
228
228
  mv "$temp_file" "$cache_file"
229
229
  }
230
230
 
231
- # Invalidate cache for a specific query
232
- # Usage: invalidate_cache <query> <category> [consultant] [context_file]
233
- invalidate_cache() {
234
- local query="$1"
235
- local category="${2:-GENERAL}"
236
- local consultant="${3:-}"
237
- local context_file="${4:-}"
238
-
239
- init_cache
240
-
241
- local fingerprint
242
- fingerprint=$(generate_fingerprint "$query" "$category" "$context_file")
243
-
244
- if [[ -n "$consultant" ]]; then
245
- # Invalidate specific consultant cache
246
- local cache_file
247
- cache_file=$(_get_cache_path "$fingerprint" "$consultant")
248
- rm -f "$cache_file" 2>/dev/null || true
249
- else
250
- # Invalidate all caches for this fingerprint
251
- rm -f "${CACHE_DIR}"/*_"${fingerprint}".json 2>/dev/null || true
252
- fi
253
- }
254
-
255
231
  # Clear all expired cache entries
256
232
  # Usage: cleanup_cache
257
233
  cleanup_cache() {
@@ -616,56 +616,3 @@ optimize_code_files() {
616
616
  log_success "Optimized $processed of $total_files files"
617
617
  }
618
618
 
619
- # =============================================================================
620
- # TOKEN ESTIMATION
621
- # =============================================================================
622
-
623
- # Estimate token savings from optimization
624
- # Usage: estimate_token_savings "/path/to/file.py"
625
- # Returns: JSON with original_tokens, optimized_tokens, savings_percent
626
- estimate_token_savings() {
627
- local file_path="$1"
628
-
629
- if [ ! -f "$file_path" ]; then
630
- log_error "File not found: $file_path"
631
- return 1
632
- fi
633
-
634
- # Get original size
635
- local original_chars
636
- original_chars=$(wc -c < "$file_path" | tr -d ' ')
637
- local original_tokens=$((original_chars / 4))
638
-
639
- # Get optimized size
640
- local optimized_content
641
- optimized_content=$(optimize_code_file "$file_path")
642
- local optimized_chars
643
- optimized_chars=$(echo -n "$optimized_content" | wc -c | tr -d ' ')
644
- local optimized_tokens=$((optimized_chars / 4))
645
-
646
- # Calculate savings
647
- local savings_percent=0
648
- if [ "$original_tokens" -gt 0 ]; then
649
- savings_percent=$(( (original_tokens - optimized_tokens) * 100 / original_tokens ))
650
- fi
651
-
652
- # Output JSON
653
- cat <<EOF
654
- {
655
- "file": "$file_path",
656
- "original_tokens": $original_tokens,
657
- "optimized_tokens": $optimized_tokens,
658
- "savings_tokens": $((original_tokens - optimized_tokens)),
659
- "savings_percent": $savings_percent
660
- }
661
- EOF
662
- }
663
-
664
- # Check if a file should be optimized based on extension
665
- # Usage: is_optimizable_file "/path/to/file.py"
666
- is_optimizable_file() {
667
- local lang
668
- lang=$(detect_language "$1")
669
- [ "$lang" != "unknown" ]
670
- }
671
-
@@ -310,7 +310,7 @@ KNOWN_API_AGENTS="GLM DEEPSEEK"
310
310
  # therefore a latent phantom-consultant bug, not a cosmetic omission -- it had
311
311
  # drifted 18 flags out of date before the pin below existed.
312
312
  # KEEP IN SYNC with the top-level ENABLE_* declarations in config.sh;
313
- # test_functions.sh::test_known_feature_flags_in_sync fails the build otherwise.
313
+ # test_common.sh::test_known_feature_flags_in_sync fails the build otherwise.
314
314
  KNOWN_FEATURE_FLAGS="PERSONA SYNTHESIS CLASSIFICATION SMART_ROUTING \
315
315
  COST_TRACKING PROGRESS_BARS EARLY_TERMINATION PREFLIGHT \
316
316
  AST_EXTRACTION BUDGET_LIMIT \
@@ -835,29 +835,6 @@ estimate_tokens() {
835
835
  echo $((chars / 4))
836
836
  }
837
837
 
838
- # Estimate tokens from a file
839
- # Usage: estimate_tokens_file "/path/to/file"
840
- estimate_tokens_file() {
841
- local file_path="$1"
842
- if [[ -f "$file_path" ]]; then
843
- local chars
844
- chars=$(wc -c < "$file_path" | tr -d ' ')
845
- echo $((chars / 4))
846
- else
847
- echo 0
848
- fi
849
- }
850
-
851
- # Log token estimate with label
852
- # Usage: log_token_estimate "Prompt" "$prompt_text"
853
- log_token_estimate() {
854
- local label="$1"
855
- local text="$2"
856
- local tokens
857
- tokens=$(estimate_tokens "$text")
858
- log_debug "$label: ~$tokens tokens (~$((tokens * 4)) chars)"
859
- }
860
-
861
838
  # =============================================================================
862
839
  # RESPONSE BUILDERS (v2.4)
863
840
  # =============================================================================
@@ -1316,39 +1293,6 @@ process_consultant_response() {
1316
1293
  return $exit_code
1317
1294
  }
1318
1295
 
1319
- # Check if a consultant is enabled
1320
- # Usage: is_consultant_enabled <consultant_name>
1321
- # Returns: 0 if enabled, 1 if disabled
1322
- is_consultant_enabled() {
1323
- local name="$1"
1324
- local name_upper
1325
- name_upper=$(to_upper "$name")
1326
- local var_name="ENABLE_${name_upper}"
1327
-
1328
- # Get default based on consultant type
1329
- local default="true"
1330
- case "$name_upper" in
1331
- GLM|DEEPSEEK)
1332
- default="false"
1333
- ;;
1334
- esac
1335
-
1336
- [[ "${!var_name:-$default}" == "true" ]]
1337
- }
1338
-
1339
- # Get list of enabled consultants
1340
- # Usage: get_enabled_consultants
1341
- # Output: Space-separated list of enabled consultant names
1342
- get_enabled_consultants() {
1343
- local enabled=()
1344
- for consultant in "${ALL_CONSULTANTS[@]}"; do
1345
- if is_consultant_enabled "$consultant"; then
1346
- enabled+=("$consultant")
1347
- fi
1348
- done
1349
- echo "${enabled[@]}"
1350
- }
1351
-
1352
1296
  # =============================================================================
1353
1297
  # SYNTHESIS CLI RESOLUTION (v2.10.1)
1354
1298
  # =============================================================================
@@ -650,23 +650,6 @@ generate_cost_report() {
650
650
  jq -r '.sessions | .[-5:] | .[] | " \(.timestamp): \(.id) - $\(.cost)"' "$COST_TRACKING_FILE" 2>/dev/null || echo " No sessions"
651
651
  }
652
652
 
653
- # =============================================================================
654
- # UTILITY
655
- # =============================================================================
656
-
657
- # Convert tokens to estimated cost (quick helper)
658
- # Usage: tokens_to_cost <tokens> [model]
659
- tokens_to_cost() {
660
- local tokens="$1"
661
- local model="${2:-default}"
662
-
663
- # Assume 60/40 split
664
- local input=$((tokens * 60 / 100))
665
- local output=$((tokens * 40 / 100))
666
-
667
- estimate_query_cost "$model" "$input" "$output"
668
- }
669
-
670
653
  # =============================================================================
671
654
  # RESPONSE LENGTH LIMITS (v2.3)
672
655
  # =============================================================================
@@ -159,16 +159,6 @@ PERSONA_CATALOG="
159
159
  # CATALOG FUNCTIONS
160
160
  # =============================================================================
161
161
 
162
- # List all available personas
163
- # Usage: list_personas
164
- list_personas() {
165
- echo "Available Personas:"
166
- echo ""
167
- echo "$PERSONA_CATALOG" | grep -v '^$' | while IFS='|' read -r id name var desc; do
168
- printf " %2s) %-22s - %s\n" "$id" "$name" "$desc"
169
- done
170
- }
171
-
172
162
  # Get persona info by ID
173
163
  # Usage: get_persona_by_id <id> [field]
174
164
  # Fields: name, var, desc, all (default: all)
@@ -331,14 +321,6 @@ get_persona_name() {
331
321
  echo "External Consultant"
332
322
  }
333
323
 
334
- # Get persona ID for a consultant (for configuration display)
335
- # Usage: get_persona_id "Gemini"
336
- get_persona_id() {
337
- local upper
338
- upper=$(_normalize_name "$1")
339
- _resolve_persona_id "$upper"
340
- }
341
-
342
324
  # Build complete system prompt with persona + output format
343
325
  # Usage: build_system_prompt "Gemini"
344
326
  build_system_prompt() {
@@ -107,26 +107,3 @@ get_consultant_reliability() {
107
107
  | if $a > 0 then (($s * 100) / $a | floor) else -1 end' \
108
108
  "$RELIABILITY_FILE" 2>/dev/null || echo "-1"
109
109
  }
110
-
111
- # Format a short human-readable reliability report, sorted by success% asc.
112
- # Usage: format_reliability_report
113
- format_reliability_report() {
114
- if [[ ! -f "$RELIABILITY_FILE" ]]; then
115
- echo "No reliability data available"
116
- return
117
- fi
118
-
119
- echo " Consultant | Attempts | Success%"
120
- echo " ---------------------|----------|---------"
121
- jq -r '
122
- .consultants
123
- | to_entries
124
- | map({name: .key, attempts: (.value.attempts // 0), successes: (.value.successes // 0)})
125
- | map(. + {rate: (if .attempts > 0 then (((.successes * 100) / .attempts) | floor) else -1 end)})
126
- | sort_by(.rate)
127
- | .[]
128
- | " \(.name)|\(.attempts)|\(.rate)"
129
- ' "$RELIABILITY_FILE" 2>/dev/null | while IFS='|' read -r name attempts rate; do
130
- printf " %-20s | %-8s | %s%%\n" "$name" "$attempts" "$rate"
131
- done
132
- }
@@ -194,34 +194,6 @@ select_consultants() {
194
194
  done
195
195
  }
196
196
 
197
- # Get the list of consultants as JSON
198
- # Usage: get_selected_consultants_json <category> [min_affinity]
199
- get_selected_consultants_json() {
200
- local category="$1"
201
- local min_affinity="${2:-7}"
202
-
203
- local consultants
204
- consultants=$(select_consultants "$category" "$min_affinity")
205
- local json="["
206
- local first=true
207
-
208
- while IFS= read -r c; do
209
- if [[ -n "$c" ]]; then
210
- local score
211
- score=$(get_affinity "$category" "$c")
212
- if [[ "$first" == "true" ]]; then
213
- first=false
214
- else
215
- json+=","
216
- fi
217
- json+="{\"consultant\":\"$c\",\"affinity\":$score}"
218
- fi
219
- done <<< "$consultants"
220
-
221
- json+="]"
222
- echo "$json"
223
- }
224
-
225
197
  # Check if a consultant is recommended for a category
226
198
  # Usage: is_recommended <category> <consultant> [min_affinity]
227
199
  is_recommended() {
@@ -236,77 +208,36 @@ is_recommended() {
236
208
  return 1
237
209
  }
238
210
 
239
- # =============================================================================
240
- # SMART ROUTING MODES
241
- # =============================================================================
242
-
243
- # Determine the routing mode based on the category
244
- # Usage: get_routing_mode <category>
245
- # Returns: full|selective|single
211
+ # Backward-compatible routing utilities. The orchestrator selects directly by
212
+ # affinity; these helpers remain for users that source routing.sh.
246
213
  get_routing_mode() {
247
214
  local category="$1"
248
-
249
215
  case "$category" in
250
- SECURITY)
251
- # Security: all consultants (important)
252
- echo "full"
253
- ;;
254
- QUICK_SYNTAX)
255
- # Syntax: just one needed
256
- echo "single"
257
- ;;
258
- CODE_REVIEW|BUG_DEBUG|ARCHITECTURE)
259
- # Important: at least 3
260
- echo "selective"
261
- ;;
262
- *)
263
- # Default: all
264
- echo "full"
265
- ;;
216
+ SECURITY) echo "full" ;;
217
+ QUICK_SYNTAX) echo "single" ;;
218
+ CODE_REVIEW|BUG_DEBUG|ARCHITECTURE) echo "selective" ;;
219
+ *) echo "full" ;;
266
220
  esac
267
221
  }
268
222
 
269
- # Get the recommended number of consultants
270
- # Usage: get_recommended_count <category>
271
223
  get_recommended_count() {
272
- local category="$1"
273
- local mode=$(get_routing_mode "$category")
274
-
224
+ local mode
225
+ mode=$(get_routing_mode "$1")
275
226
  case "$mode" in
276
- full)
277
- echo 10 # All consultants (CLI + API)
278
- ;;
279
- selective)
280
- echo 5 # Subset based on affinity
281
- ;;
282
- single)
283
- echo 1
284
- ;;
285
- *)
286
- echo 10
287
- ;;
227
+ full) echo 10 ;;
228
+ selective) echo 5 ;;
229
+ single) echo 1 ;;
230
+ *) echo 10 ;;
288
231
  esac
289
232
  }
290
233
 
291
- # =============================================================================
292
- # TIMEOUT ADJUSTMENTS
293
- # =============================================================================
294
-
295
- # Get recommended timeout for a category
296
- # Usage: get_category_timeout <category>
297
234
  get_category_timeout() {
298
- local category="$1"
299
- case "$category" in
300
- QUICK_SYNTAX) echo 60 ;;
301
- BUG_DEBUG) echo 180 ;;
302
- ARCHITECTURE) echo 240 ;;
303
- SECURITY) echo 240 ;;
304
- CODE_REVIEW) echo 180 ;;
305
- ALGORITHM) echo 180 ;;
306
- DATABASE) echo 120 ;;
307
- API_DESIGN) echo 180 ;;
308
- TESTING) echo 120 ;;
309
- GENERAL|*) echo 180 ;;
235
+ case "$1" in
236
+ QUICK_SYNTAX) echo 60 ;;
237
+ BUG_DEBUG|CODE_REVIEW|ALGORITHM|API_DESIGN) echo 180 ;;
238
+ ARCHITECTURE|SECURITY) echo 240 ;;
239
+ DATABASE|TESTING) echo 120 ;;
240
+ GENERAL|*) echo 180 ;;
310
241
  esac
311
242
  }
312
243
 
@@ -345,14 +276,12 @@ select_consultants_cost_aware() {
345
276
 
346
277
  # Simple queries: only economic models, fewer consultants
347
278
  if [[ $complexity -le $simple_threshold ]]; then
348
- # For simple queries, use only 2 consultants with economic models
349
279
  select_consultants "$category" "$min_affinity" 2
350
280
  return
351
281
  fi
352
282
 
353
283
  # Medium complexity: balanced selection
354
284
  if [[ $complexity -le $medium_threshold ]]; then
355
- # Use standard selection but limit to 3-4 consultants
356
285
  select_consultants "$category" "$min_affinity" 4
357
286
  return
358
287
  fi
@@ -395,36 +324,6 @@ get_cost_aware_model() {
395
324
  echo ""
396
325
  }
397
326
 
398
- # Check if cost-aware routing is enabled
399
- # Usage: is_cost_aware_routing_enabled
400
- is_cost_aware_routing_enabled() {
401
- [[ "${ENABLE_COST_AWARE_ROUTING:-false}" == "true" ]]
402
- }
403
-
404
- # Get routing summary for logging
405
- # Usage: get_routing_summary <category> <complexity> <num_consultants>
406
- get_routing_summary() {
407
- local category="$1"
408
- local complexity="${2:-5}"
409
- local num_consultants="${3:-5}"
410
-
411
- local mode="standard"
412
- if is_cost_aware_routing_enabled; then
413
- local simple_threshold="${COMPLEXITY_THRESHOLD_SIMPLE:-3}"
414
- local medium_threshold="${COMPLEXITY_THRESHOLD_MEDIUM:-6}"
415
-
416
- if [[ $complexity -le $simple_threshold ]]; then
417
- mode="economic"
418
- elif [[ $complexity -le $medium_threshold ]]; then
419
- mode="balanced"
420
- else
421
- mode="comprehensive"
422
- fi
423
- fi
424
-
425
- echo "{\"category\":\"$category\",\"complexity\":$complexity,\"mode\":\"$mode\",\"consultants\":$num_consultants}"
426
- }
427
-
428
327
  # =============================================================================
429
328
  # FALLBACK ESCALATION (v2.3 Quality Review)
430
329
  # =============================================================================