ai-consultants 2.10.1
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.
- package/.claude/commands/ai-consultants:consult.md +94 -0
- package/.claude/commands/ai-consultants:debate.md +103 -0
- package/.claude/commands/ai-consultants:help.md +30 -0
- package/CLAUDE.md +839 -0
- package/LICENSE +21 -0
- package/README.md +758 -0
- package/SKILL.md +156 -0
- package/bin/ai-consultants +96 -0
- package/docs/COST_RATES.md +172 -0
- package/docs/JSON_SCHEMA.md +305 -0
- package/docs/SETUP.md +879 -0
- package/docs/SMART_ROUTING.md +219 -0
- package/docs/cost_rates.json +143 -0
- package/package.json +47 -0
- package/references/configuration.md +141 -0
- package/references/details.md +60 -0
- package/scripts/build_context.sh +562 -0
- package/scripts/classify_question.sh +148 -0
- package/scripts/config.sh +753 -0
- package/scripts/configure.sh +1093 -0
- package/scripts/consult_all.sh +934 -0
- package/scripts/debate_round.sh +421 -0
- package/scripts/doctor.sh +642 -0
- package/scripts/followup.sh +197 -0
- package/scripts/install.sh +319 -0
- package/scripts/lib/api.sh +640 -0
- package/scripts/lib/api_query.sh +228 -0
- package/scripts/lib/cache.sh +338 -0
- package/scripts/lib/chunking.sh +880 -0
- package/scripts/lib/code_optimizer.sh +671 -0
- package/scripts/lib/common.sh +1088 -0
- package/scripts/lib/costs.sh +674 -0
- package/scripts/lib/personas.sh +372 -0
- package/scripts/lib/progress.sh +251 -0
- package/scripts/lib/reflection.sh +447 -0
- package/scripts/lib/routing.sh +566 -0
- package/scripts/lib/schema.json +165 -0
- package/scripts/lib/session.sh +327 -0
- package/scripts/lib/symbol_map.sh +445 -0
- package/scripts/lib/voting.sh +495 -0
- package/scripts/peer_review.sh +460 -0
- package/scripts/preflight_check.sh +452 -0
- package/scripts/query_aider.sh +83 -0
- package/scripts/query_amp.sh +67 -0
- package/scripts/query_claude.sh +99 -0
- package/scripts/query_codex.sh +92 -0
- package/scripts/query_cursor.sh +72 -0
- package/scripts/query_deepseek.sh +17 -0
- package/scripts/query_gemini.sh +85 -0
- package/scripts/query_glm.sh +17 -0
- package/scripts/query_grok.sh +17 -0
- package/scripts/query_kilo.sh +140 -0
- package/scripts/query_kimi.sh +67 -0
- package/scripts/query_minimax.sh +17 -0
- package/scripts/query_mistral.sh +97 -0
- package/scripts/query_ollama.sh +328 -0
- package/scripts/query_qwen3.sh +93 -0
- package/scripts/setup_wizard.sh +367 -0
- package/scripts/skillport-install.sh +196 -0
- package/scripts/synthesize.sh +332 -0
- package/templates/consultation_report.md +323 -0
- package/templates/synthesis_prompt.md +120 -0
|
@@ -0,0 +1,566 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# routing.sh - Smart consultant selection based on question type
|
|
3
|
+
#
|
|
4
|
+
# Selects the most suitable consultants based on the question category.
|
|
5
|
+
|
|
6
|
+
# =============================================================================
|
|
7
|
+
# AFFINITY MATRIX
|
|
8
|
+
# =============================================================================
|
|
9
|
+
# Using case statements for bash 3.2 compatibility (no associative arrays)
|
|
10
|
+
# Affinity scores: 10 = perfect match, 1 = poor match
|
|
11
|
+
|
|
12
|
+
# =============================================================================
|
|
13
|
+
# SELECTION FUNCTIONS
|
|
14
|
+
# =============================================================================
|
|
15
|
+
|
|
16
|
+
# Get affinity for a category-consultant combination
|
|
17
|
+
# Usage: get_affinity <category> <consultant>
|
|
18
|
+
get_affinity() {
|
|
19
|
+
local category="$1"
|
|
20
|
+
local consultant="$2"
|
|
21
|
+
|
|
22
|
+
case "$category" in
|
|
23
|
+
CODE_REVIEW)
|
|
24
|
+
case "$consultant" in
|
|
25
|
+
Gemini) echo 7 ;;
|
|
26
|
+
Codex) echo 10 ;;
|
|
27
|
+
Mistral) echo 8 ;;
|
|
28
|
+
Kilo) echo 9 ;;
|
|
29
|
+
Cursor) echo 9 ;;
|
|
30
|
+
Aider) echo 9 ;;
|
|
31
|
+
Amp) echo 7 ;;
|
|
32
|
+
Kimi) echo 7 ;;
|
|
33
|
+
Claude) echo 8 ;;
|
|
34
|
+
Qwen3) echo 8 ;;
|
|
35
|
+
GLM) echo 8 ;;
|
|
36
|
+
Grok) echo 7 ;;
|
|
37
|
+
DeepSeek) echo 10 ;;
|
|
38
|
+
MiniMax) echo 8 ;;
|
|
39
|
+
*) echo 5 ;;
|
|
40
|
+
esac
|
|
41
|
+
;;
|
|
42
|
+
BUG_DEBUG)
|
|
43
|
+
case "$consultant" in
|
|
44
|
+
Gemini) echo 7 ;;
|
|
45
|
+
Codex) echo 10 ;;
|
|
46
|
+
Mistral) echo 9 ;;
|
|
47
|
+
Kilo) echo 8 ;;
|
|
48
|
+
Cursor) echo 9 ;;
|
|
49
|
+
Aider) echo 9 ;;
|
|
50
|
+
Amp) echo 8 ;;
|
|
51
|
+
Kimi) echo 6 ;;
|
|
52
|
+
Claude) echo 7 ;;
|
|
53
|
+
Qwen3) echo 8 ;;
|
|
54
|
+
GLM) echo 8 ;;
|
|
55
|
+
Grok) echo 7 ;;
|
|
56
|
+
DeepSeek) echo 9 ;;
|
|
57
|
+
MiniMax) echo 8 ;;
|
|
58
|
+
*) echo 5 ;;
|
|
59
|
+
esac
|
|
60
|
+
;;
|
|
61
|
+
ARCHITECTURE)
|
|
62
|
+
case "$consultant" in
|
|
63
|
+
Gemini) echo 10 ;;
|
|
64
|
+
Codex) echo 6 ;;
|
|
65
|
+
Mistral) echo 8 ;;
|
|
66
|
+
Kilo) echo 9 ;;
|
|
67
|
+
Cursor) echo 8 ;;
|
|
68
|
+
Aider) echo 6 ;;
|
|
69
|
+
Amp) echo 10 ;;
|
|
70
|
+
Kimi) echo 9 ;;
|
|
71
|
+
Claude) echo 9 ;;
|
|
72
|
+
Qwen3) echo 7 ;;
|
|
73
|
+
GLM) echo 7 ;;
|
|
74
|
+
Grok) echo 9 ;;
|
|
75
|
+
DeepSeek) echo 7 ;;
|
|
76
|
+
MiniMax) echo 7 ;;
|
|
77
|
+
*) echo 5 ;;
|
|
78
|
+
esac
|
|
79
|
+
;;
|
|
80
|
+
ALGORITHM)
|
|
81
|
+
case "$consultant" in
|
|
82
|
+
Gemini) echo 9 ;;
|
|
83
|
+
Codex) echo 8 ;;
|
|
84
|
+
Mistral) echo 7 ;;
|
|
85
|
+
Kilo) echo 8 ;;
|
|
86
|
+
Cursor) echo 7 ;;
|
|
87
|
+
Aider) echo 7 ;;
|
|
88
|
+
Amp) echo 7 ;;
|
|
89
|
+
Kimi) echo 8 ;;
|
|
90
|
+
Claude) echo 7 ;;
|
|
91
|
+
Qwen3) echo 9 ;;
|
|
92
|
+
GLM) echo 7 ;;
|
|
93
|
+
Grok) echo 8 ;;
|
|
94
|
+
DeepSeek) echo 10 ;;
|
|
95
|
+
MiniMax) echo 8 ;;
|
|
96
|
+
*) echo 5 ;;
|
|
97
|
+
esac
|
|
98
|
+
;;
|
|
99
|
+
SECURITY)
|
|
100
|
+
case "$consultant" in
|
|
101
|
+
Gemini) echo 9 ;;
|
|
102
|
+
Codex) echo 9 ;;
|
|
103
|
+
Mistral) echo 10 ;;
|
|
104
|
+
Kilo) echo 8 ;;
|
|
105
|
+
Cursor) echo 8 ;;
|
|
106
|
+
Aider) echo 7 ;;
|
|
107
|
+
Amp) echo 8 ;;
|
|
108
|
+
Kimi) echo 7 ;;
|
|
109
|
+
Claude) echo 8 ;;
|
|
110
|
+
Qwen3) echo 7 ;;
|
|
111
|
+
GLM) echo 8 ;;
|
|
112
|
+
Grok) echo 8 ;;
|
|
113
|
+
DeepSeek) echo 8 ;;
|
|
114
|
+
MiniMax) echo 7 ;;
|
|
115
|
+
*) echo 5 ;;
|
|
116
|
+
esac
|
|
117
|
+
;;
|
|
118
|
+
QUICK_SYNTAX)
|
|
119
|
+
case "$consultant" in
|
|
120
|
+
Gemini) echo 10 ;;
|
|
121
|
+
Codex) echo 8 ;;
|
|
122
|
+
Mistral) echo 5 ;;
|
|
123
|
+
Kilo) echo 6 ;;
|
|
124
|
+
Cursor) echo 7 ;;
|
|
125
|
+
Aider) echo 8 ;;
|
|
126
|
+
Amp) echo 5 ;;
|
|
127
|
+
Kimi) echo 5 ;;
|
|
128
|
+
Claude) echo 6 ;;
|
|
129
|
+
Qwen3) echo 7 ;;
|
|
130
|
+
GLM) echo 6 ;;
|
|
131
|
+
Grok) echo 5 ;;
|
|
132
|
+
DeepSeek) echo 9 ;;
|
|
133
|
+
MiniMax) echo 8 ;;
|
|
134
|
+
*) echo 5 ;;
|
|
135
|
+
esac
|
|
136
|
+
;;
|
|
137
|
+
DATABASE)
|
|
138
|
+
case "$consultant" in
|
|
139
|
+
Gemini) echo 8 ;;
|
|
140
|
+
Codex) echo 9 ;;
|
|
141
|
+
Mistral) echo 7 ;;
|
|
142
|
+
Kilo) echo 7 ;;
|
|
143
|
+
Cursor) echo 8 ;;
|
|
144
|
+
Aider) echo 7 ;;
|
|
145
|
+
Amp) echo 7 ;;
|
|
146
|
+
Kimi) echo 7 ;;
|
|
147
|
+
Claude) echo 7 ;;
|
|
148
|
+
Qwen3) echo 9 ;;
|
|
149
|
+
GLM) echo 7 ;;
|
|
150
|
+
Grok) echo 6 ;;
|
|
151
|
+
DeepSeek) echo 9 ;;
|
|
152
|
+
MiniMax) echo 8 ;;
|
|
153
|
+
*) echo 5 ;;
|
|
154
|
+
esac
|
|
155
|
+
;;
|
|
156
|
+
API_DESIGN)
|
|
157
|
+
case "$consultant" in
|
|
158
|
+
Gemini) echo 10 ;;
|
|
159
|
+
Codex) echo 9 ;;
|
|
160
|
+
Mistral) echo 7 ;;
|
|
161
|
+
Kilo) echo 8 ;;
|
|
162
|
+
Cursor) echo 9 ;;
|
|
163
|
+
Aider) echo 7 ;;
|
|
164
|
+
Amp) echo 9 ;;
|
|
165
|
+
Kimi) echo 8 ;;
|
|
166
|
+
Claude) echo 8 ;;
|
|
167
|
+
Qwen3) echo 7 ;;
|
|
168
|
+
GLM) echo 8 ;;
|
|
169
|
+
Grok) echo 8 ;;
|
|
170
|
+
DeepSeek) echo 8 ;;
|
|
171
|
+
MiniMax) echo 8 ;;
|
|
172
|
+
*) echo 5 ;;
|
|
173
|
+
esac
|
|
174
|
+
;;
|
|
175
|
+
TESTING)
|
|
176
|
+
case "$consultant" in
|
|
177
|
+
Gemini) echo 7 ;;
|
|
178
|
+
Codex) echo 10 ;;
|
|
179
|
+
Mistral) echo 9 ;;
|
|
180
|
+
Kilo) echo 7 ;;
|
|
181
|
+
Cursor) echo 9 ;;
|
|
182
|
+
Aider) echo 9 ;;
|
|
183
|
+
Amp) echo 8 ;;
|
|
184
|
+
Kimi) echo 6 ;;
|
|
185
|
+
Claude) echo 7 ;;
|
|
186
|
+
Qwen3) echo 8 ;;
|
|
187
|
+
GLM) echo 10 ;;
|
|
188
|
+
Grok) echo 7 ;;
|
|
189
|
+
DeepSeek) echo 8 ;;
|
|
190
|
+
MiniMax) echo 7 ;;
|
|
191
|
+
*) echo 5 ;;
|
|
192
|
+
esac
|
|
193
|
+
;;
|
|
194
|
+
*)
|
|
195
|
+
# GENERAL and unknown categories: all known consultants get score 8
|
|
196
|
+
case "$consultant" in
|
|
197
|
+
Gemini|Codex|Mistral|Kilo|Cursor|Aider|Amp|Kimi|Claude|Qwen3|GLM|Grok|DeepSeek|MiniMax) echo 8 ;;
|
|
198
|
+
*) echo 5 ;;
|
|
199
|
+
esac
|
|
200
|
+
;;
|
|
201
|
+
esac
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
# Select the best consultants for a category
|
|
205
|
+
# Usage: select_consultants <category> [min_affinity] [max_consultants]
|
|
206
|
+
# Returns: list of consultants sorted by affinity
|
|
207
|
+
select_consultants() {
|
|
208
|
+
local category="$1"
|
|
209
|
+
local min_affinity="${2:-7}"
|
|
210
|
+
local max_consultants="${3:-8}"
|
|
211
|
+
|
|
212
|
+
# Include all consultants (order matches ALL_CONSULTANTS in config.sh)
|
|
213
|
+
local consultants=("Gemini" "Codex" "Mistral" "Kilo" "Cursor" "Aider" "Amp" "Kimi" "Claude" "Qwen3" "GLM" "Grok" "DeepSeek" "MiniMax")
|
|
214
|
+
local selected=()
|
|
215
|
+
local scores=()
|
|
216
|
+
|
|
217
|
+
# Collect affinities
|
|
218
|
+
for c in "${consultants[@]}"; do
|
|
219
|
+
local score=$(get_affinity "$category" "$c")
|
|
220
|
+
if [[ $score -ge $min_affinity ]]; then
|
|
221
|
+
selected+=("$c")
|
|
222
|
+
scores+=("$score")
|
|
223
|
+
fi
|
|
224
|
+
done
|
|
225
|
+
|
|
226
|
+
# Sort by score (simple bubble sort)
|
|
227
|
+
local n=${#selected[@]}
|
|
228
|
+
for ((i=0; i<n-1; i++)); do
|
|
229
|
+
for ((j=0; j<n-i-1; j++)); do
|
|
230
|
+
if [[ ${scores[$j]} -lt ${scores[$((j+1))]} ]]; then
|
|
231
|
+
# Swap
|
|
232
|
+
local tmp="${selected[$j]}"
|
|
233
|
+
selected[$j]="${selected[$((j+1))]}"
|
|
234
|
+
selected[$((j+1))]="$tmp"
|
|
235
|
+
|
|
236
|
+
tmp="${scores[$j]}"
|
|
237
|
+
scores[$j]="${scores[$((j+1))]}"
|
|
238
|
+
scores[$((j+1))]="$tmp"
|
|
239
|
+
fi
|
|
240
|
+
done
|
|
241
|
+
done
|
|
242
|
+
|
|
243
|
+
# Limit to maximum requested
|
|
244
|
+
local count=0
|
|
245
|
+
for c in ${selected[@]+"${selected[@]}"}; do
|
|
246
|
+
if [[ $count -ge $max_consultants ]]; then
|
|
247
|
+
break
|
|
248
|
+
fi
|
|
249
|
+
echo "$c"
|
|
250
|
+
count=$((count + 1))
|
|
251
|
+
done
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
# Get the list of consultants as JSON
|
|
255
|
+
# Usage: get_selected_consultants_json <category> [min_affinity]
|
|
256
|
+
get_selected_consultants_json() {
|
|
257
|
+
local category="$1"
|
|
258
|
+
local min_affinity="${2:-7}"
|
|
259
|
+
|
|
260
|
+
local consultants=$(select_consultants "$category" "$min_affinity")
|
|
261
|
+
local json="["
|
|
262
|
+
local first=true
|
|
263
|
+
|
|
264
|
+
while IFS= read -r c; do
|
|
265
|
+
if [[ -n "$c" ]]; then
|
|
266
|
+
local score=$(get_affinity "$category" "$c")
|
|
267
|
+
if [[ "$first" == "true" ]]; then
|
|
268
|
+
first=false
|
|
269
|
+
else
|
|
270
|
+
json+=","
|
|
271
|
+
fi
|
|
272
|
+
json+="{\"consultant\":\"$c\",\"affinity\":$score}"
|
|
273
|
+
fi
|
|
274
|
+
done <<< "$consultants"
|
|
275
|
+
|
|
276
|
+
json+="]"
|
|
277
|
+
echo "$json"
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
# Check if a consultant is recommended for a category
|
|
281
|
+
# Usage: is_recommended <category> <consultant> [min_affinity]
|
|
282
|
+
is_recommended() {
|
|
283
|
+
local category="$1"
|
|
284
|
+
local consultant="$2"
|
|
285
|
+
local min_affinity="${3:-7}"
|
|
286
|
+
|
|
287
|
+
local score=$(get_affinity "$category" "$consultant")
|
|
288
|
+
if [[ $score -ge $min_affinity ]]; then
|
|
289
|
+
return 0
|
|
290
|
+
fi
|
|
291
|
+
return 1
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
# =============================================================================
|
|
295
|
+
# SMART ROUTING MODES
|
|
296
|
+
# =============================================================================
|
|
297
|
+
|
|
298
|
+
# Determine the routing mode based on the category
|
|
299
|
+
# Usage: get_routing_mode <category>
|
|
300
|
+
# Returns: full|selective|single
|
|
301
|
+
get_routing_mode() {
|
|
302
|
+
local category="$1"
|
|
303
|
+
|
|
304
|
+
case "$category" in
|
|
305
|
+
SECURITY)
|
|
306
|
+
# Security: all consultants (important)
|
|
307
|
+
echo "full"
|
|
308
|
+
;;
|
|
309
|
+
QUICK_SYNTAX)
|
|
310
|
+
# Syntax: just one needed
|
|
311
|
+
echo "single"
|
|
312
|
+
;;
|
|
313
|
+
CODE_REVIEW|BUG_DEBUG|ARCHITECTURE)
|
|
314
|
+
# Important: at least 3
|
|
315
|
+
echo "selective"
|
|
316
|
+
;;
|
|
317
|
+
*)
|
|
318
|
+
# Default: all
|
|
319
|
+
echo "full"
|
|
320
|
+
;;
|
|
321
|
+
esac
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
# Get the recommended number of consultants
|
|
325
|
+
# Usage: get_recommended_count <category>
|
|
326
|
+
get_recommended_count() {
|
|
327
|
+
local category="$1"
|
|
328
|
+
local mode=$(get_routing_mode "$category")
|
|
329
|
+
|
|
330
|
+
case "$mode" in
|
|
331
|
+
full)
|
|
332
|
+
echo 10 # All consultants (CLI + API)
|
|
333
|
+
;;
|
|
334
|
+
selective)
|
|
335
|
+
echo 5 # Subset based on affinity
|
|
336
|
+
;;
|
|
337
|
+
single)
|
|
338
|
+
echo 1
|
|
339
|
+
;;
|
|
340
|
+
*)
|
|
341
|
+
echo 10
|
|
342
|
+
;;
|
|
343
|
+
esac
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
# =============================================================================
|
|
347
|
+
# TIMEOUT ADJUSTMENTS
|
|
348
|
+
# =============================================================================
|
|
349
|
+
|
|
350
|
+
# Get recommended timeout for a category
|
|
351
|
+
# Usage: get_category_timeout <category>
|
|
352
|
+
get_category_timeout() {
|
|
353
|
+
local category="$1"
|
|
354
|
+
case "$category" in
|
|
355
|
+
QUICK_SYNTAX) echo 60 ;;
|
|
356
|
+
BUG_DEBUG) echo 180 ;;
|
|
357
|
+
ARCHITECTURE) echo 240 ;;
|
|
358
|
+
SECURITY) echo 240 ;;
|
|
359
|
+
CODE_REVIEW) echo 180 ;;
|
|
360
|
+
ALGORITHM) echo 180 ;;
|
|
361
|
+
DATABASE) echo 120 ;;
|
|
362
|
+
API_DESIGN) echo 180 ;;
|
|
363
|
+
TESTING) echo 120 ;;
|
|
364
|
+
GENERAL|*) echo 180 ;;
|
|
365
|
+
esac
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
# =============================================================================
|
|
369
|
+
# COST-AWARE ROUTING (v2.3)
|
|
370
|
+
# =============================================================================
|
|
371
|
+
|
|
372
|
+
# Ensure costs.sh is sourced (lazy loading helper)
|
|
373
|
+
_ensure_costs_sourced() {
|
|
374
|
+
if ! type get_economic_model &>/dev/null; then
|
|
375
|
+
local script_dir
|
|
376
|
+
script_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
377
|
+
source "$script_dir/costs.sh" 2>/dev/null || true
|
|
378
|
+
fi
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
# Select consultants based on cost efficiency
|
|
382
|
+
# Usage: select_consultants_cost_aware <category> <complexity> [min_affinity]
|
|
383
|
+
# Returns: list of consultants optimized for cost/quality balance
|
|
384
|
+
select_consultants_cost_aware() {
|
|
385
|
+
local category="$1"
|
|
386
|
+
local complexity="${2:-5}"
|
|
387
|
+
local min_affinity="${3:-7}"
|
|
388
|
+
|
|
389
|
+
# Check if cost-aware routing is enabled
|
|
390
|
+
if [[ "${ENABLE_COST_AWARE_ROUTING:-false}" != "true" ]]; then
|
|
391
|
+
# Fall back to standard selection
|
|
392
|
+
select_consultants "$category" "$min_affinity"
|
|
393
|
+
return
|
|
394
|
+
fi
|
|
395
|
+
|
|
396
|
+
_ensure_costs_sourced
|
|
397
|
+
|
|
398
|
+
local simple_threshold="${COMPLEXITY_THRESHOLD_SIMPLE:-3}"
|
|
399
|
+
local medium_threshold="${COMPLEXITY_THRESHOLD_MEDIUM:-6}"
|
|
400
|
+
|
|
401
|
+
# Simple queries: only economic models, fewer consultants
|
|
402
|
+
if [[ $complexity -le $simple_threshold ]]; then
|
|
403
|
+
# For simple queries, use only 2 consultants with economic models
|
|
404
|
+
select_consultants "$category" "$min_affinity" 2
|
|
405
|
+
return
|
|
406
|
+
fi
|
|
407
|
+
|
|
408
|
+
# Medium complexity: balanced selection
|
|
409
|
+
if [[ $complexity -le $medium_threshold ]]; then
|
|
410
|
+
# Use standard selection but limit to 3-4 consultants
|
|
411
|
+
select_consultants "$category" "$min_affinity" 4
|
|
412
|
+
return
|
|
413
|
+
fi
|
|
414
|
+
|
|
415
|
+
# Complex queries: full selection
|
|
416
|
+
select_consultants "$category" "$min_affinity"
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
# Get model override for cost-aware routing
|
|
420
|
+
# Usage: get_cost_aware_model <consultant> <complexity>
|
|
421
|
+
# Returns: model name to use, or empty for default
|
|
422
|
+
get_cost_aware_model() {
|
|
423
|
+
local consultant="$1"
|
|
424
|
+
local complexity="${2:-5}"
|
|
425
|
+
|
|
426
|
+
# Check if cost-aware routing is enabled
|
|
427
|
+
if [[ "${ENABLE_COST_AWARE_ROUTING:-false}" != "true" ]]; then
|
|
428
|
+
echo ""
|
|
429
|
+
return
|
|
430
|
+
fi
|
|
431
|
+
|
|
432
|
+
# Check if we should use economic models for simple queries
|
|
433
|
+
if [[ "${USE_ECONOMIC_MODELS_FOR_SIMPLE:-true}" != "true" ]]; then
|
|
434
|
+
echo ""
|
|
435
|
+
return
|
|
436
|
+
fi
|
|
437
|
+
|
|
438
|
+
local simple_threshold="${COMPLEXITY_THRESHOLD_SIMPLE:-3}"
|
|
439
|
+
|
|
440
|
+
# Simple queries: use economic model
|
|
441
|
+
if [[ $complexity -le $simple_threshold ]]; then
|
|
442
|
+
_ensure_costs_sourced
|
|
443
|
+
local economic_model
|
|
444
|
+
economic_model=$(get_economic_model "$consultant" 2>/dev/null || echo "")
|
|
445
|
+
echo "$economic_model"
|
|
446
|
+
return
|
|
447
|
+
fi
|
|
448
|
+
|
|
449
|
+
# Complex queries: use default model
|
|
450
|
+
echo ""
|
|
451
|
+
}
|
|
452
|
+
|
|
453
|
+
# Check if cost-aware routing is enabled
|
|
454
|
+
# Usage: is_cost_aware_routing_enabled
|
|
455
|
+
is_cost_aware_routing_enabled() {
|
|
456
|
+
[[ "${ENABLE_COST_AWARE_ROUTING:-false}" == "true" ]]
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
# Get routing summary for logging
|
|
460
|
+
# Usage: get_routing_summary <category> <complexity> <num_consultants>
|
|
461
|
+
get_routing_summary() {
|
|
462
|
+
local category="$1"
|
|
463
|
+
local complexity="${2:-5}"
|
|
464
|
+
local num_consultants="${3:-5}"
|
|
465
|
+
|
|
466
|
+
local mode="standard"
|
|
467
|
+
if is_cost_aware_routing_enabled; then
|
|
468
|
+
local simple_threshold="${COMPLEXITY_THRESHOLD_SIMPLE:-3}"
|
|
469
|
+
local medium_threshold="${COMPLEXITY_THRESHOLD_MEDIUM:-6}"
|
|
470
|
+
|
|
471
|
+
if [[ $complexity -le $simple_threshold ]]; then
|
|
472
|
+
mode="economic"
|
|
473
|
+
elif [[ $complexity -le $medium_threshold ]]; then
|
|
474
|
+
mode="balanced"
|
|
475
|
+
else
|
|
476
|
+
mode="comprehensive"
|
|
477
|
+
fi
|
|
478
|
+
fi
|
|
479
|
+
|
|
480
|
+
echo "{\"category\":\"$category\",\"complexity\":$complexity,\"mode\":\"$mode\",\"consultants\":$num_consultants}"
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
# =============================================================================
|
|
484
|
+
# FALLBACK ESCALATION (v2.3 Quality Review)
|
|
485
|
+
# =============================================================================
|
|
486
|
+
|
|
487
|
+
# Fallback escalation threshold - escalate to premium if confidence below this
|
|
488
|
+
FALLBACK_CONFIDENCE_THRESHOLD="${FALLBACK_CONFIDENCE_THRESHOLD:-7}"
|
|
489
|
+
|
|
490
|
+
# Check if response needs escalation based on confidence
|
|
491
|
+
# Usage: needs_escalation <response_file>
|
|
492
|
+
# Returns: 0 if escalation needed, 1 otherwise
|
|
493
|
+
needs_escalation() {
|
|
494
|
+
local response_file="$1"
|
|
495
|
+
|
|
496
|
+
if [[ ! -f "$response_file" || ! -s "$response_file" ]]; then
|
|
497
|
+
return 0 # No response = needs escalation
|
|
498
|
+
fi
|
|
499
|
+
|
|
500
|
+
local confidence
|
|
501
|
+
confidence=$(jq -r '.confidence.score // 5' "$response_file" 2>/dev/null)
|
|
502
|
+
|
|
503
|
+
if [[ ! "$confidence" =~ ^[0-9]+$ ]]; then
|
|
504
|
+
confidence=5
|
|
505
|
+
fi
|
|
506
|
+
|
|
507
|
+
local threshold="${FALLBACK_CONFIDENCE_THRESHOLD:-7}"
|
|
508
|
+
|
|
509
|
+
if [[ $confidence -lt $threshold ]]; then
|
|
510
|
+
return 0 # Needs escalation
|
|
511
|
+
fi
|
|
512
|
+
|
|
513
|
+
return 1 # No escalation needed
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
# Get premium model for escalation
|
|
517
|
+
# Delegates to get_model_for_tier() in config.sh (single source of truth)
|
|
518
|
+
# Usage: get_premium_model <consultant>
|
|
519
|
+
get_premium_model() {
|
|
520
|
+
local consultant="$1"
|
|
521
|
+
if type get_model_for_tier &>/dev/null; then
|
|
522
|
+
get_model_for_tier "$consultant" "premium"
|
|
523
|
+
else
|
|
524
|
+
echo ""
|
|
525
|
+
fi
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
# Check if escalation is enabled
|
|
529
|
+
# Usage: is_escalation_enabled
|
|
530
|
+
is_escalation_enabled() {
|
|
531
|
+
# Escalation is enabled when cost-aware routing is on
|
|
532
|
+
[[ "${ENABLE_COST_AWARE_ROUTING:-false}" == "true" ]]
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
# Get escalation summary for a response
|
|
536
|
+
# Usage: get_escalation_summary <response_file> <consultant>
|
|
537
|
+
get_escalation_summary() {
|
|
538
|
+
local response_file="$1"
|
|
539
|
+
local consultant="$2"
|
|
540
|
+
|
|
541
|
+
local needs_it="false"
|
|
542
|
+
local confidence=0
|
|
543
|
+
local threshold="${FALLBACK_CONFIDENCE_THRESHOLD:-7}"
|
|
544
|
+
|
|
545
|
+
if [[ -f "$response_file" && -s "$response_file" ]]; then
|
|
546
|
+
confidence=$(jq -r '.confidence.score // 5' "$response_file" 2>/dev/null)
|
|
547
|
+
[[ ! "$confidence" =~ ^[0-9]+$ ]] && confidence=5
|
|
548
|
+
fi
|
|
549
|
+
|
|
550
|
+
if [[ $confidence -lt $threshold ]]; then
|
|
551
|
+
needs_it="true"
|
|
552
|
+
fi
|
|
553
|
+
|
|
554
|
+
local premium_model
|
|
555
|
+
premium_model=$(get_premium_model "$consultant")
|
|
556
|
+
|
|
557
|
+
cat << EOF
|
|
558
|
+
{
|
|
559
|
+
"consultant": "$consultant",
|
|
560
|
+
"confidence": $confidence,
|
|
561
|
+
"threshold": $threshold,
|
|
562
|
+
"needs_escalation": $needs_it,
|
|
563
|
+
"premium_model": "$premium_model"
|
|
564
|
+
}
|
|
565
|
+
EOF
|
|
566
|
+
}
|