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,1093 @@
|
|
|
1
|
+
#!/bin/bash
|
|
2
|
+
# configure.sh - Interactive configuration wizard for AI Consultants v2.0
|
|
3
|
+
#
|
|
4
|
+
# Detects available CLI agents, allows selection and API configuration,
|
|
5
|
+
# ensures minimum 2 agents are enabled, and saves configuration to .env
|
|
6
|
+
#
|
|
7
|
+
# Usage: ./configure.sh [--non-interactive] [--output FILE]
|
|
8
|
+
#
|
|
9
|
+
# Options:
|
|
10
|
+
# --non-interactive Skip prompts, detect and auto-enable available agents
|
|
11
|
+
# --output FILE Output file (default: .env in project root)
|
|
12
|
+
|
|
13
|
+
set -euo pipefail
|
|
14
|
+
|
|
15
|
+
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
16
|
+
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
17
|
+
|
|
18
|
+
# Load common utilities if available
|
|
19
|
+
if [[ -f "$SCRIPT_DIR/lib/common.sh" ]]; then
|
|
20
|
+
source "$SCRIPT_DIR/lib/common.sh"
|
|
21
|
+
else
|
|
22
|
+
# Fallback logging functions
|
|
23
|
+
log_info() { echo "[INFO] $*"; }
|
|
24
|
+
log_success() { echo "[OK] $*"; }
|
|
25
|
+
log_warn() { echo "[WARN] $*"; }
|
|
26
|
+
log_error() { echo "[ERROR] $*" >&2; }
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
# Load personas library for persona catalog
|
|
30
|
+
if [[ -f "$SCRIPT_DIR/lib/personas.sh" ]]; then
|
|
31
|
+
source "$SCRIPT_DIR/lib/personas.sh"
|
|
32
|
+
fi
|
|
33
|
+
|
|
34
|
+
# =============================================================================
|
|
35
|
+
# CONFIGURATION
|
|
36
|
+
# =============================================================================
|
|
37
|
+
|
|
38
|
+
NON_INTERACTIVE=false
|
|
39
|
+
OUTPUT_FILE="$PROJECT_ROOT/.env"
|
|
40
|
+
|
|
41
|
+
# CLI Agents: name|command|install_hint|persona
|
|
42
|
+
CLI_AGENT_NAMES=("Gemini" "Codex" "Mistral" "Kilo" "Cursor" "Aider")
|
|
43
|
+
CLI_AGENT_CMDS=("gemini" "codex" "vibe" "kilocode" "agent" "aider")
|
|
44
|
+
CLI_AGENT_HINTS=("npm install -g @google/gemini-cli" "npm install -g @openai/codex" "pip install mistral-vibe" "npm install -g @kilocode/cli" "See: https://cursor.com/" "pip install aider-chat")
|
|
45
|
+
CLI_AGENT_PERSONAS=("The Architect" "The Pragmatist" "The Devil's Advocate" "The Innovator" "The Integrator" "The Pair Programmer")
|
|
46
|
+
|
|
47
|
+
# API Agents: name|key_var|api_url|model|persona
|
|
48
|
+
API_AGENT_NAMES=("Qwen3" "GLM" "Grok" "DeepSeek")
|
|
49
|
+
API_AGENT_KEY_VARS=("QWEN3_API_KEY" "GLM_API_KEY" "GROK_API_KEY" "DEEPSEEK_API_KEY")
|
|
50
|
+
API_AGENT_URLS=("https://dashscope.aliyuncs.com/api/v1/services/aigc/text-generation/generation" "https://open.bigmodel.cn/api/paas/v4/chat/completions" "https://api.x.ai/v1/chat/completions" "https://api.deepseek.com/v1/chat/completions")
|
|
51
|
+
API_AGENT_MODELS=("qwen-max" "glm-4" "grok-4-1-fast-reasoning" "deepseek-reasoner")
|
|
52
|
+
API_AGENT_PERSONAS=("The Analyst" "The Methodologist" "The Provocateur" "The Code Specialist")
|
|
53
|
+
|
|
54
|
+
# State arrays (parallel to CLI_AGENT_NAMES)
|
|
55
|
+
CLI_DETECTED=() # "installed" or "missing"
|
|
56
|
+
CLI_ENABLED=() # "true" or "false"
|
|
57
|
+
|
|
58
|
+
# State arrays (parallel to API_AGENT_NAMES)
|
|
59
|
+
API_ENABLED=() # "true" or "false"
|
|
60
|
+
API_KEYS_VALUES=() # actual API key values
|
|
61
|
+
|
|
62
|
+
# Custom CLI agents
|
|
63
|
+
CUSTOM_NAMES=()
|
|
64
|
+
CUSTOM_CMDS=()
|
|
65
|
+
CUSTOM_PERSONAS=()
|
|
66
|
+
|
|
67
|
+
# Custom API agents
|
|
68
|
+
CUSTOM_API_NAMES=()
|
|
69
|
+
CUSTOM_API_URLS=()
|
|
70
|
+
CUSTOM_API_KEYS=()
|
|
71
|
+
CUSTOM_API_MODELS=()
|
|
72
|
+
CUSTOM_API_PERSONAS=()
|
|
73
|
+
CUSTOM_API_FORMATS=() # "openai" or "qwen"
|
|
74
|
+
|
|
75
|
+
# Persona assignments (maps agent name to persona ID)
|
|
76
|
+
# Parallel arrays for CLI and API agents
|
|
77
|
+
CLI_PERSONA_IDS=() # persona ID for each CLI agent
|
|
78
|
+
API_PERSONA_IDS=() # persona ID for each API agent
|
|
79
|
+
CUSTOM_PERSONA_IDS=() # persona ID for each custom CLI agent
|
|
80
|
+
CUSTOM_API_PERSONA_IDS=() # persona ID for each custom API agent
|
|
81
|
+
|
|
82
|
+
# Initialize state arrays
|
|
83
|
+
# Default persona IDs: 1=Architect, 2=Pragmatist, 3=Devil's Advocate, 4=Innovator, 5=Integrator, 16=Pair Programmer
|
|
84
|
+
CLI_DEFAULT_PERSONA_IDS=(1 2 3 4 5 16)
|
|
85
|
+
for i in "${!CLI_AGENT_NAMES[@]}"; do
|
|
86
|
+
CLI_DETECTED+=("missing")
|
|
87
|
+
CLI_ENABLED+=("false")
|
|
88
|
+
CLI_PERSONA_IDS+=("${CLI_DEFAULT_PERSONA_IDS[$i]}")
|
|
89
|
+
done
|
|
90
|
+
|
|
91
|
+
# Default persona IDs: 6=Analyst, 7=Methodologist, 8=Provocateur, 17=Code Specialist
|
|
92
|
+
API_DEFAULT_PERSONA_IDS=(6 7 8 17)
|
|
93
|
+
for i in "${!API_AGENT_NAMES[@]}"; do
|
|
94
|
+
API_ENABLED+=("false")
|
|
95
|
+
API_KEYS_VALUES+=("")
|
|
96
|
+
API_PERSONA_IDS+=("${API_DEFAULT_PERSONA_IDS[$i]}")
|
|
97
|
+
done
|
|
98
|
+
|
|
99
|
+
# =============================================================================
|
|
100
|
+
# ARGUMENT PARSING
|
|
101
|
+
# =============================================================================
|
|
102
|
+
|
|
103
|
+
while [[ $# -gt 0 ]]; do
|
|
104
|
+
case "$1" in
|
|
105
|
+
--non-interactive)
|
|
106
|
+
NON_INTERACTIVE=true
|
|
107
|
+
shift
|
|
108
|
+
;;
|
|
109
|
+
--output)
|
|
110
|
+
OUTPUT_FILE="$2"
|
|
111
|
+
shift 2
|
|
112
|
+
;;
|
|
113
|
+
-h|--help)
|
|
114
|
+
echo "Usage: $0 [--non-interactive] [--output FILE]"
|
|
115
|
+
echo ""
|
|
116
|
+
echo "Interactive configuration wizard for AI Consultants."
|
|
117
|
+
echo ""
|
|
118
|
+
echo "Options:"
|
|
119
|
+
echo " --non-interactive Auto-detect and enable available agents"
|
|
120
|
+
echo " --output FILE Output file (default: .env)"
|
|
121
|
+
exit 0
|
|
122
|
+
;;
|
|
123
|
+
*)
|
|
124
|
+
shift
|
|
125
|
+
;;
|
|
126
|
+
esac
|
|
127
|
+
done
|
|
128
|
+
|
|
129
|
+
# =============================================================================
|
|
130
|
+
# UTILITIES
|
|
131
|
+
# =============================================================================
|
|
132
|
+
|
|
133
|
+
# Normalize name to uppercase (removes spaces and hyphens)
|
|
134
|
+
to_upper() {
|
|
135
|
+
echo "$1" | tr '[:lower:]' '[:upper:]' | tr -d ' -'
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
# Print a header box
|
|
139
|
+
print_header() {
|
|
140
|
+
local title="$1"
|
|
141
|
+
local width=60
|
|
142
|
+
echo ""
|
|
143
|
+
printf '╔'; printf '═%.0s' $(seq 1 $width); printf '╗\n'
|
|
144
|
+
printf "║ %-$((width-1))s║\n" "$title"
|
|
145
|
+
printf '╚'; printf '═%.0s' $(seq 1 $width); printf '╝\n'
|
|
146
|
+
echo ""
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
# Print a section divider
|
|
150
|
+
print_section() {
|
|
151
|
+
local title="$1"
|
|
152
|
+
echo ""
|
|
153
|
+
echo "─── $title ───"
|
|
154
|
+
echo ""
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
# Emit a section header to .env file
|
|
158
|
+
# Usage: emit_env_section "SECTION TITLE" [file]
|
|
159
|
+
emit_env_section() {
|
|
160
|
+
local title="$1"
|
|
161
|
+
local file="${2:-$OUTPUT_FILE}"
|
|
162
|
+
{
|
|
163
|
+
echo ""
|
|
164
|
+
echo "# ============================================================================="
|
|
165
|
+
echo "# $title"
|
|
166
|
+
echo "# ============================================================================="
|
|
167
|
+
echo ""
|
|
168
|
+
} >> "$file"
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
# Prompt yes/no
|
|
172
|
+
confirm() {
|
|
173
|
+
local prompt="$1"
|
|
174
|
+
local default="${2:-n}"
|
|
175
|
+
|
|
176
|
+
if [[ "$NON_INTERACTIVE" == "true" ]]; then
|
|
177
|
+
[[ "$default" == "y" ]] && return 0 || return 1
|
|
178
|
+
fi
|
|
179
|
+
|
|
180
|
+
local yn
|
|
181
|
+
if [[ "$default" == "y" ]]; then
|
|
182
|
+
read -r -p "$prompt [Y/n]: " yn
|
|
183
|
+
yn=${yn:-y}
|
|
184
|
+
else
|
|
185
|
+
read -r -p "$prompt [y/N]: " yn
|
|
186
|
+
yn=${yn:-n}
|
|
187
|
+
fi
|
|
188
|
+
|
|
189
|
+
[[ "$yn" =~ ^[Yy] ]] && return 0 || return 1
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
# Prompt for input with default
|
|
193
|
+
prompt_input() {
|
|
194
|
+
local prompt="$1"
|
|
195
|
+
local default="${2:-}"
|
|
196
|
+
|
|
197
|
+
if [[ "$NON_INTERACTIVE" == "true" ]]; then
|
|
198
|
+
REPLY="$default"
|
|
199
|
+
return
|
|
200
|
+
fi
|
|
201
|
+
|
|
202
|
+
if [[ -n "$default" ]]; then
|
|
203
|
+
read -r -p "$prompt [$default]: " REPLY
|
|
204
|
+
REPLY=${REPLY:-$default}
|
|
205
|
+
else
|
|
206
|
+
read -r -p "$prompt: " REPLY
|
|
207
|
+
fi
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
# Prompt for secret (no echo)
|
|
211
|
+
prompt_secret() {
|
|
212
|
+
local prompt="$1"
|
|
213
|
+
|
|
214
|
+
if [[ "$NON_INTERACTIVE" == "true" ]]; then
|
|
215
|
+
REPLY=""
|
|
216
|
+
return
|
|
217
|
+
fi
|
|
218
|
+
|
|
219
|
+
read -r -s -p "$prompt: " REPLY
|
|
220
|
+
echo ""
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
# =============================================================================
|
|
224
|
+
# CLI AGENT DETECTION
|
|
225
|
+
# =============================================================================
|
|
226
|
+
|
|
227
|
+
detect_cli_agents() {
|
|
228
|
+
print_section "Detecting CLI Agents"
|
|
229
|
+
|
|
230
|
+
local found=0
|
|
231
|
+
for i in "${!CLI_AGENT_NAMES[@]}"; do
|
|
232
|
+
local name="${CLI_AGENT_NAMES[$i]}"
|
|
233
|
+
local cmd="${CLI_AGENT_CMDS[$i]}"
|
|
234
|
+
local persona="${CLI_AGENT_PERSONAS[$i]}"
|
|
235
|
+
|
|
236
|
+
if command -v "$cmd" &> /dev/null; then
|
|
237
|
+
CLI_DETECTED[$i]="installed"
|
|
238
|
+
local version
|
|
239
|
+
version=$("$cmd" --version 2>/dev/null | head -1 || echo "detected")
|
|
240
|
+
echo " [FOUND] $name ($persona) - $cmd"
|
|
241
|
+
((found++)) || true
|
|
242
|
+
else
|
|
243
|
+
CLI_DETECTED[$i]="missing"
|
|
244
|
+
echo " [-----] $name ($persona) - not found"
|
|
245
|
+
fi
|
|
246
|
+
done
|
|
247
|
+
|
|
248
|
+
echo ""
|
|
249
|
+
echo "Found $found CLI agent(s) installed."
|
|
250
|
+
return 0
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
# =============================================================================
|
|
254
|
+
# CLI AGENT SELECTION
|
|
255
|
+
# =============================================================================
|
|
256
|
+
|
|
257
|
+
select_cli_agents() {
|
|
258
|
+
print_section "Select CLI Agents to Enable"
|
|
259
|
+
|
|
260
|
+
if [[ "$NON_INTERACTIVE" == "true" ]]; then
|
|
261
|
+
# Auto-enable all detected CLI agents
|
|
262
|
+
for i in "${!CLI_AGENT_NAMES[@]}"; do
|
|
263
|
+
if [[ "${CLI_DETECTED[$i]}" == "installed" ]]; then
|
|
264
|
+
CLI_ENABLED[$i]="true"
|
|
265
|
+
log_info "Auto-enabled: ${CLI_AGENT_NAMES[$i]}"
|
|
266
|
+
fi
|
|
267
|
+
done
|
|
268
|
+
return
|
|
269
|
+
fi
|
|
270
|
+
|
|
271
|
+
# Build list of detected agents
|
|
272
|
+
local detected_indices=()
|
|
273
|
+
for i in "${!CLI_AGENT_NAMES[@]}"; do
|
|
274
|
+
if [[ "${CLI_DETECTED[$i]}" == "installed" ]]; then
|
|
275
|
+
detected_indices+=("$i")
|
|
276
|
+
fi
|
|
277
|
+
done
|
|
278
|
+
|
|
279
|
+
if [[ ${#detected_indices[@]} -eq 0 ]]; then
|
|
280
|
+
echo " No CLI agents detected. You can add custom ones or use API agents."
|
|
281
|
+
echo ""
|
|
282
|
+
if confirm "Add a custom CLI agent?"; then
|
|
283
|
+
add_custom_cli_agent
|
|
284
|
+
fi
|
|
285
|
+
return
|
|
286
|
+
fi
|
|
287
|
+
|
|
288
|
+
# Pre-select all detected agents
|
|
289
|
+
for i in "${detected_indices[@]}"; do
|
|
290
|
+
CLI_ENABLED[$i]="true"
|
|
291
|
+
done
|
|
292
|
+
|
|
293
|
+
local done_selecting=false
|
|
294
|
+
while [[ "$done_selecting" != "true" ]]; do
|
|
295
|
+
echo ""
|
|
296
|
+
echo "Available CLI agents (x = selected):"
|
|
297
|
+
local menu_idx=1
|
|
298
|
+
for i in "${detected_indices[@]}"; do
|
|
299
|
+
local name="${CLI_AGENT_NAMES[$i]}"
|
|
300
|
+
local persona="${CLI_AGENT_PERSONAS[$i]}"
|
|
301
|
+
local mark=" "
|
|
302
|
+
[[ "${CLI_ENABLED[$i]}" == "true" ]] && mark="x"
|
|
303
|
+
echo " $menu_idx) [$mark] $name ($persona)"
|
|
304
|
+
((menu_idx++)) || true
|
|
305
|
+
done
|
|
306
|
+
echo " a) Select all"
|
|
307
|
+
echo " n) Select none"
|
|
308
|
+
echo " c) Add custom CLI agent"
|
|
309
|
+
echo " d) Done"
|
|
310
|
+
echo ""
|
|
311
|
+
|
|
312
|
+
read -r -p "Choice: " choice
|
|
313
|
+
|
|
314
|
+
case "$choice" in
|
|
315
|
+
[1-9]|[1-9][0-9])
|
|
316
|
+
if [[ $choice -le ${#detected_indices[@]} ]]; then
|
|
317
|
+
local idx="${detected_indices[$((choice-1))]}"
|
|
318
|
+
if [[ "${CLI_ENABLED[$idx]}" == "true" ]]; then
|
|
319
|
+
CLI_ENABLED[$idx]="false"
|
|
320
|
+
else
|
|
321
|
+
CLI_ENABLED[$idx]="true"
|
|
322
|
+
fi
|
|
323
|
+
fi
|
|
324
|
+
;;
|
|
325
|
+
a|A)
|
|
326
|
+
for i in "${detected_indices[@]}"; do
|
|
327
|
+
CLI_ENABLED[$i]="true"
|
|
328
|
+
done
|
|
329
|
+
;;
|
|
330
|
+
n|N)
|
|
331
|
+
for i in "${detected_indices[@]}"; do
|
|
332
|
+
CLI_ENABLED[$i]="false"
|
|
333
|
+
done
|
|
334
|
+
;;
|
|
335
|
+
c|C)
|
|
336
|
+
add_custom_cli_agent
|
|
337
|
+
;;
|
|
338
|
+
d|D)
|
|
339
|
+
done_selecting=true
|
|
340
|
+
;;
|
|
341
|
+
esac
|
|
342
|
+
done
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
# =============================================================================
|
|
346
|
+
# CUSTOM CLI AGENT
|
|
347
|
+
# =============================================================================
|
|
348
|
+
|
|
349
|
+
add_custom_cli_agent() {
|
|
350
|
+
print_section "Add Custom CLI Agent"
|
|
351
|
+
|
|
352
|
+
prompt_input "Agent name (e.g., 'Claude', 'GPT4All')" ""
|
|
353
|
+
local name="$REPLY"
|
|
354
|
+
[[ -z "$name" ]] && return
|
|
355
|
+
|
|
356
|
+
prompt_input "Command to execute (e.g., 'claude', 'gpt4all')" ""
|
|
357
|
+
local cmd="$REPLY"
|
|
358
|
+
[[ -z "$cmd" ]] && return
|
|
359
|
+
|
|
360
|
+
# Check if command exists
|
|
361
|
+
if ! command -v "$cmd" &> /dev/null; then
|
|
362
|
+
log_warn "Command '$cmd' not found in PATH."
|
|
363
|
+
if ! confirm "Add anyway?"; then
|
|
364
|
+
return
|
|
365
|
+
fi
|
|
366
|
+
fi
|
|
367
|
+
|
|
368
|
+
prompt_input "Persona/Role description" "Custom Agent"
|
|
369
|
+
local persona="$REPLY"
|
|
370
|
+
|
|
371
|
+
# Store custom agent
|
|
372
|
+
CUSTOM_NAMES+=("$name")
|
|
373
|
+
CUSTOM_CMDS+=("$cmd")
|
|
374
|
+
CUSTOM_PERSONAS+=("$persona")
|
|
375
|
+
|
|
376
|
+
log_success "Added custom CLI agent: $name ($cmd)"
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
# =============================================================================
|
|
380
|
+
# CUSTOM API AGENT
|
|
381
|
+
# =============================================================================
|
|
382
|
+
|
|
383
|
+
add_custom_api_agent() {
|
|
384
|
+
print_section "Add Custom API Agent"
|
|
385
|
+
|
|
386
|
+
echo "Add any OpenAI-compatible or custom API endpoint."
|
|
387
|
+
echo ""
|
|
388
|
+
|
|
389
|
+
prompt_input "Agent name (e.g., 'OpenRouter', 'Groq', 'Together')" ""
|
|
390
|
+
local name="$REPLY"
|
|
391
|
+
[[ -z "$name" ]] && return
|
|
392
|
+
|
|
393
|
+
prompt_input "API endpoint URL (e.g., https://api.openrouter.ai/api/v1/chat/completions)" ""
|
|
394
|
+
local url="$REPLY"
|
|
395
|
+
[[ -z "$url" ]] && return
|
|
396
|
+
|
|
397
|
+
prompt_secret "API key"
|
|
398
|
+
local key="$REPLY"
|
|
399
|
+
[[ -z "$key" ]] && { log_warn "API key required"; return; }
|
|
400
|
+
|
|
401
|
+
prompt_input "Model name (e.g., 'gpt-4', 'anthropic/claude-3')" "gpt-4"
|
|
402
|
+
local model="$REPLY"
|
|
403
|
+
|
|
404
|
+
prompt_input "Persona/Role description" "External API Consultant"
|
|
405
|
+
local persona="$REPLY"
|
|
406
|
+
|
|
407
|
+
echo ""
|
|
408
|
+
echo "Response format:"
|
|
409
|
+
echo " 1) OpenAI-compatible (most APIs - recommended)"
|
|
410
|
+
echo " 2) Qwen/DashScope format"
|
|
411
|
+
read -r -p "Choice [1]: " format_choice
|
|
412
|
+
local format="openai"
|
|
413
|
+
[[ "$format_choice" == "2" ]] && format="qwen"
|
|
414
|
+
|
|
415
|
+
# Store custom API agent
|
|
416
|
+
CUSTOM_API_NAMES+=("$name")
|
|
417
|
+
CUSTOM_API_URLS+=("$url")
|
|
418
|
+
CUSTOM_API_KEYS+=("$key")
|
|
419
|
+
CUSTOM_API_MODELS+=("$model")
|
|
420
|
+
CUSTOM_API_PERSONAS+=("$persona")
|
|
421
|
+
CUSTOM_API_FORMATS+=("$format")
|
|
422
|
+
|
|
423
|
+
log_success "Added custom API agent: $name ($url)"
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
# =============================================================================
|
|
427
|
+
# API AGENT CONFIGURATION
|
|
428
|
+
# =============================================================================
|
|
429
|
+
|
|
430
|
+
configure_api_agents() {
|
|
431
|
+
print_section "Configure API-Based Agents"
|
|
432
|
+
|
|
433
|
+
if [[ "$NON_INTERACTIVE" == "true" ]]; then
|
|
434
|
+
# Auto-enable API agents with existing keys
|
|
435
|
+
for i in "${!API_AGENT_NAMES[@]}"; do
|
|
436
|
+
local key_var="${API_AGENT_KEY_VARS[$i]}"
|
|
437
|
+
local existing_key="${!key_var:-}"
|
|
438
|
+
if [[ -n "$existing_key" ]]; then
|
|
439
|
+
API_ENABLED[$i]="true"
|
|
440
|
+
API_KEYS_VALUES[$i]="$existing_key"
|
|
441
|
+
log_info "Auto-enabled: ${API_AGENT_NAMES[$i]} (API key found)"
|
|
442
|
+
fi
|
|
443
|
+
done
|
|
444
|
+
# Also check for custom API agents via naming convention
|
|
445
|
+
# (e.g., CUSTOMAGENT_API_KEY, CUSTOMAGENT_API_URL, ENABLE_CUSTOMAGENT=true)
|
|
446
|
+
return
|
|
447
|
+
fi
|
|
448
|
+
|
|
449
|
+
echo "API-based agents require API keys but no CLI installation."
|
|
450
|
+
echo ""
|
|
451
|
+
echo "Predefined API agents:"
|
|
452
|
+
for i in "${!API_AGENT_NAMES[@]}"; do
|
|
453
|
+
local name="${API_AGENT_NAMES[$i]}"
|
|
454
|
+
local model="${API_AGENT_MODELS[$i]}"
|
|
455
|
+
local persona="${API_AGENT_PERSONAS[$i]}"
|
|
456
|
+
echo " - $name ($persona) - Model: $model"
|
|
457
|
+
done
|
|
458
|
+
echo ""
|
|
459
|
+
echo "You can also add custom API agents (OpenRouter, Groq, Together, etc.)"
|
|
460
|
+
echo ""
|
|
461
|
+
|
|
462
|
+
if ! confirm "Configure API-based agents?"; then
|
|
463
|
+
return
|
|
464
|
+
fi
|
|
465
|
+
|
|
466
|
+
local done_api_config=false
|
|
467
|
+
while [[ "$done_api_config" != "true" ]]; do
|
|
468
|
+
echo ""
|
|
469
|
+
echo "API Agent Configuration:"
|
|
470
|
+
echo " 1) Configure predefined agents (Qwen3, GLM, Grok)"
|
|
471
|
+
echo " 2) Add custom API agent"
|
|
472
|
+
echo " 3) Done with API configuration"
|
|
473
|
+
echo ""
|
|
474
|
+
|
|
475
|
+
read -r -p "Choice [1-3]: " api_choice
|
|
476
|
+
|
|
477
|
+
case "$api_choice" in
|
|
478
|
+
1)
|
|
479
|
+
_configure_predefined_api_agents
|
|
480
|
+
;;
|
|
481
|
+
2)
|
|
482
|
+
add_custom_api_agent
|
|
483
|
+
;;
|
|
484
|
+
3|"")
|
|
485
|
+
done_api_config=true
|
|
486
|
+
;;
|
|
487
|
+
esac
|
|
488
|
+
done
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
# Internal function to configure predefined API agents
|
|
492
|
+
_configure_predefined_api_agents() {
|
|
493
|
+
for i in "${!API_AGENT_NAMES[@]}"; do
|
|
494
|
+
local name="${API_AGENT_NAMES[$i]}"
|
|
495
|
+
local key_var="${API_AGENT_KEY_VARS[$i]}"
|
|
496
|
+
local persona="${API_AGENT_PERSONAS[$i]}"
|
|
497
|
+
|
|
498
|
+
echo ""
|
|
499
|
+
if confirm "Enable $name ($persona)?"; then
|
|
500
|
+
# Check for existing key in environment
|
|
501
|
+
local existing_key="${!key_var:-}"
|
|
502
|
+
|
|
503
|
+
if [[ -n "$existing_key" ]]; then
|
|
504
|
+
local masked="${existing_key:0:8}...${existing_key: -4}"
|
|
505
|
+
echo " Existing key found: $masked"
|
|
506
|
+
if confirm " Use existing key?" "y"; then
|
|
507
|
+
API_ENABLED[$i]="true"
|
|
508
|
+
API_KEYS_VALUES[$i]="$existing_key"
|
|
509
|
+
continue
|
|
510
|
+
fi
|
|
511
|
+
fi
|
|
512
|
+
|
|
513
|
+
# Prompt for new key
|
|
514
|
+
prompt_secret " Enter $name API key ($key_var)"
|
|
515
|
+
local api_key="$REPLY"
|
|
516
|
+
|
|
517
|
+
if [[ -n "$api_key" ]]; then
|
|
518
|
+
API_ENABLED[$i]="true"
|
|
519
|
+
API_KEYS_VALUES[$i]="$api_key"
|
|
520
|
+
log_success "$name enabled"
|
|
521
|
+
else
|
|
522
|
+
log_warn "$name skipped (no API key)"
|
|
523
|
+
fi
|
|
524
|
+
fi
|
|
525
|
+
done
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
# =============================================================================
|
|
529
|
+
# VALIDATION
|
|
530
|
+
# =============================================================================
|
|
531
|
+
|
|
532
|
+
validate_configuration() {
|
|
533
|
+
print_section "Validating Configuration"
|
|
534
|
+
|
|
535
|
+
local cli_count=0
|
|
536
|
+
local api_count=0
|
|
537
|
+
local custom_cli_count=${#CUSTOM_NAMES[@]}
|
|
538
|
+
local custom_api_count=${#CUSTOM_API_NAMES[@]}
|
|
539
|
+
|
|
540
|
+
# Count enabled CLI agents
|
|
541
|
+
for i in "${!CLI_AGENT_NAMES[@]}"; do
|
|
542
|
+
if [[ "${CLI_ENABLED[$i]}" == "true" ]]; then
|
|
543
|
+
((cli_count++)) || true
|
|
544
|
+
fi
|
|
545
|
+
done
|
|
546
|
+
|
|
547
|
+
# Count enabled predefined API agents
|
|
548
|
+
for i in "${!API_AGENT_NAMES[@]}"; do
|
|
549
|
+
if [[ "${API_ENABLED[$i]}" == "true" ]]; then
|
|
550
|
+
((api_count++)) || true
|
|
551
|
+
fi
|
|
552
|
+
done
|
|
553
|
+
|
|
554
|
+
local total_cli=$((cli_count + custom_cli_count))
|
|
555
|
+
local total_api=$((api_count + custom_api_count))
|
|
556
|
+
local total_enabled=$((total_cli + total_api))
|
|
557
|
+
|
|
558
|
+
echo "Summary:"
|
|
559
|
+
echo " CLI agents enabled: $total_cli (predefined: $cli_count, custom: $custom_cli_count)"
|
|
560
|
+
echo " API agents enabled: $total_api (predefined: $api_count, custom: $custom_api_count)"
|
|
561
|
+
echo " Total enabled: $total_enabled"
|
|
562
|
+
echo ""
|
|
563
|
+
|
|
564
|
+
# Validation: minimum 2 agents required
|
|
565
|
+
if [[ $total_enabled -lt 2 ]]; then
|
|
566
|
+
log_error "At least 2 agents must be enabled for AI Consultants to work."
|
|
567
|
+
echo ""
|
|
568
|
+
echo "The system requires multiple perspectives for:"
|
|
569
|
+
echo " - Comparison and voting"
|
|
570
|
+
echo " - Multi-Agent Debate"
|
|
571
|
+
echo " - Consensus building"
|
|
572
|
+
echo ""
|
|
573
|
+
|
|
574
|
+
if [[ "$NON_INTERACTIVE" == "true" ]]; then
|
|
575
|
+
return 1
|
|
576
|
+
fi
|
|
577
|
+
|
|
578
|
+
echo "Options:"
|
|
579
|
+
echo " 1) Add custom CLI agent"
|
|
580
|
+
echo " 2) Configure API agents"
|
|
581
|
+
echo " 3) Abort configuration"
|
|
582
|
+
echo ""
|
|
583
|
+
|
|
584
|
+
read -r -p "Choice [1-3]: " choice
|
|
585
|
+
|
|
586
|
+
case "$choice" in
|
|
587
|
+
1)
|
|
588
|
+
add_custom_cli_agent
|
|
589
|
+
validate_configuration
|
|
590
|
+
return $?
|
|
591
|
+
;;
|
|
592
|
+
2)
|
|
593
|
+
configure_api_agents
|
|
594
|
+
validate_configuration
|
|
595
|
+
return $?
|
|
596
|
+
;;
|
|
597
|
+
*)
|
|
598
|
+
return 1
|
|
599
|
+
;;
|
|
600
|
+
esac
|
|
601
|
+
else
|
|
602
|
+
log_success "Configuration valid: $total_enabled agents enabled"
|
|
603
|
+
return 0
|
|
604
|
+
fi
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
# =============================================================================
|
|
608
|
+
# SAVE CONFIGURATION
|
|
609
|
+
# =============================================================================
|
|
610
|
+
|
|
611
|
+
save_configuration() {
|
|
612
|
+
print_section "Saving Configuration"
|
|
613
|
+
|
|
614
|
+
# Backup existing .env if present
|
|
615
|
+
if [[ -f "$OUTPUT_FILE" ]]; then
|
|
616
|
+
local backup="${OUTPUT_FILE}.backup.$(date +%Y%m%d_%H%M%S)"
|
|
617
|
+
cp "$OUTPUT_FILE" "$backup"
|
|
618
|
+
chmod 600 "$backup" # Secure backup file too
|
|
619
|
+
log_info "Backed up existing config to: $backup"
|
|
620
|
+
fi
|
|
621
|
+
|
|
622
|
+
# Generate .env file with secure permissions
|
|
623
|
+
# Create file with restrictive permissions BEFORE writing secrets
|
|
624
|
+
touch "$OUTPUT_FILE"
|
|
625
|
+
chmod 600 "$OUTPUT_FILE"
|
|
626
|
+
|
|
627
|
+
cat > "$OUTPUT_FILE" << 'HEADER'
|
|
628
|
+
# =============================================================================
|
|
629
|
+
# AI Consultants v2.0 - Generated Configuration
|
|
630
|
+
# =============================================================================
|
|
631
|
+
# Generated by: ./scripts/configure.sh
|
|
632
|
+
#
|
|
633
|
+
# This file was auto-generated. You can edit it manually or re-run configure.sh
|
|
634
|
+
#
|
|
635
|
+
# Export variables before running:
|
|
636
|
+
# source .env && ./scripts/consult_all.sh "Your question"
|
|
637
|
+
|
|
638
|
+
HEADER
|
|
639
|
+
|
|
640
|
+
# CLI Agents
|
|
641
|
+
emit_env_section "ENABLED CONSULTANTS"
|
|
642
|
+
echo "# CLI-based consultants" >> "$OUTPUT_FILE"
|
|
643
|
+
|
|
644
|
+
for i in "${!CLI_AGENT_NAMES[@]}"; do
|
|
645
|
+
local name_upper
|
|
646
|
+
name_upper=$(to_upper "${CLI_AGENT_NAMES[$i]}")
|
|
647
|
+
echo "ENABLE_${name_upper}=${CLI_ENABLED[$i]}" >> "$OUTPUT_FILE"
|
|
648
|
+
done
|
|
649
|
+
|
|
650
|
+
echo -e "\n# API-based consultants" >> "$OUTPUT_FILE"
|
|
651
|
+
|
|
652
|
+
for i in "${!API_AGENT_NAMES[@]}"; do
|
|
653
|
+
local name_upper
|
|
654
|
+
name_upper=$(to_upper "${API_AGENT_NAMES[$i]}")
|
|
655
|
+
echo "ENABLE_${name_upper}=${API_ENABLED[$i]}" >> "$OUTPUT_FILE"
|
|
656
|
+
done
|
|
657
|
+
|
|
658
|
+
# API Keys
|
|
659
|
+
emit_env_section "API KEYS"
|
|
660
|
+
|
|
661
|
+
for i in "${!API_AGENT_NAMES[@]}"; do
|
|
662
|
+
if [[ -n "${API_KEYS_VALUES[$i]}" ]]; then
|
|
663
|
+
local key_var="${API_AGENT_KEY_VARS[$i]}"
|
|
664
|
+
echo "${key_var}=${API_KEYS_VALUES[$i]}" >> "$OUTPUT_FILE"
|
|
665
|
+
fi
|
|
666
|
+
done
|
|
667
|
+
|
|
668
|
+
# Custom CLI agents
|
|
669
|
+
if [[ ${#CUSTOM_NAMES[@]} -gt 0 ]]; then
|
|
670
|
+
emit_env_section "CUSTOM CLI AGENTS"
|
|
671
|
+
|
|
672
|
+
for i in "${!CUSTOM_NAMES[@]}"; do
|
|
673
|
+
local var_upper
|
|
674
|
+
var_upper=$(to_upper "${CUSTOM_NAMES[$i]}")
|
|
675
|
+
echo "# Custom CLI agent: ${CUSTOM_NAMES[$i]} (${CUSTOM_PERSONAS[$i]})" >> "$OUTPUT_FILE"
|
|
676
|
+
echo "${var_upper}_CMD=${CUSTOM_CMDS[$i]}" >> "$OUTPUT_FILE"
|
|
677
|
+
echo "ENABLE_${var_upper}=true" >> "$OUTPUT_FILE"
|
|
678
|
+
done
|
|
679
|
+
fi
|
|
680
|
+
|
|
681
|
+
# Custom API agents
|
|
682
|
+
if [[ ${#CUSTOM_API_NAMES[@]} -gt 0 ]]; then
|
|
683
|
+
emit_env_section "CUSTOM API AGENTS"
|
|
684
|
+
|
|
685
|
+
for i in "${!CUSTOM_API_NAMES[@]}"; do
|
|
686
|
+
local var_upper
|
|
687
|
+
var_upper=$(to_upper "${CUSTOM_API_NAMES[$i]}")
|
|
688
|
+
{
|
|
689
|
+
echo "# Custom API agent: ${CUSTOM_API_NAMES[$i]}"
|
|
690
|
+
echo "# Persona: ${CUSTOM_API_PERSONAS[$i]}"
|
|
691
|
+
echo "${var_upper}_API_KEY=${CUSTOM_API_KEYS[$i]}"
|
|
692
|
+
echo "${var_upper}_API_URL=${CUSTOM_API_URLS[$i]}"
|
|
693
|
+
echo "${var_upper}_MODEL=${CUSTOM_API_MODELS[$i]}"
|
|
694
|
+
echo "${var_upper}_TIMEOUT=180"
|
|
695
|
+
echo "${var_upper}_FORMAT=${CUSTOM_API_FORMATS[$i]}"
|
|
696
|
+
echo "${var_upper}_PERSONA=\"${CUSTOM_API_PERSONAS[$i]}\""
|
|
697
|
+
echo "ENABLE_${var_upper}=true"
|
|
698
|
+
echo ""
|
|
699
|
+
} >> "$OUTPUT_FILE"
|
|
700
|
+
done
|
|
701
|
+
fi
|
|
702
|
+
|
|
703
|
+
# Persona assignments (only output non-default assignments)
|
|
704
|
+
emit_env_section "PERSONA ASSIGNMENTS"
|
|
705
|
+
{
|
|
706
|
+
echo "# Default personas are used unless overridden here"
|
|
707
|
+
echo "# Persona IDs: 1=Architect, 2=Pragmatist, 3=Devil's Advocate, 4=Innovator,"
|
|
708
|
+
echo "# 5=Integrator, 6=Analyst, 7=Methodologist, 8=Provocateur, 9=Mentor,"
|
|
709
|
+
echo "# 10=Optimizer, 11=Security Expert, 12=Minimalist, 13=DX Advocate,"
|
|
710
|
+
echo "# 14=Debugger, 15=Reviewer"
|
|
711
|
+
echo ""
|
|
712
|
+
} >> "$OUTPUT_FILE"
|
|
713
|
+
|
|
714
|
+
# Helper to write persona assignment if non-default
|
|
715
|
+
_write_persona_if_changed() {
|
|
716
|
+
local name_upper="$1" persona_id="$2" default_id="$3" custom_text="$4"
|
|
717
|
+
if [[ "$persona_id" == "0" && -n "$custom_text" ]]; then
|
|
718
|
+
echo "${name_upper}_PERSONA=\"$custom_text\"" >> "$OUTPUT_FILE"
|
|
719
|
+
elif [[ "$persona_id" != "$default_id" ]]; then
|
|
720
|
+
echo "${name_upper}_PERSONA_ID=$persona_id" >> "$OUTPUT_FILE"
|
|
721
|
+
fi
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
# CLI agent personas
|
|
725
|
+
for i in "${!CLI_AGENT_NAMES[@]}"; do
|
|
726
|
+
[[ "${CLI_ENABLED[$i]}" != "true" ]] && continue
|
|
727
|
+
_write_persona_if_changed "$(to_upper "${CLI_AGENT_NAMES[$i]}")" \
|
|
728
|
+
"${CLI_PERSONA_IDS[$i]}" "${CLI_DEFAULT_PERSONA_IDS[$i]}" "${CLI_AGENT_PERSONAS[$i]:-}"
|
|
729
|
+
done
|
|
730
|
+
|
|
731
|
+
# API agent personas
|
|
732
|
+
for i in "${!API_AGENT_NAMES[@]}"; do
|
|
733
|
+
[[ "${API_ENABLED[$i]}" != "true" ]] && continue
|
|
734
|
+
_write_persona_if_changed "$(to_upper "${API_AGENT_NAMES[$i]}")" \
|
|
735
|
+
"${API_PERSONA_IDS[$i]}" "${API_DEFAULT_PERSONA_IDS[$i]}" "${API_AGENT_PERSONAS[$i]:-}"
|
|
736
|
+
done
|
|
737
|
+
|
|
738
|
+
# Custom CLI agent personas
|
|
739
|
+
for i in "${!CUSTOM_NAMES[@]}"; do
|
|
740
|
+
[[ ${#CUSTOM_PERSONA_IDS[@]} -le $i ]] && continue
|
|
741
|
+
_write_persona_if_changed "$(to_upper "${CUSTOM_NAMES[$i]}")" \
|
|
742
|
+
"${CUSTOM_PERSONA_IDS[$i]}" "1" "${CUSTOM_PERSONAS[$i]:-}"
|
|
743
|
+
done
|
|
744
|
+
|
|
745
|
+
# Default configuration from template
|
|
746
|
+
cat >> "$OUTPUT_FILE" << 'DEFAULTS'
|
|
747
|
+
|
|
748
|
+
# =============================================================================
|
|
749
|
+
# MODEL CONFIGURATION
|
|
750
|
+
# =============================================================================
|
|
751
|
+
|
|
752
|
+
GEMINI_MODEL=gemini-2.5-pro
|
|
753
|
+
GEMINI_TIMEOUT=180
|
|
754
|
+
|
|
755
|
+
CODEX_MODEL=
|
|
756
|
+
CODEX_TIMEOUT=180
|
|
757
|
+
|
|
758
|
+
MISTRAL_TIMEOUT=180
|
|
759
|
+
|
|
760
|
+
KILO_TIMEOUT=180
|
|
761
|
+
|
|
762
|
+
CURSOR_TIMEOUT=180
|
|
763
|
+
|
|
764
|
+
AIDER_MODEL=
|
|
765
|
+
AIDER_TIMEOUT=180
|
|
766
|
+
|
|
767
|
+
# API models
|
|
768
|
+
QWEN3_MODEL=qwen-max
|
|
769
|
+
QWEN3_TIMEOUT=180
|
|
770
|
+
|
|
771
|
+
GLM_MODEL=glm-4
|
|
772
|
+
GLM_TIMEOUT=180
|
|
773
|
+
|
|
774
|
+
GROK_MODEL=grok-4-1-fast-reasoning
|
|
775
|
+
GROK_TIMEOUT=180
|
|
776
|
+
|
|
777
|
+
DEEPSEEK_MODEL=deepseek-reasoner
|
|
778
|
+
DEEPSEEK_TIMEOUT=180
|
|
779
|
+
|
|
780
|
+
# =============================================================================
|
|
781
|
+
# FEATURES
|
|
782
|
+
# =============================================================================
|
|
783
|
+
|
|
784
|
+
ENABLE_PERSONA=true
|
|
785
|
+
ENABLE_SYNTHESIS=true
|
|
786
|
+
SYNTHESIS_CMD=claude
|
|
787
|
+
|
|
788
|
+
ENABLE_DEBATE=false
|
|
789
|
+
DEBATE_ROUNDS=1
|
|
790
|
+
|
|
791
|
+
ENABLE_REFLECTION=false
|
|
792
|
+
REFLECTION_CYCLES=1
|
|
793
|
+
|
|
794
|
+
# =============================================================================
|
|
795
|
+
# SMART ROUTING
|
|
796
|
+
# =============================================================================
|
|
797
|
+
|
|
798
|
+
ENABLE_CLASSIFICATION=true
|
|
799
|
+
CLASSIFICATION_MODE=pattern
|
|
800
|
+
ENABLE_SMART_ROUTING=false
|
|
801
|
+
MIN_AFFINITY=7
|
|
802
|
+
|
|
803
|
+
# =============================================================================
|
|
804
|
+
# COST & SESSION
|
|
805
|
+
# =============================================================================
|
|
806
|
+
|
|
807
|
+
ENABLE_COST_TRACKING=true
|
|
808
|
+
MAX_SESSION_COST=1.00
|
|
809
|
+
WARN_AT_COST=0.50
|
|
810
|
+
|
|
811
|
+
SESSION_DIR=/tmp/ai_consultants_sessions
|
|
812
|
+
SESSION_CLEANUP_DAYS=7
|
|
813
|
+
|
|
814
|
+
# =============================================================================
|
|
815
|
+
# OTHER
|
|
816
|
+
# =============================================================================
|
|
817
|
+
|
|
818
|
+
ENABLE_PROGRESS_BARS=true
|
|
819
|
+
ENABLE_EARLY_TERMINATION=true
|
|
820
|
+
ENABLE_PREFLIGHT=false
|
|
821
|
+
MAX_RETRIES=2
|
|
822
|
+
RETRY_DELAY_SECONDS=5
|
|
823
|
+
LOG_LEVEL=INFO
|
|
824
|
+
DEFAULTS
|
|
825
|
+
|
|
826
|
+
log_success "Configuration saved to: $OUTPUT_FILE"
|
|
827
|
+
echo ""
|
|
828
|
+
echo "To use this configuration:"
|
|
829
|
+
echo " source $OUTPUT_FILE && ./scripts/consult_all.sh \"Your question\""
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
# =============================================================================
|
|
833
|
+
# PERSONA CONFIGURATION
|
|
834
|
+
# =============================================================================
|
|
835
|
+
|
|
836
|
+
configure_personas() {
|
|
837
|
+
print_section "Configure Personas"
|
|
838
|
+
|
|
839
|
+
if [[ "$NON_INTERACTIVE" == "true" ]]; then
|
|
840
|
+
log_info "Using default personas (non-interactive mode)"
|
|
841
|
+
return
|
|
842
|
+
fi
|
|
843
|
+
|
|
844
|
+
echo "Each agent can have a different persona that shapes its response style."
|
|
845
|
+
echo "Default personas are pre-configured, but you can customize them."
|
|
846
|
+
echo ""
|
|
847
|
+
|
|
848
|
+
if ! confirm "Customize agent personas?" "n"; then
|
|
849
|
+
return
|
|
850
|
+
fi
|
|
851
|
+
|
|
852
|
+
local done_personas=false
|
|
853
|
+
while [[ "$done_personas" != "true" ]]; do
|
|
854
|
+
echo ""
|
|
855
|
+
echo "Enabled agents and their personas:"
|
|
856
|
+
echo ""
|
|
857
|
+
|
|
858
|
+
local menu_idx=1
|
|
859
|
+
local agent_list=() # Track: "type|index" (e.g., "cli|0", "api|2")
|
|
860
|
+
|
|
861
|
+
# List CLI agents
|
|
862
|
+
for i in "${!CLI_AGENT_NAMES[@]}"; do
|
|
863
|
+
if [[ "${CLI_ENABLED[$i]}" == "true" ]]; then
|
|
864
|
+
local name="${CLI_AGENT_NAMES[$i]}"
|
|
865
|
+
local persona_id="${CLI_PERSONA_IDS[$i]}"
|
|
866
|
+
local persona_name
|
|
867
|
+
persona_name=$(get_persona_by_id "$persona_id" "name" 2>/dev/null || echo "Unknown")
|
|
868
|
+
printf " %2s) %-12s - %s\n" "$menu_idx" "$name" "$persona_name"
|
|
869
|
+
agent_list+=("cli|$i")
|
|
870
|
+
((menu_idx++)) || true
|
|
871
|
+
fi
|
|
872
|
+
done
|
|
873
|
+
|
|
874
|
+
# List API agents
|
|
875
|
+
for i in "${!API_AGENT_NAMES[@]}"; do
|
|
876
|
+
if [[ "${API_ENABLED[$i]}" == "true" ]]; then
|
|
877
|
+
local name="${API_AGENT_NAMES[$i]}"
|
|
878
|
+
local persona_id="${API_PERSONA_IDS[$i]}"
|
|
879
|
+
local persona_name
|
|
880
|
+
persona_name=$(get_persona_by_id "$persona_id" "name" 2>/dev/null || echo "Unknown")
|
|
881
|
+
printf " %2s) %-12s - %s\n" "$menu_idx" "$name" "$persona_name"
|
|
882
|
+
agent_list+=("api|$i")
|
|
883
|
+
((menu_idx++)) || true
|
|
884
|
+
fi
|
|
885
|
+
done
|
|
886
|
+
|
|
887
|
+
# List custom CLI agents
|
|
888
|
+
for i in "${!CUSTOM_NAMES[@]}"; do
|
|
889
|
+
local name="${CUSTOM_NAMES[$i]}"
|
|
890
|
+
local persona_id="${CUSTOM_PERSONA_IDS[$i]:-1}"
|
|
891
|
+
local persona_name
|
|
892
|
+
persona_name=$(get_persona_by_id "$persona_id" "name" 2>/dev/null || echo "Custom")
|
|
893
|
+
printf " %2s) %-12s - %s (custom)\n" "$menu_idx" "$name" "$persona_name"
|
|
894
|
+
agent_list+=("custom_cli|$i")
|
|
895
|
+
((menu_idx++)) || true
|
|
896
|
+
done
|
|
897
|
+
|
|
898
|
+
# List custom API agents
|
|
899
|
+
for i in "${!CUSTOM_API_NAMES[@]}"; do
|
|
900
|
+
local name="${CUSTOM_API_NAMES[$i]}"
|
|
901
|
+
local persona_id="${CUSTOM_API_PERSONA_IDS[$i]:-1}"
|
|
902
|
+
local persona_name
|
|
903
|
+
persona_name=$(get_persona_by_id "$persona_id" "name" 2>/dev/null || echo "Custom")
|
|
904
|
+
printf " %2s) %-12s - %s (custom API)\n" "$menu_idx" "$name" "$persona_name"
|
|
905
|
+
agent_list+=("custom_api|$i")
|
|
906
|
+
((menu_idx++)) || true
|
|
907
|
+
done
|
|
908
|
+
|
|
909
|
+
echo ""
|
|
910
|
+
echo " d) Done with persona configuration"
|
|
911
|
+
echo ""
|
|
912
|
+
|
|
913
|
+
read -r -p "Select agent to change persona (or 'd' for done): " choice
|
|
914
|
+
|
|
915
|
+
if [[ "$choice" == "d" || "$choice" == "D" ]]; then
|
|
916
|
+
done_personas=true
|
|
917
|
+
continue
|
|
918
|
+
fi
|
|
919
|
+
|
|
920
|
+
# Validate selection
|
|
921
|
+
if ! [[ "$choice" =~ ^[0-9]+$ ]] || [[ $choice -lt 1 ]] || [[ $choice -gt ${#agent_list[@]} ]]; then
|
|
922
|
+
log_warn "Invalid selection"
|
|
923
|
+
continue
|
|
924
|
+
fi
|
|
925
|
+
|
|
926
|
+
# Get selected agent info
|
|
927
|
+
local selected="${agent_list[$((choice-1))]}"
|
|
928
|
+
local agent_type="${selected%%|*}"
|
|
929
|
+
local agent_idx="${selected##*|}"
|
|
930
|
+
|
|
931
|
+
local agent_name
|
|
932
|
+
case "$agent_type" in
|
|
933
|
+
cli) agent_name="${CLI_AGENT_NAMES[$agent_idx]}" ;;
|
|
934
|
+
api) agent_name="${API_AGENT_NAMES[$agent_idx]}" ;;
|
|
935
|
+
custom_cli) agent_name="${CUSTOM_NAMES[$agent_idx]}" ;;
|
|
936
|
+
custom_api) agent_name="${CUSTOM_API_NAMES[$agent_idx]}" ;;
|
|
937
|
+
esac
|
|
938
|
+
|
|
939
|
+
# Show persona selection menu
|
|
940
|
+
_select_persona_for_agent "$agent_type" "$agent_idx" "$agent_name"
|
|
941
|
+
done
|
|
942
|
+
|
|
943
|
+
log_success "Persona configuration complete"
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
# Internal: Select a persona for a specific agent
|
|
947
|
+
_select_persona_for_agent() {
|
|
948
|
+
local agent_type="$1"
|
|
949
|
+
local agent_idx="$2"
|
|
950
|
+
local agent_name="$3"
|
|
951
|
+
|
|
952
|
+
echo ""
|
|
953
|
+
echo "Select persona for $agent_name:"
|
|
954
|
+
echo ""
|
|
955
|
+
|
|
956
|
+
# Get current persona ID
|
|
957
|
+
local current_id
|
|
958
|
+
case "$agent_type" in
|
|
959
|
+
cli) current_id="${CLI_PERSONA_IDS[$agent_idx]}" ;;
|
|
960
|
+
api) current_id="${API_PERSONA_IDS[$agent_idx]}" ;;
|
|
961
|
+
custom_cli) current_id="${CUSTOM_PERSONA_IDS[$agent_idx]:-1}" ;;
|
|
962
|
+
custom_api) current_id="${CUSTOM_API_PERSONA_IDS[$agent_idx]:-1}" ;;
|
|
963
|
+
esac
|
|
964
|
+
|
|
965
|
+
# Display persona catalog
|
|
966
|
+
echo "$PERSONA_CATALOG" | grep -v '^$' | while IFS='|' read -r id name var desc; do
|
|
967
|
+
local marker=" "
|
|
968
|
+
[[ "$id" == "$current_id" ]] && marker="* "
|
|
969
|
+
printf " %s%2s) %-22s - %s\n" "$marker" "$id" "$name" "$desc"
|
|
970
|
+
done
|
|
971
|
+
|
|
972
|
+
echo ""
|
|
973
|
+
echo " c) Enter custom persona text"
|
|
974
|
+
echo ""
|
|
975
|
+
|
|
976
|
+
read -r -p "Choice [$current_id]: " persona_choice
|
|
977
|
+
persona_choice="${persona_choice:-$current_id}"
|
|
978
|
+
|
|
979
|
+
if [[ "$persona_choice" == "c" || "$persona_choice" == "C" ]]; then
|
|
980
|
+
prompt_input "Enter custom persona description" ""
|
|
981
|
+
local custom_text="$REPLY"
|
|
982
|
+
if [[ -n "$custom_text" ]]; then
|
|
983
|
+
# For custom text, we store it differently - use ID 0 to indicate custom
|
|
984
|
+
case "$agent_type" in
|
|
985
|
+
cli)
|
|
986
|
+
CLI_PERSONA_IDS[$agent_idx]="0"
|
|
987
|
+
CLI_AGENT_PERSONAS[$agent_idx]="$custom_text"
|
|
988
|
+
;;
|
|
989
|
+
api)
|
|
990
|
+
API_PERSONA_IDS[$agent_idx]="0"
|
|
991
|
+
API_AGENT_PERSONAS[$agent_idx]="$custom_text"
|
|
992
|
+
;;
|
|
993
|
+
custom_cli)
|
|
994
|
+
CUSTOM_PERSONA_IDS[$agent_idx]="0"
|
|
995
|
+
CUSTOM_PERSONAS[$agent_idx]="$custom_text"
|
|
996
|
+
;;
|
|
997
|
+
custom_api)
|
|
998
|
+
CUSTOM_API_PERSONA_IDS[$agent_idx]="0"
|
|
999
|
+
CUSTOM_API_PERSONAS[$agent_idx]="$custom_text"
|
|
1000
|
+
;;
|
|
1001
|
+
esac
|
|
1002
|
+
log_success "$agent_name: Custom persona set"
|
|
1003
|
+
fi
|
|
1004
|
+
return
|
|
1005
|
+
fi
|
|
1006
|
+
|
|
1007
|
+
# Validate persona ID selection
|
|
1008
|
+
if [[ "$persona_choice" =~ ^[0-9]+$ ]] && [[ $persona_choice -ge 1 ]] && [[ $persona_choice -le 15 ]]; then
|
|
1009
|
+
case "$agent_type" in
|
|
1010
|
+
cli) CLI_PERSONA_IDS[$agent_idx]="$persona_choice" ;;
|
|
1011
|
+
api) API_PERSONA_IDS[$agent_idx]="$persona_choice" ;;
|
|
1012
|
+
custom_cli)
|
|
1013
|
+
# Ensure array is large enough
|
|
1014
|
+
while [[ ${#CUSTOM_PERSONA_IDS[@]} -le $agent_idx ]]; do
|
|
1015
|
+
CUSTOM_PERSONA_IDS+=("1")
|
|
1016
|
+
done
|
|
1017
|
+
CUSTOM_PERSONA_IDS[$agent_idx]="$persona_choice"
|
|
1018
|
+
;;
|
|
1019
|
+
custom_api)
|
|
1020
|
+
while [[ ${#CUSTOM_API_PERSONA_IDS[@]} -le $agent_idx ]]; do
|
|
1021
|
+
CUSTOM_API_PERSONA_IDS+=("1")
|
|
1022
|
+
done
|
|
1023
|
+
CUSTOM_API_PERSONA_IDS[$agent_idx]="$persona_choice"
|
|
1024
|
+
;;
|
|
1025
|
+
esac
|
|
1026
|
+
local new_name
|
|
1027
|
+
new_name=$(get_persona_by_id "$persona_choice" "name")
|
|
1028
|
+
log_success "$agent_name: Persona changed to $new_name"
|
|
1029
|
+
else
|
|
1030
|
+
log_warn "Invalid selection, keeping current persona"
|
|
1031
|
+
fi
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
# =============================================================================
|
|
1035
|
+
# MAIN
|
|
1036
|
+
# =============================================================================
|
|
1037
|
+
|
|
1038
|
+
main() {
|
|
1039
|
+
print_header "AI Consultants v2.0 - Configuration Wizard"
|
|
1040
|
+
|
|
1041
|
+
echo "This wizard will help you configure AI Consultants."
|
|
1042
|
+
echo "You need at least 2 agents enabled (CLI or API-based)."
|
|
1043
|
+
echo ""
|
|
1044
|
+
|
|
1045
|
+
# Step 1: Detect CLI agents
|
|
1046
|
+
detect_cli_agents
|
|
1047
|
+
|
|
1048
|
+
# Step 2: Select CLI agents
|
|
1049
|
+
select_cli_agents
|
|
1050
|
+
|
|
1051
|
+
# Step 3: Configure API agents
|
|
1052
|
+
configure_api_agents
|
|
1053
|
+
|
|
1054
|
+
# Step 4: Configure personas
|
|
1055
|
+
configure_personas
|
|
1056
|
+
|
|
1057
|
+
# Step 5: Validate (minimum 2 agents)
|
|
1058
|
+
if ! validate_configuration; then
|
|
1059
|
+
log_error "Configuration incomplete. At least 2 agents required."
|
|
1060
|
+
exit 1
|
|
1061
|
+
fi
|
|
1062
|
+
|
|
1063
|
+
# Step 6: Save
|
|
1064
|
+
if [[ "$NON_INTERACTIVE" == "true" ]] || confirm "Save configuration to $OUTPUT_FILE?" "y"; then
|
|
1065
|
+
save_configuration
|
|
1066
|
+
else
|
|
1067
|
+
log_warn "Configuration not saved."
|
|
1068
|
+
exit 1
|
|
1069
|
+
fi
|
|
1070
|
+
|
|
1071
|
+
print_header "Configuration Complete"
|
|
1072
|
+
|
|
1073
|
+
# Show summary
|
|
1074
|
+
echo "Enabled agents:"
|
|
1075
|
+
for i in "${!CLI_AGENT_NAMES[@]}"; do
|
|
1076
|
+
[[ "${CLI_ENABLED[$i]}" == "true" ]] && echo " [CLI] ${CLI_AGENT_NAMES[$i]}"
|
|
1077
|
+
done
|
|
1078
|
+
for name in ${CUSTOM_NAMES[@]+"${CUSTOM_NAMES[@]}"}; do echo " [CLI] $name (custom)"; done
|
|
1079
|
+
for i in "${!API_AGENT_NAMES[@]}"; do
|
|
1080
|
+
[[ "${API_ENABLED[$i]}" == "true" ]] && echo " [API] ${API_AGENT_NAMES[$i]}"
|
|
1081
|
+
done
|
|
1082
|
+
for name in ${CUSTOM_API_NAMES[@]+"${CUSTOM_API_NAMES[@]}"}; do echo " [API] $name (custom)"; done
|
|
1083
|
+
|
|
1084
|
+
echo ""
|
|
1085
|
+
echo "Next steps:"
|
|
1086
|
+
echo " 1. Review and edit $OUTPUT_FILE if needed"
|
|
1087
|
+
echo " 2. Run: source $OUTPUT_FILE"
|
|
1088
|
+
echo " 3. Test: ./scripts/preflight_check.sh"
|
|
1089
|
+
echo " 4. Start: ./scripts/consult_all.sh \"Your question\""
|
|
1090
|
+
echo ""
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
main "$@"
|