claude-all-config 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/LICENSE.md +70 -0
- package/README.md +133 -0
- package/VERSION +1 -0
- package/agents/accessibility-reviewer.md +96 -0
- package/agents/ai-prompt-optimizer.md +94 -0
- package/agents/api-tester.md +102 -0
- package/agents/code-generator.md +94 -0
- package/agents/code-reviewer.md +47 -0
- package/agents/component-generator.md +102 -0
- package/agents/doc-generator.md +91 -0
- package/agents/migration-generator.md +94 -0
- package/agents/performance-analyzer.md +90 -0
- package/agents/proactive-mode.md +91 -0
- package/agents/readme-generator.md +101 -0
- package/agents/security-auditor.md +86 -0
- package/agents/terraform-generator.md +94 -0
- package/agents/test-generator.md +76 -0
- package/bin/agentrouter.json +36 -0
- package/bin/ai-chat +20 -0
- package/bin/antigravity.json +76 -0
- package/bin/api-manager +340 -0
- package/bin/claude-launcher +19 -0
- package/bin/claude-master +15 -0
- package/bin/claude_master.py +295 -0
- package/bin/cohere.json +7 -0
- package/bin/deepseek.json +44 -0
- package/bin/gemini.json +56 -0
- package/bin/glm.json +21 -0
- package/bin/groq.json +41 -0
- package/bin/minimax.json +26 -0
- package/bin/mistral.json +7 -0
- package/bin/moonshot.json +7 -0
- package/bin/ollama.json +36 -0
- package/bin/openai.json +46 -0
- package/bin/openrouter.json +38 -0
- package/bin/perplexity.json +12 -0
- package/bin/qwen.json +7 -0
- package/bin/switch-provider +73 -0
- package/bin/test.json +7 -0
- package/bin/xai.json +41 -0
- package/claude-all +2707 -0
- package/claude-config.json +340 -0
- package/claude-suite/REFACTORING_SUMMARY.md +88 -0
- package/claude-suite/auth/.antigravity_proxy.py +78 -0
- package/claude-suite/auth/__pycache__/openai_auth.cpython-312.pyc +0 -0
- package/claude-suite/auth/gemini_auth.py +80 -0
- package/claude-suite/auth/openai_auth.py +138 -0
- package/claude-suite/backups/claude-all-before-refactor +1075 -0
- package/claude-suite/backups/claude-all.backup +840 -0
- package/claude-suite/backups/claude-all.original +840 -0
- package/claude-suite/models/add-model-manual.sh +588 -0
- package/claude-suite/models/add-model.sh +114 -0
- package/claude-suite/models/model-switcher.sh +69 -0
- package/claude-suite/providers/claude-glm +89 -0
- package/claude-suite/providers/claude-glm-wrapper.sh +55 -0
- package/claude-suite/providers/claude-minimax +12 -0
- package/claude-suite/providers/claude-smart +132 -0
- package/claude-suite/providers/xai_chat.sh +56 -0
- package/claude-suite/utils/__pycache__/claude_master.cpython-312.pyc +0 -0
- package/claude-suite/utils/antigravity_proxy_server.py +168 -0
- package/claude-suite/utils/claude-all-help.txt +83 -0
- package/claude-suite/utils/claude_master.py +408 -0
- package/commands/brainstorm.md +5 -0
- package/commands/execute-plan.md +5 -0
- package/commands/write-plan.md +5 -0
- package/docs/ANTIGRAVITY-SETUP.md +176 -0
- package/docs/AUTH_CREDENTIALS.md +54 -0
- package/docs/NPM-INSTALLATION.md +166 -0
- package/hooks/hooks.json +15 -0
- package/hooks/run-hook.cmd +19 -0
- package/hooks/session-start.sh +52 -0
- package/install.sh +155 -0
- package/mcp.json +34 -0
- package/model/perplexity.json +12 -0
- package/package.json +69 -0
- package/plugins/README.md +47 -0
- package/plugins/installed_plugins.json +317 -0
- package/plugins/known_marketplaces.json +10 -0
- package/plugins/marketplace-info/marketplace.json +517 -0
- package/postinstall.js +100 -0
- package/scripts/antigravity_proxy_server.py +168 -0
- package/scripts/get_gemini_api_key.py +96 -0
- package/scripts/setup_antigravity_auth.py +171 -0
- package/skills/api-development/SKILL.md +11 -0
- package/skills/api-development/openapi/api-documentation.yaml +108 -0
- package/skills/brainstorming/SKILL.md +54 -0
- package/skills/code-quality/SKILL.md +196 -0
- package/skills/condition-based-waiting/SKILL.md +120 -0
- package/skills/condition-based-waiting/example.ts +158 -0
- package/skills/database-development/SKILL.md +11 -0
- package/skills/database-development/migrations/migration.template.sql +49 -0
- package/skills/defense-in-depth/SKILL.md +127 -0
- package/skills/deployment/SKILL.md +11 -0
- package/skills/deployment/ci-cd/github-actions.yml +95 -0
- package/skills/deployment/docker/Dockerfile.template +39 -0
- package/skills/dispatching-parallel-agents/SKILL.md +180 -0
- package/skills/documentation-generation/SKILL.md +8 -0
- package/skills/documentation-generation/templates/README.template.md +60 -0
- package/skills/error-handling/SKILL.md +267 -0
- package/skills/executing-plans/SKILL.md +76 -0
- package/skills/finishing-a-development-branch/SKILL.md +200 -0
- package/skills/frontend-design/frontend-design/SKILL.md +42 -0
- package/skills/integration-testing/SKILL.md +13 -0
- package/skills/integration-testing/examples/contract-test.py +317 -0
- package/skills/integration-testing/examples/e2e-test.js +147 -0
- package/skills/integration-testing/examples/test-isolation.md +94 -0
- package/skills/logging-monitoring/SKILL.md +66 -0
- package/skills/mobile-development/SKILL.md +11 -0
- package/skills/mobile-development/responsive/responsive.css +80 -0
- package/skills/performance-optimization/SKILL.md +9 -0
- package/skills/performance-optimization/profiling/profile.template.js +21 -0
- package/skills/receiving-code-review/SKILL.md +209 -0
- package/skills/refactoring/SKILL.md +11 -0
- package/skills/refactoring/code-smells/common-smells.md +115 -0
- package/skills/requesting-code-review/SKILL.md +105 -0
- package/skills/requesting-code-review/code-reviewer.md +146 -0
- package/skills/root-cause-tracing/SKILL.md +174 -0
- package/skills/root-cause-tracing/find-polluter.sh +63 -0
- package/skills/security-review/SKILL.md +11 -0
- package/skills/security-review/checklists/owasp-checklist.md +31 -0
- package/skills/sharing-skills/SKILL.md +194 -0
- package/skills/subagent-driven-development/SKILL.md +240 -0
- package/skills/subagent-driven-development/code-quality-reviewer-prompt.md +20 -0
- package/skills/subagent-driven-development/implementer-prompt.md +78 -0
- package/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -0
- package/skills/systematic-debugging/CREATION-LOG.md +119 -0
- package/skills/systematic-debugging/SKILL.md +295 -0
- package/skills/systematic-debugging/test-academic.md +14 -0
- package/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/skills/test-driven-development/SKILL.md +364 -0
- package/skills/testing-anti-patterns/SKILL.md +302 -0
- package/skills/testing-skills-with-subagents/SKILL.md +387 -0
- package/skills/testing-skills-with-subagents/examples/CLAUDE_MD_TESTING.md +189 -0
- package/skills/ui-ux-review/SKILL.md +13 -0
- package/skills/ui-ux-review/checklists/ux-heuristics.md +61 -0
- package/skills/using-git-worktrees/SKILL.md +213 -0
- package/skills/using-superpowers/SKILL.md +101 -0
- package/skills/verification-before-completion/SKILL.md +139 -0
- package/skills/writing-plans/SKILL.md +116 -0
- package/skills/writing-skills/SKILL.md +622 -0
- package/skills/writing-skills/anthropic-best-practices.md +1150 -0
- package/skills/writing-skills/graphviz-conventions.dot +172 -0
- package/skills/writing-skills/persuasion-principles.md +187 -0
- package/update.sh +36 -0
- package/utils/check-superpowers.sh +114 -0
- package/utils/claude-branding.md +166 -0
- package/utils/config.js +185 -0
- package/utils/custom-claude-config.sh +89 -0
- package/utils/custom-claude-hooks.md +129 -0
- package/utils/custom-claude-lib.js +222 -0
- package/utils/customize-claude-ui.sh +162 -0
- package/utils/fix-claude-integration.sh +133 -0
- package/utils/help.js +125 -0
- package/utils/install-curl.ps1 +135 -0
- package/utils/install-curl.sh +525 -0
- package/utils/install-superpowers.js +411 -0
- package/utils/install.js +298 -0
- package/utils/install.sh +182 -0
- package/utils/postinstall.js +63 -0
- package/utils/rename-claude.sh +96 -0
- package/utils/uninstall-superpowers.js +273 -0
- package/utils/uninstall.ps1 +136 -0
- package/utils/uninstall.sh +163 -0
- package/utils/update.sh +160 -0
package/claude-all
ADDED
|
@@ -0,0 +1,2707 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
|
|
3
|
+
# Cross-platform Claude-All Launcher v7.0
|
|
4
|
+
# Supports: Linux, Termux, macOS, Windows (Git Bash/WSL)
|
|
5
|
+
# Includes Superpowers Library (30 skills + 14 agents)
|
|
6
|
+
|
|
7
|
+
# Platform detection
|
|
8
|
+
detect_platform() {
|
|
9
|
+
case "$(uname -s)" in
|
|
10
|
+
Linux*) echo "Linux";;
|
|
11
|
+
Darwin*) echo "macOS";;
|
|
12
|
+
CYGWIN*|MINGW*|MSYS*) echo "Windows";;
|
|
13
|
+
esac
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
PLATFORM=$(detect_platform)
|
|
17
|
+
|
|
18
|
+
# Colors - auto-detect and install if needed
|
|
19
|
+
setup_colors() {
|
|
20
|
+
# Ensure tput is available for colors
|
|
21
|
+
if ! command -v tput &> /dev/null; then
|
|
22
|
+
if command -v pkg &> /dev/null && [[ "$PLATFORM" != "Windows" ]]; then
|
|
23
|
+
# Install ncurses-utils silently in background
|
|
24
|
+
pkg install -y ncurses-utils &>/dev/null &
|
|
25
|
+
fi
|
|
26
|
+
fi
|
|
27
|
+
|
|
28
|
+
if command -v tput &> /dev/null; then
|
|
29
|
+
GREEN=$(tput setaf 2 2>/dev/null || echo "")
|
|
30
|
+
BLUE=$(tput setaf 4 2>/dev/null || echo "")
|
|
31
|
+
RED=$(tput setaf 1 2>/dev/null || echo "")
|
|
32
|
+
YELLOW=$(tput setaf 3 2>/dev/null || echo "")
|
|
33
|
+
NC=$(tput sgr0 2>/dev/null || echo "")
|
|
34
|
+
else
|
|
35
|
+
# Fallback to plain text
|
|
36
|
+
GREEN=''
|
|
37
|
+
BLUE=''
|
|
38
|
+
RED=''
|
|
39
|
+
YELLOW=''
|
|
40
|
+
NC=''
|
|
41
|
+
fi
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
setup_colors
|
|
45
|
+
|
|
46
|
+
# Reusable functions for API key management
|
|
47
|
+
save_api_key() {
|
|
48
|
+
local api_key="$1"
|
|
49
|
+
local key_file="$2"
|
|
50
|
+
local provider_name="$3"
|
|
51
|
+
|
|
52
|
+
if [[ -z "$api_key" ]]; then
|
|
53
|
+
echo -e "${RED}Error: No API key provided for $provider_name${NC}" >&2
|
|
54
|
+
return 1
|
|
55
|
+
fi
|
|
56
|
+
|
|
57
|
+
if ! echo "$api_key" > "$key_file" 2>/dev/null; then
|
|
58
|
+
echo -e "${YELLOW}Warning: Could not save $provider_name API key to file${NC}" >&2
|
|
59
|
+
return 1
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
if ! chmod 600 "$key_file" 2>/dev/null; then
|
|
63
|
+
echo -e "${YELLOW}Warning: Could not set secure permissions on $provider_name API key file${NC}" >&2
|
|
64
|
+
return 1
|
|
65
|
+
fi
|
|
66
|
+
|
|
67
|
+
echo -e "${GREEN}✓ $provider_name API key saved securely${NC}"
|
|
68
|
+
return 0
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
load_api_key() {
|
|
72
|
+
local key_file="$1"
|
|
73
|
+
local provider_name="$2"
|
|
74
|
+
|
|
75
|
+
if [[ -f "$key_file" ]]; then
|
|
76
|
+
local saved_key
|
|
77
|
+
saved_key=$(cat "$key_file" 2>/dev/null || echo "")
|
|
78
|
+
if [[ -n "$saved_key" ]]; then
|
|
79
|
+
echo -e "${GREEN}✓ Using saved $provider_name API key${NC}"
|
|
80
|
+
echo "$saved_key"
|
|
81
|
+
return 0
|
|
82
|
+
fi
|
|
83
|
+
fi
|
|
84
|
+
return 1
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
prompt_api_key() {
|
|
88
|
+
local provider_name="$1"
|
|
89
|
+
local api_key=""
|
|
90
|
+
|
|
91
|
+
echo -e "${BLUE}Enter $provider_name API Key:${NC}"
|
|
92
|
+
|
|
93
|
+
# Check if we're on Windows (no silent input)
|
|
94
|
+
if [[ "$PLATFORM" == "Windows" ]]; then
|
|
95
|
+
read -p "API Key: " api_key
|
|
96
|
+
else
|
|
97
|
+
# Linux/macOS/Termux - silent read
|
|
98
|
+
read -s -p "API Key: " api_key
|
|
99
|
+
fi
|
|
100
|
+
echo ""
|
|
101
|
+
|
|
102
|
+
echo "$api_key"
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
# Portable home directory
|
|
106
|
+
if [[ -n "$HOME" ]]; then
|
|
107
|
+
USER_HOME="$HOME"
|
|
108
|
+
elif [[ -n "$USERPROFILE" ]]; then
|
|
109
|
+
# Windows
|
|
110
|
+
USER_HOME="$USERPROFILE"
|
|
111
|
+
else
|
|
112
|
+
USER_HOME="$HOME"
|
|
113
|
+
fi
|
|
114
|
+
|
|
115
|
+
# API Key Files - Use user home directory
|
|
116
|
+
GLM_API_KEY_FILE="$USER_HOME/.glm_api_key"
|
|
117
|
+
MINIMAX_API_KEY_FILE="$USER_HOME/.minimax_api_key"
|
|
118
|
+
|
|
119
|
+
# Configuration
|
|
120
|
+
MODEL_OVERRIDE=""
|
|
121
|
+
SELECTED_MODEL=""
|
|
122
|
+
|
|
123
|
+
# Function to get custom models
|
|
124
|
+
get_custom_models() {
|
|
125
|
+
local custom_models=()
|
|
126
|
+
local model_dir="$SCRIPT_DIR/model"
|
|
127
|
+
|
|
128
|
+
# Ensure model directory exists
|
|
129
|
+
if [[ ! -d "$model_dir" ]]; then
|
|
130
|
+
mkdir -p "$model_dir" 2>/dev/null || return 0
|
|
131
|
+
fi
|
|
132
|
+
|
|
133
|
+
# Find JSON files using simple for loop (most compatible)
|
|
134
|
+
for json_file in "$model_dir"/*.json; do
|
|
135
|
+
if [[ -f "$json_file" ]]; then
|
|
136
|
+
local filename=$(basename "$json_file" .json)
|
|
137
|
+
|
|
138
|
+
# Skip default model files
|
|
139
|
+
case "$filename" in
|
|
140
|
+
"glm"|"groq"|"minimax"|"openai"|"gemini"|"xai"|"ollama")
|
|
141
|
+
continue
|
|
142
|
+
;;
|
|
143
|
+
esac
|
|
144
|
+
|
|
145
|
+
# Parse JSON for model info
|
|
146
|
+
if command -v jq &> /dev/null; then
|
|
147
|
+
local provider_name=$(jq -r '.provider_name // "Unknown"' "$json_file" 2>/dev/null)
|
|
148
|
+
local description=$(jq -r '.description // "Custom Provider"' "$json_file" 2>/dev/null)
|
|
149
|
+
# Ensure we got valid values
|
|
150
|
+
[[ "$provider_name" == "null" || -z "$provider_name" ]] && provider_name="Unknown"
|
|
151
|
+
[[ "$description" == "null" || -z "$description" ]] && description="Custom Provider"
|
|
152
|
+
printf '%s:%s:%s\n' "$filename" "$provider_name" "$description"
|
|
153
|
+
else
|
|
154
|
+
# Fallback parsing without jq
|
|
155
|
+
local provider_name=$(grep '"provider_name"' "$json_file" | sed 's/.*"provider_name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/' 2>/dev/null)
|
|
156
|
+
[[ -z "$provider_name" ]] && provider_name="$filename"
|
|
157
|
+
local description=$(grep '"description"' "$json_file" | sed 's/.*"description"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/' 2>/dev/null)
|
|
158
|
+
[[ -z "$description" ]] && description="Custom Provider"
|
|
159
|
+
printf '%s:%s:%s\n' "$filename" "$provider_name" "$description"
|
|
160
|
+
fi
|
|
161
|
+
fi
|
|
162
|
+
done
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
# Function to handle custom model
|
|
166
|
+
handle_custom_model() {
|
|
167
|
+
local model_name="$1"
|
|
168
|
+
local model_file="$SCRIPT_DIR/model/${model_name}.json"
|
|
169
|
+
|
|
170
|
+
if [[ ! -f "$model_file" ]]; then
|
|
171
|
+
echo -e "${RED}Error: Model configuration not found: $model_file${NC}"
|
|
172
|
+
exit 1
|
|
173
|
+
fi
|
|
174
|
+
|
|
175
|
+
# Extract configuration
|
|
176
|
+
if command -v jq &> /dev/null; then
|
|
177
|
+
local api_base=$(jq -r '.api_base // ""' "$model_file" 2>/dev/null)
|
|
178
|
+
local api_key=$(jq -r '.api_key // ""' "$model_file" 2>/dev/null)
|
|
179
|
+
local model=$(jq -r '.model // ""' "$model_file" 2>/dev/null)
|
|
180
|
+
local provider_name=$(jq -r '.provider_name // ""' "$model_file" 2>/dev/null)
|
|
181
|
+
else
|
|
182
|
+
echo -e "${RED}Error: jq is required for custom models. Install with: pkg install jq${NC}"
|
|
183
|
+
exit 1
|
|
184
|
+
fi
|
|
185
|
+
|
|
186
|
+
# Get API key if not provided
|
|
187
|
+
if [[ -z "$api_key" || "$api_key" == "your-api-key-here" ]]; then
|
|
188
|
+
# Try to get from environment based on provider name
|
|
189
|
+
case "${model_name,,}" in
|
|
190
|
+
"qwen"|"qwen2")
|
|
191
|
+
if [[ -n "$DASHSCOPE_API_KEY" ]]; then
|
|
192
|
+
api_key="$DASHSCOPE_API_KEY"
|
|
193
|
+
echo -e "${GREEN}✓ Using API key from DASHSCOPE_API_KEY${NC}"
|
|
194
|
+
else
|
|
195
|
+
echo -e "${YELLOW}Enter Qwen API Key (https://bailian.console.aliyun.com/):${NC}"
|
|
196
|
+
read -s api_key
|
|
197
|
+
fi
|
|
198
|
+
;;
|
|
199
|
+
"deepseek")
|
|
200
|
+
if [[ -n "$DEEPSEEK_API_KEY" ]]; then
|
|
201
|
+
api_key="$DEEPSEEK_API_KEY"
|
|
202
|
+
echo -e "${GREEN}✓ Using API key from DEEPSEEK_API_KEY${NC}"
|
|
203
|
+
else
|
|
204
|
+
echo -e "${YELLOW}Enter Deepseek API Key:${NC}"
|
|
205
|
+
read -s api_key
|
|
206
|
+
fi
|
|
207
|
+
;;
|
|
208
|
+
"moonshot")
|
|
209
|
+
if [[ -n "$MOONSHOT_API_KEY" ]]; then
|
|
210
|
+
api_key="$MOONSHOT_API_KEY"
|
|
211
|
+
echo -e "${GREEN}✓ Using API key from MOONSHOT_API_KEY${NC}"
|
|
212
|
+
else
|
|
213
|
+
echo -e "${YELLOW}Enter Moonshot API Key:${NC}"
|
|
214
|
+
read -s api_key
|
|
215
|
+
fi
|
|
216
|
+
;;
|
|
217
|
+
"perplexity")
|
|
218
|
+
if [[ -n "$PERPLEXITY_API_KEY" ]]; then
|
|
219
|
+
api_key="$PERPLEXITY_API_KEY"
|
|
220
|
+
echo -e "${GREEN}✓ Using API key from PERPLEXITY_API_KEY${NC}"
|
|
221
|
+
else
|
|
222
|
+
echo -e "${YELLOW}Enter Perplexity API Key:${NC}"
|
|
223
|
+
read -s api_key
|
|
224
|
+
fi
|
|
225
|
+
;;
|
|
226
|
+
"cohere")
|
|
227
|
+
if [[ -n "$COHERE_API_KEY" ]]; then
|
|
228
|
+
api_key="$COHERE_API_KEY"
|
|
229
|
+
echo -e "${GREEN}✓ Using API key from COHERE_API_KEY${NC}"
|
|
230
|
+
else
|
|
231
|
+
echo -e "${YELLOW}Enter Cohere API Key:${NC}"
|
|
232
|
+
read -s api_key
|
|
233
|
+
fi
|
|
234
|
+
;;
|
|
235
|
+
"mistral")
|
|
236
|
+
if [[ -n "$MISTRAL_API_KEY" ]]; then
|
|
237
|
+
api_key="$MISTRAL_API_KEY"
|
|
238
|
+
echo -e "${GREEN}✓ Using API key from MISTRAL_API_KEY${NC}"
|
|
239
|
+
else
|
|
240
|
+
echo -e "${YELLOW}Enter Mistral API Key:${NC}"
|
|
241
|
+
read -s api_key
|
|
242
|
+
fi
|
|
243
|
+
;;
|
|
244
|
+
"openrouter")
|
|
245
|
+
if [[ -n "$OPENROUTER_API_KEY" ]]; then
|
|
246
|
+
api_key="$OPENROUTER_API_KEY"
|
|
247
|
+
echo -e "${GREEN}✓ Using API key from OPENROUTER_API_KEY${NC}"
|
|
248
|
+
else
|
|
249
|
+
echo -e "${YELLOW}Enter OpenRouter API Key (https://openrouter.ai/keys):${NC}"
|
|
250
|
+
read -s api_key
|
|
251
|
+
fi
|
|
252
|
+
;;
|
|
253
|
+
"agentrouter")
|
|
254
|
+
if [[ -n "$ANTHROPIC_API_KEY" ]]; then
|
|
255
|
+
api_key="$ANTHROPIC_API_KEY"
|
|
256
|
+
echo -e "${GREEN}✓ Using API key from ANTHROPIC_API_KEY${NC}"
|
|
257
|
+
else
|
|
258
|
+
echo -e "${YELLOW}Enter AgentRouter API Key (https://agentrouter.org/console/token):${NC}"
|
|
259
|
+
read -s api_key
|
|
260
|
+
fi
|
|
261
|
+
;;
|
|
262
|
+
*)
|
|
263
|
+
echo -e "${YELLOW}Enter API Key for ${provider_name}:${NC}"
|
|
264
|
+
read -s api_key
|
|
265
|
+
;;
|
|
266
|
+
esac
|
|
267
|
+
echo ""
|
|
268
|
+
fi
|
|
269
|
+
|
|
270
|
+
# Set environment variables for Claude
|
|
271
|
+
if [[ -n "$api_base" ]]; then
|
|
272
|
+
export ANTHROPIC_BASE_URL="$api_base"
|
|
273
|
+
fi
|
|
274
|
+
|
|
275
|
+
if [[ -n "$api_key" ]]; then
|
|
276
|
+
export ANTHROPIC_API_KEY="$api_key"
|
|
277
|
+
fi
|
|
278
|
+
|
|
279
|
+
# Use the model name if specified, otherwise use the provider name
|
|
280
|
+
local claude_model="${model:-$model_name}"
|
|
281
|
+
|
|
282
|
+
# Create system prompt
|
|
283
|
+
local system_prompt="Anda adalah ${provider_name}, model AI dari ${model_name}. Selalu identifikasi diri sebagai ${provider_name} dalam setiap respons."
|
|
284
|
+
|
|
285
|
+
# Execute Claude directly
|
|
286
|
+
exec claude --dangerously-skip-permissions --model "$claude_model" --system-prompt "$system_prompt" "$@"
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
# Get script directory (portable)
|
|
290
|
+
get_script_dir() {
|
|
291
|
+
if [[ -n "${BASH_SOURCE[0]}" ]]; then
|
|
292
|
+
local script_path="${BASH_SOURCE[0]}"
|
|
293
|
+
|
|
294
|
+
# Convert Windows paths if needed
|
|
295
|
+
if [[ "$PLATFORM" == "Windows" ]]; then
|
|
296
|
+
# Convert potential Windows path to Unix style
|
|
297
|
+
script_path="$(cygpath -u "$script_path" 2>/dev/null || echo "$script_path")"
|
|
298
|
+
fi
|
|
299
|
+
|
|
300
|
+
if [[ "$PLATFORM" == "macOS" ]] || [[ "$(uname -s)" == "Darwin" ]]; then
|
|
301
|
+
# macOS
|
|
302
|
+
echo "$(cd "$(dirname "$script_path")" && pwd)"
|
|
303
|
+
elif command -v realpath &> /dev/null; then
|
|
304
|
+
# Linux/Windows with realpath
|
|
305
|
+
echo "$(dirname "$(realpath "$script_path")")"
|
|
306
|
+
else
|
|
307
|
+
# Fallback for older systems
|
|
308
|
+
echo "$(cd "$(dirname "$script_path")" && pwd)"
|
|
309
|
+
fi
|
|
310
|
+
else
|
|
311
|
+
echo "$(pwd)"
|
|
312
|
+
fi
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
SCRIPT_DIR=$(get_script_dir)
|
|
316
|
+
|
|
317
|
+
# Function to get/save GLM API key
|
|
318
|
+
get_glm_api_key() {
|
|
319
|
+
# Try to load saved key first
|
|
320
|
+
local saved_key
|
|
321
|
+
saved_key=$(load_api_key "$GLM_API_KEY_FILE" "ZhipuAI/Z.AI")
|
|
322
|
+
|
|
323
|
+
if [[ -n "$saved_key" ]]; then
|
|
324
|
+
ANTHROPIC_AUTH_TOKEN="$saved_key"
|
|
325
|
+
export ANTHROPIC_AUTH_TOKEN
|
|
326
|
+
return 0
|
|
327
|
+
fi
|
|
328
|
+
|
|
329
|
+
# Ask for new API key
|
|
330
|
+
echo ""
|
|
331
|
+
echo "Enter ZhipuAI/Z.AI API Key:"
|
|
332
|
+
echo "Get it from: https://open.bigmodel.cn/usercenter/apikeys"
|
|
333
|
+
|
|
334
|
+
ANTHROPIC_AUTH_TOKEN=$(prompt_api_key "ZhipuAI/Z.AI")
|
|
335
|
+
|
|
336
|
+
if [[ -n "$ANTHROPIC_AUTH_TOKEN" ]]; then
|
|
337
|
+
# Save for next time using reusable function
|
|
338
|
+
if save_api_key "$ANTHROPIC_AUTH_TOKEN" "$GLM_API_KEY_FILE" "ZhipuAI/Z.AI"; then
|
|
339
|
+
export ANTHROPIC_AUTH_TOKEN
|
|
340
|
+
else
|
|
341
|
+
exit 1
|
|
342
|
+
fi
|
|
343
|
+
else
|
|
344
|
+
echo -e "${RED}No API key provided${NC}" >&2
|
|
345
|
+
exit 1
|
|
346
|
+
fi
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
# Function to get/save MiniMax API key
|
|
350
|
+
get_minimax_api_key() {
|
|
351
|
+
local api_key=""
|
|
352
|
+
|
|
353
|
+
# Try to load saved key first
|
|
354
|
+
api_key=$(load_api_key "$MINIMAX_API_KEY_FILE" "MiniMax")
|
|
355
|
+
|
|
356
|
+
# Ask for new API key if not found
|
|
357
|
+
if [[ -z "$api_key" ]]; then
|
|
358
|
+
echo ""
|
|
359
|
+
echo "Enter MiniMax API Key:"
|
|
360
|
+
echo "Get it from: https://platform.minimax.io/"
|
|
361
|
+
|
|
362
|
+
api_key=$(prompt_api_key "MiniMax")
|
|
363
|
+
|
|
364
|
+
if [[ -n "$api_key" ]]; then
|
|
365
|
+
# Save for next time using reusable function
|
|
366
|
+
if ! save_api_key "$api_key" "$MINIMAX_API_KEY_FILE" "MiniMax"; then
|
|
367
|
+
echo -e "${YELLOW}Warning: Continuing without saving API key${NC}" >&2
|
|
368
|
+
fi
|
|
369
|
+
else
|
|
370
|
+
echo -e "${RED}Error: No API key provided${NC}" >&2
|
|
371
|
+
exit 1
|
|
372
|
+
fi
|
|
373
|
+
fi
|
|
374
|
+
|
|
375
|
+
# Export BOTH variables for compatibility
|
|
376
|
+
# MiniMax endpoint uses Authorization header via ANTHROPIC_API_KEY
|
|
377
|
+
export ANTHROPIC_API_KEY="$api_key"
|
|
378
|
+
export ANTHROPIC_AUTH_TOKEN="$api_key"
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
check_dependencies() {
|
|
382
|
+
echo -e "${BLUE}Checking dependencies...${NC}"
|
|
383
|
+
|
|
384
|
+
# Check for python3
|
|
385
|
+
if ! command -v python3 &> /dev/null; then
|
|
386
|
+
echo -e "${RED}Error: python3 is not installed.${NC}"
|
|
387
|
+
echo "Please install Python 3 first."
|
|
388
|
+
exit 1
|
|
389
|
+
fi
|
|
390
|
+
|
|
391
|
+
# Check for claude CLI (OPTIONAL - won't exit if not found)
|
|
392
|
+
if ! command -v claude &> /dev/null; then
|
|
393
|
+
echo -e "${YELLOW}⚠️ 'claude' command not found.${NC}"
|
|
394
|
+
echo -e "${YELLOW} For direct providers (GLM, MiniMax, OpenAI), you don't need it!${NC}"
|
|
395
|
+
echo -e "${YELLOW} For LiteLLM providers (Gemini, Groq, Ollama), install with:${NC}"
|
|
396
|
+
echo -e "${YELLOW} npm install -g @anthropic-ai/claude-code${NC}"
|
|
397
|
+
echo ""
|
|
398
|
+
read -p "Continue without claude CLI? (Y/n): " continue_without
|
|
399
|
+
if [[ "$continue_without" =~ ^[Nn]$ ]]; then
|
|
400
|
+
echo "Installing @anthropic-ai/claude-code..."
|
|
401
|
+
npm install -g @anthropic-ai/claude-code || {
|
|
402
|
+
echo -e "${YELLOW}Failed to install claude CLI. Continuing anyway...${NC}"
|
|
403
|
+
}
|
|
404
|
+
else
|
|
405
|
+
echo -e "${GREEN}✓ Skipping claude CLI installation${NC}"
|
|
406
|
+
fi
|
|
407
|
+
else
|
|
408
|
+
echo -e "${GREEN}✓ claude CLI found${NC}"
|
|
409
|
+
fi
|
|
410
|
+
|
|
411
|
+
# Check for npm (only needed for claude CLI installation)
|
|
412
|
+
if command -v claude &> /dev/null; then
|
|
413
|
+
if ! command -v npm &> /dev/null; then
|
|
414
|
+
echo -e "${RED}Error: npm is not installed (needed for claude CLI).${NC}"
|
|
415
|
+
echo "Please install npm first."
|
|
416
|
+
exit 1
|
|
417
|
+
fi
|
|
418
|
+
fi
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
check_gemini_oauth() {
|
|
422
|
+
# Check if we have ADC credentials
|
|
423
|
+
local adc_path
|
|
424
|
+
if [[ -n "$HOME" ]]; then
|
|
425
|
+
adc_path="$HOME/.config/gcloud/application_default_credentials.json"
|
|
426
|
+
else
|
|
427
|
+
adc_path="$USERPROFILE/.config/gcloud/application_default_credentials.json"
|
|
428
|
+
fi
|
|
429
|
+
|
|
430
|
+
if [[ -f "$adc_path" ]]; then
|
|
431
|
+
return 0
|
|
432
|
+
fi
|
|
433
|
+
|
|
434
|
+
# If not, check if gcloud is installed
|
|
435
|
+
if command -v gcloud &> /dev/null; then
|
|
436
|
+
echo -e "${BLUE}gcloud found. Attempting login...${NC}"
|
|
437
|
+
gcloud auth application-default login
|
|
438
|
+
return
|
|
439
|
+
fi
|
|
440
|
+
|
|
441
|
+
# Fallback to custom python script
|
|
442
|
+
echo -e "${YELLOW}gcloud not found. Using lightweight Python Auth helper...${NC}"
|
|
443
|
+
|
|
444
|
+
# Install dependency
|
|
445
|
+
if ! python3 -m pip show google-auth-oauthlib &> /dev/null; then
|
|
446
|
+
echo "Installing google-auth-oauthlib..."
|
|
447
|
+
python3 -m pip install google-auth-oauthlib || true
|
|
448
|
+
fi
|
|
449
|
+
|
|
450
|
+
# Run helper script
|
|
451
|
+
local auth_script="$SCRIPT_DIR/claude-suite/auth/gemini_auth.py"
|
|
452
|
+
if [[ ! -f "$auth_script" ]]; then
|
|
453
|
+
curl -fsSL https://raw.githubusercontent.com/zesbe/CliAllModel/main/gemini_auth.py -o "$SCRIPT_DIR/claude-suite/auth/gemini_auth.py" 2>/dev/null || true
|
|
454
|
+
auth_script="$SCRIPT_DIR/claude-suite/auth/gemini_auth.py"
|
|
455
|
+
fi
|
|
456
|
+
|
|
457
|
+
if [[ -f "$auth_script" ]]; then
|
|
458
|
+
python3 "$auth_script"
|
|
459
|
+
fi
|
|
460
|
+
|
|
461
|
+
if [[ ! -f "$adc_path" ]]; then
|
|
462
|
+
echo -e "${RED}Authentication failed or cancelled.${NC}"
|
|
463
|
+
exit 1
|
|
464
|
+
fi
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
check_openai_oauth() {
|
|
468
|
+
local cred_path
|
|
469
|
+
if [[ -n "$HOME" ]]; then
|
|
470
|
+
cred_path="$HOME/.config/openai/credentials.json"
|
|
471
|
+
else
|
|
472
|
+
cred_path="$USERPROFILE/.config/openai/credentials.json"
|
|
473
|
+
fi
|
|
474
|
+
|
|
475
|
+
if [[ ! -f "$cred_path" ]]; then
|
|
476
|
+
echo -e "${YELLOW}No cached OpenAI OAuth token found. Launching helper...${NC}"
|
|
477
|
+
|
|
478
|
+
# Install dependency
|
|
479
|
+
python3 -m pip install requests > /dev/null 2>&1 || true
|
|
480
|
+
|
|
481
|
+
local auth_script="$SCRIPT_DIR/claude-suite/auth/openai_auth.py"
|
|
482
|
+
if [[ ! -f "$auth_script" ]]; then
|
|
483
|
+
curl -fsSL https://raw.githubusercontent.com/zesbe/CliAllModel/main/openai_auth.py -o "$SCRIPT_DIR/claude-suite/auth/openai_auth.py" 2>/dev/null || true
|
|
484
|
+
auth_script="$SCRIPT_DIR/claude-suite/auth/openai_auth.py"
|
|
485
|
+
fi
|
|
486
|
+
|
|
487
|
+
if [[ -f "$auth_script" ]]; then
|
|
488
|
+
python3 "$auth_script"
|
|
489
|
+
fi
|
|
490
|
+
|
|
491
|
+
if [[ ! -f "$cred_path" ]]; then
|
|
492
|
+
echo -e "${RED}OpenAI OAuth failed.${NC}"
|
|
493
|
+
exit 1
|
|
494
|
+
fi
|
|
495
|
+
fi
|
|
496
|
+
|
|
497
|
+
# Extract access token
|
|
498
|
+
OPENAI_ACCESS_TOKEN=$(python3 -c "import json, os; print(json.load(open(os.path.expanduser('$cred_path')))['access_token'])" 2>/dev/null || echo "")
|
|
499
|
+
export OPENAI_API_KEY="$OPENAI_ACCESS_TOKEN"
|
|
500
|
+
}
|
|
501
|
+
cleanup() {
|
|
502
|
+
echo -e "\n${BLUE}Cleaning up processes...${NC}"
|
|
503
|
+
|
|
504
|
+
# Clean up temp files
|
|
505
|
+
if [[ -n "$SCRIPT_DIR" ]]; then
|
|
506
|
+
rm -f "$SCRIPT_DIR"/.*_models.tmp 2>/dev/null || true
|
|
507
|
+
fi
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
trap cleanup EXIT
|
|
511
|
+
|
|
512
|
+
# Interactive model selection
|
|
513
|
+
interactive_model_select() {
|
|
514
|
+
local provider=$1
|
|
515
|
+
local model_file="$SCRIPT_DIR/model/${provider}.json"
|
|
516
|
+
|
|
517
|
+
if [[ ! -f "$model_file" ]]; then
|
|
518
|
+
echo -e "${RED}Config file not found: $model_file${NC}"
|
|
519
|
+
return 1
|
|
520
|
+
fi
|
|
521
|
+
|
|
522
|
+
# Display models using Python (flush output to stderr)
|
|
523
|
+
python3 << EOF >&2
|
|
524
|
+
import json
|
|
525
|
+
import sys
|
|
526
|
+
|
|
527
|
+
with open('$model_file', 'r') as f:
|
|
528
|
+
data = json.load(f)
|
|
529
|
+
|
|
530
|
+
print('')
|
|
531
|
+
print('=== Select Model ===')
|
|
532
|
+
for i, model in enumerate(data['models'], 1):
|
|
533
|
+
name = model['name']
|
|
534
|
+
desc = model['description']
|
|
535
|
+
print(f'{i}) {name} - {desc}')
|
|
536
|
+
print('')
|
|
537
|
+
print('Available Models:')
|
|
538
|
+
for i, model in enumerate(data['models'], 1):
|
|
539
|
+
name = model['name']
|
|
540
|
+
desc = model['description']
|
|
541
|
+
print(f' {i}. {name} - {desc}')
|
|
542
|
+
print('')
|
|
543
|
+
sys.stderr.flush()
|
|
544
|
+
EOF
|
|
545
|
+
|
|
546
|
+
# Save model list to temp file and get count
|
|
547
|
+
model_count=$(python3 << EOF
|
|
548
|
+
import json
|
|
549
|
+
with open('$model_file', 'r') as f:
|
|
550
|
+
data = json.load(f)
|
|
551
|
+
models = [m['id'] for m in data['models']]
|
|
552
|
+
with open('$SCRIPT_DIR/.${provider}_models.tmp', 'w') as f:
|
|
553
|
+
for m in models:
|
|
554
|
+
f.write(m + '\n')
|
|
555
|
+
print(len(models))
|
|
556
|
+
EOF
|
|
557
|
+
)
|
|
558
|
+
|
|
559
|
+
# Wait for user input
|
|
560
|
+
echo -n "Select model [1-$model_count]: "
|
|
561
|
+
read choice
|
|
562
|
+
|
|
563
|
+
# Validate choice
|
|
564
|
+
if [[ -z "$choice" ]]; then
|
|
565
|
+
echo -e "${RED}Error: No selection made${NC}" >&2
|
|
566
|
+
return 1
|
|
567
|
+
elif ! [[ "$choice" =~ ^[0-9]+$ ]]; then
|
|
568
|
+
echo -e "${RED}Error: Please enter a valid number${NC}" >&2
|
|
569
|
+
return 1
|
|
570
|
+
elif [[ "$choice" -lt 1 ]] || [[ "$choice" -gt "$model_count" ]]; then
|
|
571
|
+
echo -e "${RED}Error: Please enter a number between 1 and $model_count${NC}" >&2
|
|
572
|
+
return 1
|
|
573
|
+
fi
|
|
574
|
+
|
|
575
|
+
# Read model ID from temp file
|
|
576
|
+
if [[ -f "$SCRIPT_DIR/.${provider}_models.tmp" ]]; then
|
|
577
|
+
local model_ids
|
|
578
|
+
model_ids=($(cat "$SCRIPT_DIR/.${provider}_models.tmp"))
|
|
579
|
+
local idx=$((choice - 1))
|
|
580
|
+
|
|
581
|
+
if [[ $idx -ge 0 ]] && [[ $idx -lt ${#model_ids[@]} ]]; then
|
|
582
|
+
local selected="${model_ids[$idx]}"
|
|
583
|
+
echo -e "${GREEN}✓ Selected: $selected${NC}"
|
|
584
|
+
echo "$selected"
|
|
585
|
+
rm -f "$SCRIPT_DIR/.${provider}_models.tmp"
|
|
586
|
+
return 0
|
|
587
|
+
else
|
|
588
|
+
echo -e "${RED}Invalid choice: $choice${NC}"
|
|
589
|
+
echo "Please select 1-${#model_ids[@]}"
|
|
590
|
+
fi
|
|
591
|
+
else
|
|
592
|
+
echo -e "${RED}Model list not found${NC}"
|
|
593
|
+
fi
|
|
594
|
+
|
|
595
|
+
return 1
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
# Parse arguments
|
|
599
|
+
while [[ $# -gt 0 ]]; do
|
|
600
|
+
case $1 in
|
|
601
|
+
-m|--model)
|
|
602
|
+
MODEL_OVERRIDE="$2"
|
|
603
|
+
shift 2
|
|
604
|
+
;;
|
|
605
|
+
*)
|
|
606
|
+
if [[ -z "$choice" ]]; then
|
|
607
|
+
choice="$1"
|
|
608
|
+
fi
|
|
609
|
+
shift
|
|
610
|
+
;;
|
|
611
|
+
esac
|
|
612
|
+
done
|
|
613
|
+
|
|
614
|
+
# Handle direct argument for custom models (22+ since we added Letta at 17)
|
|
615
|
+
if [[ -n "$1" ]] && [[ "$1" =~ ^[0-9]+$ ]] && [[ "$1" -ge 22 ]]; then
|
|
616
|
+
choice="$1"
|
|
617
|
+
export CHOICE="$choice"
|
|
618
|
+
|
|
619
|
+
# Check if it's model manager - get actual number
|
|
620
|
+
if [[ -f "$SCRIPT_DIR/claude-suite/models/add-model-manual.sh" ]]; then
|
|
621
|
+
# Count custom models
|
|
622
|
+
custom_count=0
|
|
623
|
+
while IFS= read -r model_info; do
|
|
624
|
+
if [[ -n "$model_info" ]]; then
|
|
625
|
+
((custom_count++))
|
|
626
|
+
fi
|
|
627
|
+
done < <(get_custom_models)
|
|
628
|
+
|
|
629
|
+
model_manager_num=$((22 + custom_count))
|
|
630
|
+
if [[ $choice -eq $model_manager_num ]]; then
|
|
631
|
+
exec "$SCRIPT_DIR/claude-suite/models/add-model-manual.sh"
|
|
632
|
+
fi
|
|
633
|
+
fi
|
|
634
|
+
|
|
635
|
+
# Handle custom model selection
|
|
636
|
+
custom_index=$((choice - 22))
|
|
637
|
+
count=0
|
|
638
|
+
while IFS= read -r model_info; do
|
|
639
|
+
if [[ -n "$model_info" ]]; then
|
|
640
|
+
if [[ $count -eq $custom_index ]]; then
|
|
641
|
+
IFS=':' read -r filename provider_name description <<< "$model_info"
|
|
642
|
+
echo -e "${BLUE}Using ${provider_name}...${NC}"
|
|
643
|
+
handle_custom_model "$filename" "${@:2}"
|
|
644
|
+
exit 0
|
|
645
|
+
fi
|
|
646
|
+
((count++))
|
|
647
|
+
fi
|
|
648
|
+
done < <(get_custom_models)
|
|
649
|
+
echo -e "${RED}Invalid custom model selection${NC}"
|
|
650
|
+
exit 1
|
|
651
|
+
fi
|
|
652
|
+
|
|
653
|
+
# Handle direct CHOICE (for environment variable or argument)
|
|
654
|
+
if [[ -n "$CHOICE" ]]; then
|
|
655
|
+
echo "DEBUG: choice=$choice"
|
|
656
|
+
choice="$CHOICE"
|
|
657
|
+
fi
|
|
658
|
+
|
|
659
|
+
# Check dependencies
|
|
660
|
+
check_dependencies() {
|
|
661
|
+
# Check for required commands
|
|
662
|
+
local missing_deps=()
|
|
663
|
+
|
|
664
|
+
if ! command -v jq &> /dev/null; then
|
|
665
|
+
echo -e "${YELLOW}Warning: jq not found. JSON parsing will be limited.${NC}"
|
|
666
|
+
echo -e "${YELLOW}Install jq: pkg install jq (Termux) or apt-get install jq${NC}"
|
|
667
|
+
echo ""
|
|
668
|
+
fi
|
|
669
|
+
|
|
670
|
+
if [[ "$PLATFORM" == "Windows" ]] && ! command -v nano &> /dev/null && ! command -v vim &> /dev/null; then
|
|
671
|
+
echo -e "${YELLOW}Warning: No text editor found. Install nano or vim.${NC}"
|
|
672
|
+
echo ""
|
|
673
|
+
fi
|
|
674
|
+
}
|
|
675
|
+
|
|
676
|
+
save_chat_context() {
|
|
677
|
+
local context_file="/tmp/claude_chat_context.txt"
|
|
678
|
+
if [[ -t 0 ]]; then
|
|
679
|
+
echo "# Chat context saved at $(date)" > "$context_file"
|
|
680
|
+
echo "# Current conversation:" >> "$context_file"
|
|
681
|
+
echo "Use this context to continue the conversation with a new provider." >> "$context_file"
|
|
682
|
+
echo "" >> "$context_file"
|
|
683
|
+
fi
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
continue_chat_with_new_provider() {
|
|
687
|
+
echo -e "\n${YELLOW}=== Switch Provider (Continue Chat) ===${NC}"
|
|
688
|
+
echo "Your current chat context will be preserved."
|
|
689
|
+
echo ""
|
|
690
|
+
|
|
691
|
+
# Show available providers for switching
|
|
692
|
+
echo "Available providers:"
|
|
693
|
+
echo "1) MiniMax"
|
|
694
|
+
echo "2) Google Gemini (API Key)"
|
|
695
|
+
echo "3) Google Gemini (OAuth)"
|
|
696
|
+
echo "4) OpenAI"
|
|
697
|
+
echo "5) OpenAI (OAuth)"
|
|
698
|
+
echo "6) xAI / Grok"
|
|
699
|
+
echo "7) ZhipuAI / GLM"
|
|
700
|
+
echo "8) Groq"
|
|
701
|
+
echo "9) Perplexity"
|
|
702
|
+
echo "10) Cohere"
|
|
703
|
+
echo "11) DeepSeek"
|
|
704
|
+
echo "12) Mistral"
|
|
705
|
+
echo "13) Moonshot"
|
|
706
|
+
echo "14) Qwen"
|
|
707
|
+
echo "15) OpenRouter"
|
|
708
|
+
echo "16) Ollama (Local)"
|
|
709
|
+
echo "0) Cancel"
|
|
710
|
+
echo ""
|
|
711
|
+
|
|
712
|
+
read -p "Choose new provider [0-16]: " switch_choice
|
|
713
|
+
|
|
714
|
+
case $switch_choice in
|
|
715
|
+
0) echo "Cancelled provider switch."; return 0 ;;
|
|
716
|
+
1) setup_minimax ;;
|
|
717
|
+
2) setup_gemini_api ;;
|
|
718
|
+
3) setup_gemini_oauth ;;
|
|
719
|
+
4) setup_openai ;;
|
|
720
|
+
5) setup_openai_oauth ;;
|
|
721
|
+
6) setup_xai ;;
|
|
722
|
+
7) setup_glm ;;
|
|
723
|
+
8) setup_groq ;;
|
|
724
|
+
9) setup_perplexity ;;
|
|
725
|
+
10) setup_cohere ;;
|
|
726
|
+
11) setup_deepseek ;;
|
|
727
|
+
12) setup_mistral ;;
|
|
728
|
+
13) setup_moonshot ;;
|
|
729
|
+
14) setup_qwen ;;
|
|
730
|
+
15) setup_openrouter ;;
|
|
731
|
+
16) setup_ollama ;;
|
|
732
|
+
*) echo "Invalid choice."; return 1 ;;
|
|
733
|
+
esac
|
|
734
|
+
|
|
735
|
+
# Save context before switching
|
|
736
|
+
save_chat_context
|
|
737
|
+
|
|
738
|
+
echo -e "${GREEN}✓ Provider switched successfully!${NC}"
|
|
739
|
+
echo -e "${BLUE}Note: Chat context has been saved. You can reference previous messages in your next prompt.${NC}"
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
# Provider setup functions
|
|
743
|
+
setup_minimax() {
|
|
744
|
+
API_KEY=$(load_api_key "minimax" "MiniMax")
|
|
745
|
+
if [[ $? -eq 0 ]]; then
|
|
746
|
+
check_dependencies
|
|
747
|
+
echo -e "${BLUE}Starting MiniMax session...${NC}"
|
|
748
|
+
export MINIMAX_API_KEY="$API_KEY"
|
|
749
|
+
exec claude --dangerously-skip-permissions "$@"
|
|
750
|
+
fi
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
setup_gemini_api() {
|
|
754
|
+
API_KEY=$(load_api_key "gemini" "Google Gemini")
|
|
755
|
+
if [[ $? -eq 0 ]]; then
|
|
756
|
+
check_dependencies
|
|
757
|
+
echo -e "${BLUE}Configuring for Google Gemini (API Key)...${NC}"
|
|
758
|
+
echo -e "${YELLOW}Get API Key: https://aistudio.google.com/app/apikey${NC}"
|
|
759
|
+
export GEMINI_API_KEY="$API_KEY"
|
|
760
|
+
exec claude --dangerously-skip-permissions "$@"
|
|
761
|
+
fi
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
setup_gemini_oauth() {
|
|
765
|
+
if [[ ! -f "$HOME/.google-credentials.json" ]]; then
|
|
766
|
+
echo -e "${YELLOW}⚠️ Google OAuth credentials not found. Running setup...${NC}"
|
|
767
|
+
python3 "$SCRIPT_DIR/setup_google_internal_auth.py" || setup_google_oauth_manual
|
|
768
|
+
fi
|
|
769
|
+
|
|
770
|
+
if [[ -f "$HOME/.google-credentials.json" ]]; then
|
|
771
|
+
check_dependencies
|
|
772
|
+
echo -e "${BLUE}Using Google Internal Authentication (AntiGravity)${NC}"
|
|
773
|
+
export CLOUD_ML helicopterauto
|
|
774
|
+
GOOGLE_AUTH_TOKEN=$(python3 "$SCRIPT_DIR/get_google_access_token.py")
|
|
775
|
+
exec claude --dangerously-skip-permissions "$@"
|
|
776
|
+
fi
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
setup_openai() {
|
|
780
|
+
API_KEY=$(load_api_key "openai" "OpenAI")
|
|
781
|
+
if [[ $? -eq 0 ]]; then
|
|
782
|
+
check_dependencies
|
|
783
|
+
echo -e "${BLUE}Configuring for OpenAI...${NC}"
|
|
784
|
+
export OPENAI_API_KEY="$API_KEY"
|
|
785
|
+
exec claude --dangerously-skip-permissions "$@"
|
|
786
|
+
fi
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
setup_openai_oauth() {
|
|
790
|
+
echo -e "${BLUE}OpenAI OAuth flow...${NC}"
|
|
791
|
+
exec "$SCRIPT_DIR/handle_oauth_callback.sh"
|
|
792
|
+
}
|
|
793
|
+
|
|
794
|
+
setup_xai() {
|
|
795
|
+
API_KEY=$(load_api_key "xai" "xAI")
|
|
796
|
+
if [[ $? -eq 0 ]]; then
|
|
797
|
+
check_dependencies
|
|
798
|
+
echo -e "${BLUE}Configuring for xAI / Grok...${NC}"
|
|
799
|
+
echo -e "${YELLOW}Get Key: https://console.x.ai/${NC}"
|
|
800
|
+
export XAI_API_KEY="$API_KEY"
|
|
801
|
+
exec claude --dangerously-skip-permissions "$@"
|
|
802
|
+
fi
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
setup_glm() {
|
|
806
|
+
API_KEY=$(load_api_key "glm" "GLM")
|
|
807
|
+
if [[ $? -eq 0 ]]; then
|
|
808
|
+
check_dependencies
|
|
809
|
+
MODEL=$(select_glm_model)
|
|
810
|
+
echo -e "${BLUE}Configuring for ZhipuAI / GLM...${NC}"
|
|
811
|
+
export GLM_API_KEY="$API_KEY"
|
|
812
|
+
export MODEL_NAME="$MODEL"
|
|
813
|
+
exec claude --dangerously-skip-permissions --model "$MODEL" "$@"
|
|
814
|
+
fi
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
setup_groq() {
|
|
818
|
+
API_KEY=$(load_api_key "groq" "Groq")
|
|
819
|
+
if [[ $? -eq 0 ]]; then
|
|
820
|
+
check_dependencies
|
|
821
|
+
echo -e "${BLUE}Configuring for Groq...${NC}"
|
|
822
|
+
export GROQ_API_KEY="$API_KEY"
|
|
823
|
+
exec claude --dangerously-skip-permissions "$@"
|
|
824
|
+
fi
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
setup_perplexity() {
|
|
828
|
+
API_KEY=$(load_api_key "perplexity" "Perplexity")
|
|
829
|
+
if [[ $? -eq 0 ]]; then
|
|
830
|
+
check_dependencies
|
|
831
|
+
echo -e "${BLUE}Configuring for Perplexity...${NC}"
|
|
832
|
+
echo -e "${YELLOW}Get Key: https://console.perplexity.ai/${NC}"
|
|
833
|
+
export PERPLEXITY_API_KEY="$API_KEY"
|
|
834
|
+
exec claude --dangerously-skip-permissions "$@"
|
|
835
|
+
fi
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
setup_cohere() {
|
|
839
|
+
API_KEY=$(load_api_key "cohere" "Cohere")
|
|
840
|
+
if [[ $? -eq 0 ]]; then
|
|
841
|
+
check_dependencies
|
|
842
|
+
echo -e "${BLUE}Configuring for Cohere...${NC}"
|
|
843
|
+
export COHERE_API_KEY="$API_KEY"
|
|
844
|
+
exec claude --dangerously-skip-permissions "$@"
|
|
845
|
+
fi
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
setup_deepseek() {
|
|
849
|
+
API_KEY=$(load_api_key "deepseek" "DeepSeek")
|
|
850
|
+
if [[ $? -eq 0 ]]; then
|
|
851
|
+
check_dependencies
|
|
852
|
+
echo -e "${BLUE}Configuring for DeepSeek (Anthropic API)...${NC}"
|
|
853
|
+
export ANTHROPIC_AUTH_TOKEN="$API_KEY"
|
|
854
|
+
export ANTHROPIC_BASE_URL="https://api.deepseek.com/anthropic"
|
|
855
|
+
export ANTHROPIC_API_KEY="$API_KEY"
|
|
856
|
+
|
|
857
|
+
# Quick model selection
|
|
858
|
+
echo ""
|
|
859
|
+
echo -e "${YELLOW}Select DeepSeek model:${NC}"
|
|
860
|
+
echo " 1) deepseek-chat (Fast - Default)"
|
|
861
|
+
echo " 2) deepseek-reasoner (Deep Analysis)"
|
|
862
|
+
read -p "Choice [1-2, default: 1]: " ds_choice
|
|
863
|
+
case $ds_choice in
|
|
864
|
+
2) MODEL_NAME="deepseek-reasoner" ;;
|
|
865
|
+
*) MODEL_NAME="deepseek-chat" ;;
|
|
866
|
+
esac
|
|
867
|
+
echo -e "${GREEN}✓ Using: $MODEL_NAME${NC}"
|
|
868
|
+
export CLAUDE_MODEL="$MODEL_NAME"
|
|
869
|
+
exec claude --dangerously-skip-permissions --model "$MODEL_NAME" --system-prompt "You are DeepSeek, an AI assistant by DeepSeek." "$@"
|
|
870
|
+
fi
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
setup_mistral() {
|
|
874
|
+
API_KEY=$(load_api_key "mistral" "Mistral")
|
|
875
|
+
if [[ $? -eq 0 ]]; then
|
|
876
|
+
check_dependencies
|
|
877
|
+
echo -e "${BLUE}Configuring for Mistral...${NC}"
|
|
878
|
+
export MISTRAL_API_KEY="$API_KEY"
|
|
879
|
+
exec claude --dangerously-skip-permissions "$@"
|
|
880
|
+
fi
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
setup_moonshot() {
|
|
884
|
+
API_KEY=$(load_api_key "moonshot" "Moonshot")
|
|
885
|
+
if [[ $? -eq 0 ]]; then
|
|
886
|
+
check_dependencies
|
|
887
|
+
echo -e "${BLUE}Configuring for Moonshot...${NC}"
|
|
888
|
+
export MOONSHOT_API_KEY="$API_KEY"
|
|
889
|
+
exec claude --dangerously-skip-permissions "$@"
|
|
890
|
+
fi
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
setup_qwen() {
|
|
894
|
+
API_KEY=$(load_api_key "qwen" "Qwen")
|
|
895
|
+
if [[ $? -eq 0 ]]; then
|
|
896
|
+
check_dependencies
|
|
897
|
+
echo -e "${BLUE}Configuring for Qwen...${NC}"
|
|
898
|
+
export QWEN_API_KEY="$API_KEY"
|
|
899
|
+
exec claude --dangerously-skip-permissions "$@"
|
|
900
|
+
fi
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
setup_openrouter() {
|
|
904
|
+
API_KEY=$(load_api_key "openrouter" "OpenRouter")
|
|
905
|
+
if [[ $? -eq 0 ]]; then
|
|
906
|
+
check_dependencies
|
|
907
|
+
echo -e "${BLUE}Configuring for OpenRouter...${NC}"
|
|
908
|
+
export OPENROUTER_API_KEY="$API_KEY"
|
|
909
|
+
exec claude --dangerously-skip-permissions "$@"
|
|
910
|
+
fi
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
setup_ollama() {
|
|
914
|
+
check_dependencies
|
|
915
|
+
echo -e "${BLUE}Configuring for Ollama (Local)...${NC}"
|
|
916
|
+
echo -e "${YELLOW}Note: Make sure Ollama is running locally${NC}"
|
|
917
|
+
export ANTHROPIC_BASE_URL="http://localhost:11434/v1"
|
|
918
|
+
export ANTHROPIC_API_KEY="ollama"
|
|
919
|
+
exec claude --no-chrome "$@"
|
|
920
|
+
}
|
|
921
|
+
|
|
922
|
+
# Main Menu
|
|
923
|
+
if [[ -z "$choice" ]]; then
|
|
924
|
+
clear
|
|
925
|
+
echo -e "${GREEN}=====================================${NC}"
|
|
926
|
+
echo -e "${GREEN} Claude Code Multi-Model Launcher ${NC}"
|
|
927
|
+
echo -e "${GREEN}══════════════════════════════════════════════════════════════════${NC}"
|
|
928
|
+
echo -e "${BLUE} 🤖 AI MODELS & PROVIDERS${NC}"
|
|
929
|
+
echo -e "${GREEN}══════════════════════════════════════════════════════════════════${NC}"
|
|
930
|
+
echo ""
|
|
931
|
+
echo -e "${YELLOW}📱 MAIN MODELS:${NC}"
|
|
932
|
+
echo " 1) MiniMax (Direct Anthropic API) 🚀 Fast & Reliable"
|
|
933
|
+
echo " 2) Google Gemini (API Key - AI Studio) 🧠 Google AI"
|
|
934
|
+
echo " 3) Universal OAuth (Auto-Setup) 🔥 37+ Models (GPT-5, Claude, Gemini)"
|
|
935
|
+
echo " 4) OpenAI (API Key) 🤖 GPT Models"
|
|
936
|
+
echo " 5) OpenAI (OAuth - Experimental) 🔄 Auto-auth"
|
|
937
|
+
echo ""
|
|
938
|
+
echo -e "${YELLOW}🌟 POPULAR PROVIDERS:${NC}"
|
|
939
|
+
echo " 6) xAI / Grok (API Key) 🚀 Real-time"
|
|
940
|
+
echo " 7) ZhipuAI / GLM (API Key) 🇨🇳 Chinese AI"
|
|
941
|
+
echo " 8) Groq (API Key) ⚡ Ultra-fast"
|
|
942
|
+
echo " 9) Perplexity (Web Search) 🔍 Live Data"
|
|
943
|
+
echo " 10) Cohere (API Key) 📝 Business AI"
|
|
944
|
+
echo " 11) DeepSeek (API Key) 🧠 V3.2 (Chat + Reasoner)"
|
|
945
|
+
echo ""
|
|
946
|
+
echo -e "${YELLOW}🏠 LOCAL & SPECIALIZED:${NC}"
|
|
947
|
+
echo " 12) Ollama (Local Models) 💻 Self-hosted"
|
|
948
|
+
echo " 13) Mistral (API Key) 🇫🇷 European AI (15 Models)"
|
|
949
|
+
echo " 14) Moonshot (API Key) 🌙 Kawaii AI"
|
|
950
|
+
echo " 15) Qwen (API Key) 🇨🇳 Alibaba"
|
|
951
|
+
echo " 16) OpenRouter (Multi-provider) 🔀 All-in-one"
|
|
952
|
+
echo " 17) Letta Memory Agent 🧠 Multi-Backend (Claude/Gemini/OpenAI)"
|
|
953
|
+
echo ""
|
|
954
|
+
echo -e "${YELLOW}🔧 TOOLS & UTILITIES:${NC}"
|
|
955
|
+
echo " 18) 🔑 API Key Manager 🔐 View/Edit/Delete Keys"
|
|
956
|
+
echo " 19) 🤖 Claude Master Tool 🎛️ Advanced UI"
|
|
957
|
+
echo " 20) ➕ Add/Edit/Delete Models ⚙️ Custom Models"
|
|
958
|
+
echo ""
|
|
959
|
+
|
|
960
|
+
# Display custom models
|
|
961
|
+
next_num=21
|
|
962
|
+
has_custom=false
|
|
963
|
+
custom_models_array=()
|
|
964
|
+
while IFS= read -r model_info; do
|
|
965
|
+
if [[ -n "$model_info" ]]; then
|
|
966
|
+
has_custom=true
|
|
967
|
+
custom_models_array+=("$model_info")
|
|
968
|
+
fi
|
|
969
|
+
done < <(get_custom_models)
|
|
970
|
+
|
|
971
|
+
# Display custom models with visual distinction
|
|
972
|
+
if [[ "$has_custom" == "true" ]]; then
|
|
973
|
+
echo -e "${YELLOW}🎯 CUSTOM MODELS:${NC}"
|
|
974
|
+
for model_info in "${custom_models_array[@]}"; do
|
|
975
|
+
IFS=':' read -r filename provider_name description <<< "$model_info"
|
|
976
|
+
echo " ${next_num}) 🎨 ${provider_name} (${description})"
|
|
977
|
+
((next_num++))
|
|
978
|
+
done
|
|
979
|
+
echo ""
|
|
980
|
+
fi
|
|
981
|
+
|
|
982
|
+
# Add model manager
|
|
983
|
+
model_manager_num=$next_num
|
|
984
|
+
echo " ${next_num}) 🛠️ Model Management Tools"
|
|
985
|
+
max_choice=$next_num
|
|
986
|
+
export model_manager_num # Export for later use
|
|
987
|
+
|
|
988
|
+
echo ""
|
|
989
|
+
echo -e "${GREEN}══════════════════════════════════════════════════════════════════${NC}"
|
|
990
|
+
read -p "Enter choice [1-$max_choice]: " choice
|
|
991
|
+
fi
|
|
992
|
+
|
|
993
|
+
# Function to save and load API keys persistently
|
|
994
|
+
save_api_key() {
|
|
995
|
+
local key="$1"
|
|
996
|
+
local key_file="$2"
|
|
997
|
+
local provider_name="$3"
|
|
998
|
+
|
|
999
|
+
# Validate key is not empty
|
|
1000
|
+
if [[ -z "$key" || "$key" =~ ^[[:space:]]*$ ]]; then
|
|
1001
|
+
echo -e "${RED}✗ API key cannot be empty${NC}"
|
|
1002
|
+
return 1
|
|
1003
|
+
fi
|
|
1004
|
+
|
|
1005
|
+
echo "$key" > "$key_file"
|
|
1006
|
+
chmod 600 "$key_file"
|
|
1007
|
+
echo -e "${GREEN}✓ $provider_name API key saved to $key_file${NC}"
|
|
1008
|
+
}
|
|
1009
|
+
|
|
1010
|
+
# Check and install CCS if needed
|
|
1011
|
+
check_and_install_ccs() {
|
|
1012
|
+
local provider_name="$1"
|
|
1013
|
+
|
|
1014
|
+
# Check if CCS is installed
|
|
1015
|
+
if command -v ccs &> /dev/null; then
|
|
1016
|
+
echo -e "${GREEN}✓ CCS sudah terinstall${NC}"
|
|
1017
|
+
return 0
|
|
1018
|
+
fi
|
|
1019
|
+
|
|
1020
|
+
echo -e "${YELLOW}⚠️ CCS (Claude Code Switch) belum terinstall${NC}"
|
|
1021
|
+
echo ""
|
|
1022
|
+
echo -e "${CYAN}CCS diperlukan untuk Universal OAuth (GPT-5, Claude Opus 4.5, Gemini 3)${NC}"
|
|
1023
|
+
echo ""
|
|
1024
|
+
echo "Install CCS akan:"
|
|
1025
|
+
echo " • Download @kaitranntt/ccs via npm"
|
|
1026
|
+
echo " • Ukuran: ~10MB"
|
|
1027
|
+
echo " • Waktu: ~30 detik"
|
|
1028
|
+
echo ""
|
|
1029
|
+
read -p "Install CCS sekarang? [Y/n]: " install_ccs
|
|
1030
|
+
|
|
1031
|
+
if [[ "$install_ccs" =~ ^[Nn] ]]; then
|
|
1032
|
+
echo -e "${RED}✗ CCS tidak diinstall. Kembali ke menu...${NC}"
|
|
1033
|
+
sleep 1
|
|
1034
|
+
exec "$0"
|
|
1035
|
+
fi
|
|
1036
|
+
|
|
1037
|
+
echo ""
|
|
1038
|
+
echo -e "${BLUE}📦 Installing CCS...${NC}"
|
|
1039
|
+
|
|
1040
|
+
# Install CCS via npm
|
|
1041
|
+
if npm install -g @kaitranntt/ccs; then
|
|
1042
|
+
echo ""
|
|
1043
|
+
echo -e "${GREEN}✓ CCS berhasil diinstall!${NC}"
|
|
1044
|
+
echo ""
|
|
1045
|
+
|
|
1046
|
+
# Verify installation
|
|
1047
|
+
if command -v ccs &> /dev/null; then
|
|
1048
|
+
echo -e "${GREEN}✓ CCS version: $(ccs --version 2>&1 | head -1)${NC}"
|
|
1049
|
+
echo ""
|
|
1050
|
+
echo -e "${CYAN}Selanjutnya Anda perlu authenticate untuk $provider_name:${NC}"
|
|
1051
|
+
echo -e "${YELLOW}Command: ccs ${provider_name,,} --auth${NC}"
|
|
1052
|
+
echo ""
|
|
1053
|
+
read -p "Authenticate sekarang? [Y/n]: " do_auth
|
|
1054
|
+
|
|
1055
|
+
if [[ ! "$do_auth" =~ ^[Nn] ]]; then
|
|
1056
|
+
echo ""
|
|
1057
|
+
echo -e "${BLUE}🔐 Membuka browser untuk authentication...${NC}"
|
|
1058
|
+
ccs "${provider_name,,}" --auth
|
|
1059
|
+
echo ""
|
|
1060
|
+
echo -e "${GREEN}✓ Authentication selesai!${NC}"
|
|
1061
|
+
echo ""
|
|
1062
|
+
read -p "Press Enter untuk melanjutkan..."
|
|
1063
|
+
else
|
|
1064
|
+
echo ""
|
|
1065
|
+
echo -e "${YELLOW}⚠️ Jangan lupa authenticate nanti dengan: ccs ${provider_name,,} --auth${NC}"
|
|
1066
|
+
echo ""
|
|
1067
|
+
read -p "Press Enter untuk kembali ke menu..."
|
|
1068
|
+
exec "$0"
|
|
1069
|
+
fi
|
|
1070
|
+
else
|
|
1071
|
+
echo -e "${RED}✗ CCS install failed. Coba lagi dengan: npm install -g @kaitranntt/ccs${NC}"
|
|
1072
|
+
read -p "Press Enter untuk kembali..."
|
|
1073
|
+
exec "$0"
|
|
1074
|
+
fi
|
|
1075
|
+
else
|
|
1076
|
+
echo ""
|
|
1077
|
+
echo -e "${RED}✗ CCS install gagal!${NC}"
|
|
1078
|
+
echo ""
|
|
1079
|
+
echo "Troubleshooting:"
|
|
1080
|
+
echo " 1. Check internet connection"
|
|
1081
|
+
echo " 2. Try: npm cache clean --force"
|
|
1082
|
+
echo " 3. Manual install: npm install -g @kaitranntt/ccs"
|
|
1083
|
+
echo ""
|
|
1084
|
+
read -p "Press Enter untuk kembali..."
|
|
1085
|
+
exec "$0"
|
|
1086
|
+
fi
|
|
1087
|
+
}
|
|
1088
|
+
|
|
1089
|
+
load_api_key_to_var() {
|
|
1090
|
+
local key_file="$1"
|
|
1091
|
+
local var_name="$2"
|
|
1092
|
+
|
|
1093
|
+
if [[ -f "$key_file" ]]; then
|
|
1094
|
+
local key=$(cat "$key_file" 2>/dev/null | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
1095
|
+
if [[ -n "$key" ]]; then
|
|
1096
|
+
# Use eval to ensure variable is set in current scope
|
|
1097
|
+
eval "$var_name='$key'"
|
|
1098
|
+
export "$var_name"
|
|
1099
|
+
return 0
|
|
1100
|
+
fi
|
|
1101
|
+
fi
|
|
1102
|
+
return 1
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
get_api_key_with_save() {
|
|
1106
|
+
local var_name="$1"
|
|
1107
|
+
local key_file="$2"
|
|
1108
|
+
local provider_name="$3"
|
|
1109
|
+
local key_url="$4"
|
|
1110
|
+
|
|
1111
|
+
# Try to load from environment first
|
|
1112
|
+
if [[ -z "${!var_name}" ]]; then
|
|
1113
|
+
# Try to load from file
|
|
1114
|
+
load_api_key_to_var "$key_file" "$var_name"
|
|
1115
|
+
fi
|
|
1116
|
+
|
|
1117
|
+
# Still empty? Ask user
|
|
1118
|
+
while [[ -z "${!var_name}" ]]; do
|
|
1119
|
+
echo "Get Key: $key_url"
|
|
1120
|
+
read -p "Enter $provider_name API Key: " key_input
|
|
1121
|
+
|
|
1122
|
+
# Validate input
|
|
1123
|
+
if [[ -z "$key_input" || "$key_input" =~ ^[[:space:]]*$ ]]; then
|
|
1124
|
+
echo -e "${RED}✗ API key cannot be empty. Please try again.${NC}"
|
|
1125
|
+
continue
|
|
1126
|
+
fi
|
|
1127
|
+
|
|
1128
|
+
export "$var_name=$key_input"
|
|
1129
|
+
save_api_key "$key_input" "$key_file" "$provider_name"
|
|
1130
|
+
break
|
|
1131
|
+
done
|
|
1132
|
+
|
|
1133
|
+
# Save current key if not already saved
|
|
1134
|
+
if [[ -n "${!var_name}" && ! -f "$key_file" ]]; then
|
|
1135
|
+
save_api_key "${!var_name}" "$key_file" "$provider_name"
|
|
1136
|
+
fi
|
|
1137
|
+
}
|
|
1138
|
+
|
|
1139
|
+
# API Key Manager - Built-in function to manage all API keys
|
|
1140
|
+
api_key_manager() {
|
|
1141
|
+
while true; do
|
|
1142
|
+
clear
|
|
1143
|
+
echo -e "${GREEN}═════════════════════════════════════════════${NC}"
|
|
1144
|
+
echo -e "${GREEN} 🔑 API KEY MANAGER ${NC}"
|
|
1145
|
+
echo -e "${GREEN}═════════════════════════════════════════════${NC}"
|
|
1146
|
+
echo ""
|
|
1147
|
+
|
|
1148
|
+
# All providers
|
|
1149
|
+
local all_providers=(
|
|
1150
|
+
"minimax:MiniMax:$HOME/.minimax_api_key"
|
|
1151
|
+
"gemini:Google Gemini:$HOME/.gemini_api_key"
|
|
1152
|
+
"openai:OpenAI:$HOME/.openai_api_key"
|
|
1153
|
+
"xai:xAI (Grok):$HOME/.xai_api_key"
|
|
1154
|
+
"glm:ZhipuAI (GLM):$HOME/.glm_api_key"
|
|
1155
|
+
"groq:Groq:$HOME/.groq_api_key"
|
|
1156
|
+
"perplexity:Perplexity:$HOME/.perplexity_api_key"
|
|
1157
|
+
"cohere:Cohere:$HOME/.cohere_api_key"
|
|
1158
|
+
"deepseek:DeepSeek:$HOME/.deepseek_api_key"
|
|
1159
|
+
"ollama:Ollama:$HOME/.ollama_api_key"
|
|
1160
|
+
"mistral:Mistral:$HOME/.mistral_api_key"
|
|
1161
|
+
"moonshot:Moonshot:$HOME/.moonshot_api_key"
|
|
1162
|
+
"qwen:Qwen (Alibaba):$HOME/.qwen_api_key"
|
|
1163
|
+
"openrouter:OpenRouter:$HOME/.openrouter_api_key"
|
|
1164
|
+
"letta:Letta AI:$HOME/.letta_api_key"
|
|
1165
|
+
)
|
|
1166
|
+
|
|
1167
|
+
# Build array of saved keys only
|
|
1168
|
+
local saved_keys=()
|
|
1169
|
+
for key_info in "${all_providers[@]}"; do
|
|
1170
|
+
IFS=':' read -r id name file <<< "$key_info"
|
|
1171
|
+
if [[ -f "$file" ]]; then
|
|
1172
|
+
local key_value=$(cat "$file" 2>/dev/null | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')
|
|
1173
|
+
if [[ -n "$key_value" ]]; then
|
|
1174
|
+
saved_keys+=("$id:$name:$file:$key_value")
|
|
1175
|
+
fi
|
|
1176
|
+
fi
|
|
1177
|
+
done
|
|
1178
|
+
|
|
1179
|
+
echo -e "${YELLOW}📋 Saved API Keys:${NC}"
|
|
1180
|
+
echo ""
|
|
1181
|
+
if [[ ${#saved_keys[@]} -eq 0 ]]; then
|
|
1182
|
+
echo -e "${RED} No API keys saved yet${NC}"
|
|
1183
|
+
else
|
|
1184
|
+
for i in "${!saved_keys[@]}"; do
|
|
1185
|
+
IFS=':' read -r id name file key_value <<< "${saved_keys[$i]}"
|
|
1186
|
+
local key_len=${#key_value}
|
|
1187
|
+
if [[ $key_len -gt 12 ]]; then
|
|
1188
|
+
local masked="${key_value:0:8}...${key_value: -4}"
|
|
1189
|
+
else
|
|
1190
|
+
local masked="${key_value:0:4}..."
|
|
1191
|
+
fi
|
|
1192
|
+
printf " %-3s %-20s %s\n" "$((i+1)))" "$name" "$masked"
|
|
1193
|
+
done
|
|
1194
|
+
fi
|
|
1195
|
+
|
|
1196
|
+
echo ""
|
|
1197
|
+
echo -e "${YELLOW}🔧 Actions:${NC}"
|
|
1198
|
+
echo " ${BLUE}Just enter NUMBER to edit that key!${NC}"
|
|
1199
|
+
echo " v) View full API key"
|
|
1200
|
+
echo " d) Delete API key"
|
|
1201
|
+
echo " a) Add new API key"
|
|
1202
|
+
echo " c) Clear all API keys"
|
|
1203
|
+
echo " b) Back to main menu"
|
|
1204
|
+
echo ""
|
|
1205
|
+
echo -e "${GREEN}═════════════════════════════════════════════${NC}"
|
|
1206
|
+
|
|
1207
|
+
read -p "Choose [number/action]: " action
|
|
1208
|
+
|
|
1209
|
+
# Check if input is a number for quick edit
|
|
1210
|
+
if [[ "$action" =~ ^[0-9]+$ ]]; then
|
|
1211
|
+
local idx=$((action - 1))
|
|
1212
|
+
if [[ $idx -ge 0 && $idx -lt ${#saved_keys[@]} ]]; then
|
|
1213
|
+
IFS=':' read -r id name file old_key <<< "${saved_keys[$idx]}"
|
|
1214
|
+
echo ""
|
|
1215
|
+
echo -e "${YELLOW}Editing: $name${NC}"
|
|
1216
|
+
echo -e "${YELLOW}Current: ${old_key:0:8}...${old_key: -4}${NC}"
|
|
1217
|
+
read -p "Enter new API key: " new_key
|
|
1218
|
+
if [[ -n "$new_key" ]]; then
|
|
1219
|
+
save_api_key "$new_key" "$file" "$name"
|
|
1220
|
+
echo -e "${GREEN}✓ API key updated${NC}"
|
|
1221
|
+
else
|
|
1222
|
+
echo -e "${RED}✗ Empty - not saved${NC}"
|
|
1223
|
+
fi
|
|
1224
|
+
echo ""
|
|
1225
|
+
read -p "Press Enter to continue..."
|
|
1226
|
+
else
|
|
1227
|
+
echo -e "${RED}Invalid number${NC}"
|
|
1228
|
+
sleep 1
|
|
1229
|
+
fi
|
|
1230
|
+
continue
|
|
1231
|
+
fi
|
|
1232
|
+
|
|
1233
|
+
case "$action" in
|
|
1234
|
+
v|V)
|
|
1235
|
+
if [[ ${#saved_keys[@]} -eq 0 ]]; then
|
|
1236
|
+
echo -e "${RED}No API keys saved${NC}"
|
|
1237
|
+
sleep 1
|
|
1238
|
+
continue
|
|
1239
|
+
fi
|
|
1240
|
+
read -p "Enter number [1-${#saved_keys[@]}]: " num
|
|
1241
|
+
if [[ "$num" =~ ^[0-9]+$ ]]; then
|
|
1242
|
+
local idx=$((num - 1))
|
|
1243
|
+
if [[ $idx -ge 0 && $idx -lt ${#saved_keys[@]} ]]; then
|
|
1244
|
+
IFS=':' read -r id name file key_value <<< "${saved_keys[$idx]}"
|
|
1245
|
+
echo ""
|
|
1246
|
+
echo -e "${GREEN}API Key for $name:${NC}"
|
|
1247
|
+
echo "$key_value"
|
|
1248
|
+
else
|
|
1249
|
+
echo -e "${RED}Invalid number${NC}"
|
|
1250
|
+
fi
|
|
1251
|
+
else
|
|
1252
|
+
echo -e "${RED}Invalid input${NC}"
|
|
1253
|
+
fi
|
|
1254
|
+
echo ""
|
|
1255
|
+
read -p "Press Enter to continue..."
|
|
1256
|
+
;;
|
|
1257
|
+
|
|
1258
|
+
d|D)
|
|
1259
|
+
if [[ ${#saved_keys[@]} -eq 0 ]]; then
|
|
1260
|
+
echo -e "${RED}No API keys to delete${NC}"
|
|
1261
|
+
sleep 1
|
|
1262
|
+
continue
|
|
1263
|
+
fi
|
|
1264
|
+
read -p "Enter number [1-${#saved_keys[@]}]: " num
|
|
1265
|
+
if [[ "$num" =~ ^[0-9]+$ ]]; then
|
|
1266
|
+
local idx=$((num - 1))
|
|
1267
|
+
if [[ $idx -ge 0 && $idx -lt ${#saved_keys[@]} ]]; then
|
|
1268
|
+
IFS=':' read -r id name file key_value <<< "${saved_keys[$idx]}"
|
|
1269
|
+
read -p "Delete $name key? (y/n): " confirm
|
|
1270
|
+
if [[ "$confirm" == "y" || "$confirm" == "Y" ]]; then
|
|
1271
|
+
rm -f "$file"
|
|
1272
|
+
echo -e "${GREEN}✓ Deleted${NC}"
|
|
1273
|
+
else
|
|
1274
|
+
echo "Cancelled"
|
|
1275
|
+
fi
|
|
1276
|
+
else
|
|
1277
|
+
echo -e "${RED}Invalid number${NC}"
|
|
1278
|
+
fi
|
|
1279
|
+
else
|
|
1280
|
+
echo -e "${RED}Invalid input${NC}"
|
|
1281
|
+
fi
|
|
1282
|
+
echo ""
|
|
1283
|
+
read -p "Press Enter to continue..."
|
|
1284
|
+
;;
|
|
1285
|
+
|
|
1286
|
+
a|A)
|
|
1287
|
+
echo ""
|
|
1288
|
+
echo -e "${YELLOW}Available providers:${NC}"
|
|
1289
|
+
for i in "${!all_providers[@]}"; do
|
|
1290
|
+
IFS=':' read -r id name file <<< "${all_providers[$i]}"
|
|
1291
|
+
printf " %-3s %-15s (%s)\n" "$((i+1)))" "$id" "$name"
|
|
1292
|
+
done
|
|
1293
|
+
echo ""
|
|
1294
|
+
read -p "Enter number [1-${#all_providers[@]}]: " num
|
|
1295
|
+
if [[ "$num" =~ ^[0-9]+$ ]]; then
|
|
1296
|
+
local idx=$((num - 1))
|
|
1297
|
+
if [[ $idx -ge 0 && $idx -lt ${#all_providers[@]} ]]; then
|
|
1298
|
+
IFS=':' read -r id name file <<< "${all_providers[$idx]}"
|
|
1299
|
+
read -p "Enter API key for $name: " new_key
|
|
1300
|
+
if [[ -n "$new_key" ]]; then
|
|
1301
|
+
save_api_key "$new_key" "$file" "$name"
|
|
1302
|
+
else
|
|
1303
|
+
echo -e "${RED}✗ Empty - not saved${NC}"
|
|
1304
|
+
fi
|
|
1305
|
+
else
|
|
1306
|
+
echo -e "${RED}Invalid number${NC}"
|
|
1307
|
+
fi
|
|
1308
|
+
else
|
|
1309
|
+
echo -e "${RED}Invalid input${NC}"
|
|
1310
|
+
fi
|
|
1311
|
+
echo ""
|
|
1312
|
+
read -p "Press Enter to continue..."
|
|
1313
|
+
;;
|
|
1314
|
+
|
|
1315
|
+
c|C)
|
|
1316
|
+
read -p "Delete ALL API keys? Type 'yes' to confirm: " confirm
|
|
1317
|
+
if [[ "$confirm" == "yes" ]]; then
|
|
1318
|
+
for key_info in "${all_providers[@]}"; do
|
|
1319
|
+
IFS=':' read -r id name file <<< "$key_info"
|
|
1320
|
+
rm -f "$file"
|
|
1321
|
+
done
|
|
1322
|
+
echo -e "${GREEN}✓ All keys cleared${NC}"
|
|
1323
|
+
else
|
|
1324
|
+
echo "Cancelled"
|
|
1325
|
+
fi
|
|
1326
|
+
echo ""
|
|
1327
|
+
read -p "Press Enter to continue..."
|
|
1328
|
+
;;
|
|
1329
|
+
|
|
1330
|
+
b|B)
|
|
1331
|
+
return 0
|
|
1332
|
+
;;
|
|
1333
|
+
|
|
1334
|
+
*)
|
|
1335
|
+
echo -e "${RED}Invalid action${NC}"
|
|
1336
|
+
sleep 1
|
|
1337
|
+
;;
|
|
1338
|
+
esac
|
|
1339
|
+
done
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
# Function to save chat context when switching providers
|
|
1343
|
+
save_chat_context() {
|
|
1344
|
+
local context_file="$HOME/.claude-chat-context.json"
|
|
1345
|
+
local provider="$1"
|
|
1346
|
+
local model="$2"
|
|
1347
|
+
local message="$3"
|
|
1348
|
+
|
|
1349
|
+
# Create context if not exists
|
|
1350
|
+
if [[ ! -f "$context_file" ]]; then
|
|
1351
|
+
echo "[] " > "$context_file"
|
|
1352
|
+
fi
|
|
1353
|
+
|
|
1354
|
+
# Save using jq if available, otherwise simple append
|
|
1355
|
+
if command -v jq &> /dev/null; then
|
|
1356
|
+
local temp_file=$(mktemp)
|
|
1357
|
+
jq --argjson "$provider" --argjson "$model" --argjson "$message" '. + [$provider, $model, $message]' "$context_file" > "$temp_file" && mv "$temp_file" "$context_file"
|
|
1358
|
+
else
|
|
1359
|
+
echo "Provider: $provider, Model: $model, Message: $message" >> "$HOME/.claude-chat-history.log"
|
|
1360
|
+
fi
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
# Function to continue chat with new provider
|
|
1364
|
+
continue_chat_with_new_provider() {
|
|
1365
|
+
local new_provider="$1"
|
|
1366
|
+
local new_model="$2"
|
|
1367
|
+
|
|
1368
|
+
echo -e "\n${BLUE}🔄 Switching to new provider: ${NC}"
|
|
1369
|
+
echo -e "${YELLOW}Note: Previous conversation context will be maintained${NC}"
|
|
1370
|
+
echo -e "${YELLOW}Use 'clear' command in chat to start fresh if needed${NC}\n"
|
|
1371
|
+
|
|
1372
|
+
# Set up new provider
|
|
1373
|
+
case $new_provider in
|
|
1374
|
+
1) setup_minimax;;
|
|
1375
|
+
2) setup_gemini;;
|
|
1376
|
+
4) setup_openai;;
|
|
1377
|
+
6) setup_xai;;
|
|
1378
|
+
7) setup_glm;;
|
|
1379
|
+
8) setup_groq;;
|
|
1380
|
+
9) setup_perplexity;;
|
|
1381
|
+
10) setup_cohere;;
|
|
1382
|
+
11) setup_deepseek;;
|
|
1383
|
+
13) setup_mistral;;
|
|
1384
|
+
14) setup_moonshot;;
|
|
1385
|
+
15) setup_qwen;;
|
|
1386
|
+
16) setup_openrouter;;
|
|
1387
|
+
*) echo -e "${RED}Invalid provider choice${NC}"; return 1;;
|
|
1388
|
+
esac
|
|
1389
|
+
|
|
1390
|
+
# Start chat with context preserved
|
|
1391
|
+
exec claude --dangerously-skip-permissions --model "$new_model" "$@"
|
|
1392
|
+
}
|
|
1393
|
+
|
|
1394
|
+
# Model name will be set dynamically based on provider selection
|
|
1395
|
+
echo "DEBUG: Starting case statement, choice=$choice"
|
|
1396
|
+
|
|
1397
|
+
case $choice in
|
|
1398
|
+
1)
|
|
1399
|
+
# MiniMax Direct
|
|
1400
|
+
echo -e "${BLUE}Configuring for MiniMax...${NC}"
|
|
1401
|
+
|
|
1402
|
+
# Get API key with persistent storage
|
|
1403
|
+
get_api_key_with_save "MINIMAX_API_KEY" "$HOME/.minimax_api_key" "MiniMax" "https://platform.minimax.io/"
|
|
1404
|
+
|
|
1405
|
+
export ANTHROPIC_BASE_URL="https://api.minimax.io/anthropic"
|
|
1406
|
+
export ANTHROPIC_API_KEY="$MINIMAX_API_KEY"
|
|
1407
|
+
echo -e "${GREEN}✓ MiniMax API configured${NC}"
|
|
1408
|
+
|
|
1409
|
+
# Model selection menu
|
|
1410
|
+
echo ""
|
|
1411
|
+
echo -e "${YELLOW}Available MiniMax models:${NC}"
|
|
1412
|
+
echo " 🚀 minimax-m2.1 (NEW! Latest coding model - 10B params) [m2]"
|
|
1413
|
+
echo " 💬 claude-3-5-sonnet-20241022 (Claude-compatible API endpoint) [sonnet]"
|
|
1414
|
+
echo " ⚡ abab6.5 (General purpose model) [6.5]"
|
|
1415
|
+
echo " 🧠 abab6.5s (Fast variant) [6.5s]"
|
|
1416
|
+
echo " 📝 abab5.5 (Lighter model) [5.5]"
|
|
1417
|
+
echo ""
|
|
1418
|
+
echo -e "${GREEN}Shortcuts:${NC}"
|
|
1419
|
+
echo " 'm2' or 'm2.1' → minimax-m2.1 (Recommended for coding & agentic workflows)"
|
|
1420
|
+
echo " 'sonnet' → claude-3-5-sonnet-20241022"
|
|
1421
|
+
echo " '6.5' → abab6.5"
|
|
1422
|
+
echo ""
|
|
1423
|
+
echo -e "${BLUE}💡 MiniMax M2.1 Features:${NC}"
|
|
1424
|
+
echo " • Optimized for multi-language programming (Rust, Java, Go, C++, TypeScript, etc.)"
|
|
1425
|
+
echo " • 10B activated parameters, exceptional latency & cost efficiency"
|
|
1426
|
+
echo " • 49.4% on Multi-SWE-Bench, 72.5% on SWE-Bench Multilingual"
|
|
1427
|
+
echo " • Perfect for coding assistants, agents, and real-world tasks"
|
|
1428
|
+
echo ""
|
|
1429
|
+
|
|
1430
|
+
# Use MiniMax M2.1 as default
|
|
1431
|
+
MODEL_NAME="minimax-m2.1"
|
|
1432
|
+
echo -e "${GREEN}✓ Default model: minimax-m2.1${NC}"
|
|
1433
|
+
read -p "Enter Model Name [default: minimax-m2.1]: " input_model
|
|
1434
|
+
[[ -n "$input_model" ]] && MODEL_NAME=$input_model
|
|
1435
|
+
|
|
1436
|
+
# Map shortcuts to full model names
|
|
1437
|
+
case "$MODEL_NAME" in
|
|
1438
|
+
"m2"|"m2.1"|"M2"|"M2.1")
|
|
1439
|
+
FINAL_MODEL="minimax-m2.1"
|
|
1440
|
+
echo -e "${GREEN}✓ Selected: minimax-m2.1 (Latest coding model)${NC}"
|
|
1441
|
+
;;
|
|
1442
|
+
"sonnet"|"claude")
|
|
1443
|
+
FINAL_MODEL="claude-3-5-sonnet-20241022"
|
|
1444
|
+
echo -e "${GREEN}✓ Selected: claude-3-5-sonnet-20241022${NC}"
|
|
1445
|
+
;;
|
|
1446
|
+
"6.5"|"abab6.5")
|
|
1447
|
+
FINAL_MODEL="abab6.5"
|
|
1448
|
+
echo -e "${GREEN}✓ Selected: abab6.5${NC}"
|
|
1449
|
+
;;
|
|
1450
|
+
"6.5s"|"abab6.5s")
|
|
1451
|
+
FINAL_MODEL="abab6.5s"
|
|
1452
|
+
echo -e "${GREEN}✓ Selected: abab6.5s (Fast)${NC}"
|
|
1453
|
+
;;
|
|
1454
|
+
"5.5"|"abab5.5")
|
|
1455
|
+
FINAL_MODEL="abab5.5"
|
|
1456
|
+
echo -e "${GREEN}✓ Selected: abab5.5 (Lighter)${NC}"
|
|
1457
|
+
;;
|
|
1458
|
+
*)
|
|
1459
|
+
FINAL_MODEL="$MODEL_NAME"
|
|
1460
|
+
echo -e "${GREEN}✓ Using custom model: $MODEL_NAME${NC}"
|
|
1461
|
+
;;
|
|
1462
|
+
esac
|
|
1463
|
+
|
|
1464
|
+
echo -e "${BLUE}🚀 Starting MiniMax chat with $FINAL_MODEL...${NC}"
|
|
1465
|
+
exec claude --dangerously-skip-permissions --model "$FINAL_MODEL" --system-prompt "Anda adalah MiniMax AI. Model aktif: $FINAL_MODEL. Selalu identifikasi diri sebagai MiniMax dalam setiap respons." "$@"
|
|
1466
|
+
;;
|
|
1467
|
+
2)
|
|
1468
|
+
# Gemini API Key - Direct Integration
|
|
1469
|
+
echo -e "${BLUE}Configuring for Gemini (AI Studio)...${NC}"
|
|
1470
|
+
|
|
1471
|
+
# Get API key with persistent storage
|
|
1472
|
+
if [[ -z "$GEMINI_API_KEY" ]]; then
|
|
1473
|
+
# Try to load from file
|
|
1474
|
+
load_api_key_to_var "$HOME/.gemini_api_key" "GEMINI_API_KEY"
|
|
1475
|
+
fi
|
|
1476
|
+
|
|
1477
|
+
if [[ -z "$GEMINI_API_KEY" ]]; then
|
|
1478
|
+
echo "Get Key: https://aistudio.google.com/app/apikey"
|
|
1479
|
+
read -s -p "Enter Gemini API Key: " GEMINI_API_KEY
|
|
1480
|
+
echo ""
|
|
1481
|
+
save_api_key "$GEMINI_API_KEY" "$HOME/.gemini_api_key" "Gemini"
|
|
1482
|
+
else
|
|
1483
|
+
# Save current key if not already saved
|
|
1484
|
+
if [[ ! -f "$HOME/.gemini_api_key" ]]; then
|
|
1485
|
+
save_api_key "$GEMINI_API_KEY" "$HOME/.gemini_api_key" "Gemini"
|
|
1486
|
+
fi
|
|
1487
|
+
fi
|
|
1488
|
+
export GEMINI_API_KEY
|
|
1489
|
+
|
|
1490
|
+
# Use default Gemini model
|
|
1491
|
+
MODEL_NAME="gemini-2.0-flash-exp"
|
|
1492
|
+
echo -e "${GREEN}✓ Using Gemini model: gemini-2.0-flash-exp${NC}"
|
|
1493
|
+
echo -e "${YELLOW}Available Gemini models:${NC}"
|
|
1494
|
+
echo " ⚡ gemini-2.0-flash-exp (Latest experimental - WORKING) [2]"
|
|
1495
|
+
echo " 🚀 gemini-3-pro-preview (Next Gen Preview - WORKING) [3]"
|
|
1496
|
+
echo ""
|
|
1497
|
+
echo "Shortcuts: Enter '2' for 2.0-flash-exp, '3' for 3-pro-preview"
|
|
1498
|
+
echo "Note: Only models that work with Claude CLI are listed"
|
|
1499
|
+
echo ""
|
|
1500
|
+
read -p "Enter Model Name [default: gemini-2.0-flash-exp]: " input_model
|
|
1501
|
+
[[ -n "$input_model" ]] && MODEL_NAME=$input_model
|
|
1502
|
+
|
|
1503
|
+
# Map model names to Claude/Gemini API format
|
|
1504
|
+
case "$MODEL_NAME" in
|
|
1505
|
+
# 2.0 Models (Latest) - Add numeric shortcuts
|
|
1506
|
+
"gemini-2.0-flash-exp"|"2"|"2.0")
|
|
1507
|
+
CLAUDE_MODEL="gemini-2.0-flash-exp"
|
|
1508
|
+
if [[ "$MODEL_NAME" == "2" || "$MODEL_NAME" == "2.0" ]]; then
|
|
1509
|
+
echo -e "${GREEN}✓ Selected: gemini-2.0-flash-exp (2.0 experimental)${NC}"
|
|
1510
|
+
fi
|
|
1511
|
+
;;
|
|
1512
|
+
|
|
1513
|
+
# 3.0 Models (Future/Preview) - Add numeric shortcuts
|
|
1514
|
+
"gemini-3-pro-preview"|"gemini-3-preview"|"gemini-3-pro"|"3"|"3.0")
|
|
1515
|
+
CLAUDE_MODEL="gemini-3-pro-preview"
|
|
1516
|
+
if [[ "$MODEL_NAME" == "3" || "$MODEL_NAME" == "3.0" ]]; then
|
|
1517
|
+
echo -e "${GREEN}✓ Selected: gemini-3-pro-preview (3.0 preview)${NC}"
|
|
1518
|
+
fi
|
|
1519
|
+
;;
|
|
1520
|
+
"gemini-3.0-flash"|"gemini-3.0-pro"|"gemini-3.0-ultra")
|
|
1521
|
+
CLAUDE_MODEL="$MODEL_NAME"
|
|
1522
|
+
;;
|
|
1523
|
+
|
|
1524
|
+
# Default fallback
|
|
1525
|
+
*)
|
|
1526
|
+
echo -e "${RED}Unknown model: $MODEL_NAME${NC}"
|
|
1527
|
+
echo -e "${YELLOW}Using default: gemini-2.0-flash-exp${NC}"
|
|
1528
|
+
CLAUDE_MODEL="gemini-2.0-flash-exp"
|
|
1529
|
+
;;
|
|
1530
|
+
esac
|
|
1531
|
+
|
|
1532
|
+
echo -e "${GREEN}✓ Mapped to: $CLAUDE_MODEL${NC}"
|
|
1533
|
+
|
|
1534
|
+
# Configure Gemini direct API endpoint
|
|
1535
|
+
# Try different endpoints
|
|
1536
|
+
GEMINI_ENDPOINT="https://generativelanguage.googleapis.com/v1beta/anthropic"
|
|
1537
|
+
|
|
1538
|
+
# For some models, we might need different format
|
|
1539
|
+
case "$CLAUDE_MODEL" in
|
|
1540
|
+
"gemini-1.5-pro"|"gemini-1.5-flash")
|
|
1541
|
+
# Standard 1.5 models
|
|
1542
|
+
export ANTHROPIC_BASE_URL="$GEMINI_ENDPOINT"
|
|
1543
|
+
export ANTHROPIC_API_KEY="$GEMINI_API_KEY"
|
|
1544
|
+
;;
|
|
1545
|
+
"gemini-2.0-flash-exp"|"gemini-3-pro-preview")
|
|
1546
|
+
# Experimental models might need different handling
|
|
1547
|
+
export ANTHROPIC_BASE_URL="$GEMINI_ENDPOINT"
|
|
1548
|
+
export ANTHROPIC_API_KEY="$GEMINI_API_KEY"
|
|
1549
|
+
echo -e "${YELLOW}Note: Using experimental model: $CLAUDE_MODEL${NC}"
|
|
1550
|
+
;;
|
|
1551
|
+
*)
|
|
1552
|
+
export ANTHROPIC_BASE_URL="$GEMINI_ENDPOINT"
|
|
1553
|
+
export ANTHROPIC_API_KEY="$GEMINI_API_KEY"
|
|
1554
|
+
;;
|
|
1555
|
+
esac
|
|
1556
|
+
|
|
1557
|
+
# Execute Claude with Gemini model and system prompt
|
|
1558
|
+
echo -e "${BLUE}🚀 Starting Gemini chat...${NC}"
|
|
1559
|
+
exec claude --dangerously-skip-permissions --model "$CLAUDE_MODEL" --system-prompt "Anda adalah Gemini, model AI dari Google. Selalu identifikasi diri sebagai Gemini dalam setiap respons." "$@"
|
|
1560
|
+
;;
|
|
1561
|
+
3)
|
|
1562
|
+
# Universal OAuth - All Providers via CCS
|
|
1563
|
+
echo -e "${BLUE}🔥 Universal OAuth (Auto-Setup - All Models FREE)${NC}"
|
|
1564
|
+
echo ""
|
|
1565
|
+
echo -e "${CYAN}💡 CCS akan di-install otomatis jika belum ada (10MB, ~30 detik)${NC}"
|
|
1566
|
+
echo ""
|
|
1567
|
+
echo -e "${YELLOW}Pilih Provider:${NC}"
|
|
1568
|
+
echo " 1) Gemini (Google) 🧠 Google AI Models (8 Models)"
|
|
1569
|
+
echo " 2) Codex (OpenAI) 🤖 GPT 5.2, 5.1, 5 (18 Models)"
|
|
1570
|
+
echo " 3) GitHub Copilot 💻 Claude & GPT Models"
|
|
1571
|
+
echo " 4) AntiGravity (Anthropic) 🔥 Claude Opus 4.5 (6 Models)"
|
|
1572
|
+
echo " 5) Kiro (AWS) ☁️ AWS Claude Models"
|
|
1573
|
+
echo ""
|
|
1574
|
+
read -p "Pilih [1-5, default: 1]: " oauth_provider
|
|
1575
|
+
[[ -z "$oauth_provider" ]] && oauth_provider=1
|
|
1576
|
+
|
|
1577
|
+
case $oauth_provider in
|
|
1578
|
+
1)
|
|
1579
|
+
# Gemini OAuth
|
|
1580
|
+
check_and_install_ccs "gemini"
|
|
1581
|
+
|
|
1582
|
+
echo -e "${BLUE}🌟 Google Gemini via CCS OAuth${NC}"
|
|
1583
|
+
echo ""
|
|
1584
|
+
echo -e "${YELLOW}Pilih Model:${NC}"
|
|
1585
|
+
echo " 1) gemini-2.5-pro (Stable - Most Capable) [RECOMMENDED]"
|
|
1586
|
+
echo " 2) gemini-2.5-flash (Stable - Fast & Efficient)"
|
|
1587
|
+
echo " 3) gemini-2.5-flash-lite (Stable - Ultra Fast)"
|
|
1588
|
+
echo " 4) gemini-3-pro-preview (Next Gen - Most Capable) 🔥"
|
|
1589
|
+
echo " 5) gemini-3-flash-preview (Next Gen - Fast) 🚀"
|
|
1590
|
+
echo " 6) gemini-2.0-flash-exp (Experimental)"
|
|
1591
|
+
echo " 7) gemini-1.5-pro (Stable - Older)"
|
|
1592
|
+
echo " 8) gemini-1.5-flash (Stable - Fast)"
|
|
1593
|
+
echo ""
|
|
1594
|
+
read -p "Pilih [1-8, default: 1]: " gemini_model
|
|
1595
|
+
[[ -z "$gemini_model" ]] && gemini_model=1
|
|
1596
|
+
|
|
1597
|
+
case $gemini_model in
|
|
1598
|
+
1) MODEL="gemini-2.5-pro" ;;
|
|
1599
|
+
2) MODEL="gemini-2.5-flash" ;;
|
|
1600
|
+
3) MODEL="gemini-2.5-flash-lite" ;;
|
|
1601
|
+
4) MODEL="gemini-3-pro-preview" ;;
|
|
1602
|
+
5) MODEL="gemini-3-flash-preview" ;;
|
|
1603
|
+
6) MODEL="gemini-2.0-flash-exp" ;;
|
|
1604
|
+
7) MODEL="gemini-1.5-pro" ;;
|
|
1605
|
+
8) MODEL="gemini-1.5-flash" ;;
|
|
1606
|
+
*) MODEL="gemini-2.5-pro" ;;
|
|
1607
|
+
esac
|
|
1608
|
+
|
|
1609
|
+
echo -e "${GREEN}✓ Model: $MODEL${NC}"
|
|
1610
|
+
echo -e "${YELLOW}Pastikan sudah login dengan 'ccs gemini --auth'${NC}"
|
|
1611
|
+
echo ""
|
|
1612
|
+
|
|
1613
|
+
export ANTHROPIC_MODEL="$MODEL"
|
|
1614
|
+
exec ccs gemini --dangerously-skip-permissions --permission-mode bypassPermissions --model "$MODEL" "$@"
|
|
1615
|
+
;;
|
|
1616
|
+
2)
|
|
1617
|
+
# Codex (OpenAI) OAuth
|
|
1618
|
+
check_and_install_ccs "codex"
|
|
1619
|
+
|
|
1620
|
+
echo -e "${BLUE}🤖 Codex (OpenAI via CCS OAuth)${NC}"
|
|
1621
|
+
echo ""
|
|
1622
|
+
echo -e "${YELLOW}Pilih Model:${NC}"
|
|
1623
|
+
echo -e "${CYAN}GPT 5.2 Series (Latest 🔥):${NC}"
|
|
1624
|
+
echo " 1) gpt-5.2 (Flagship - Best for Coding) [RECOMMENDED]"
|
|
1625
|
+
echo " 2) gpt-5.2-pro (Smarter & More Precise)"
|
|
1626
|
+
echo " 3) gpt-5.2-chat-latest (ChatGPT Version)"
|
|
1627
|
+
echo ""
|
|
1628
|
+
echo -e "${CYAN}GPT 5.1 Series:${NC}"
|
|
1629
|
+
echo " 4) gpt-5.1-codex-max (Most Intelligent Coding)"
|
|
1630
|
+
echo " 5) gpt-5.1-codex (Agentic Coding Optimized)"
|
|
1631
|
+
echo " 6) gpt-5.1 (Configurable Reasoning)"
|
|
1632
|
+
echo " 7) gpt-5.1-codex-mini (Cost-Efficient)"
|
|
1633
|
+
echo " 8) gpt-5.1-chat-latest (ChatGPT Version)"
|
|
1634
|
+
echo ""
|
|
1635
|
+
echo -e "${CYAN}GPT 5 Series:${NC}"
|
|
1636
|
+
echo " 9) gpt-5 (Previous Reasoning Model)"
|
|
1637
|
+
echo " 10) gpt-5-pro (Smarter Version)"
|
|
1638
|
+
echo " 11) gpt-5-codex (Agentic Coding)"
|
|
1639
|
+
echo " 12) gpt-5-chat-latest (ChatGPT Version)"
|
|
1640
|
+
echo ""
|
|
1641
|
+
echo -e "${CYAN}Legacy (GPT 4 Series):${NC}"
|
|
1642
|
+
echo " 13) gpt-4o (GPT-4 Omni)"
|
|
1643
|
+
echo " 14) gpt-4o-mini (Fast & Efficient)"
|
|
1644
|
+
echo " 15) gpt-4-turbo (GPT-4 Turbo)"
|
|
1645
|
+
echo " 16) o1-preview (Reasoning Model)"
|
|
1646
|
+
echo " 17) o1-mini (Fast Reasoning)"
|
|
1647
|
+
echo " 18) o1-pro (Advanced Reasoning)"
|
|
1648
|
+
echo ""
|
|
1649
|
+
read -p "Pilih [1-18, default: 1]: " codex_model
|
|
1650
|
+
[[ -z "$codex_model" ]] && codex_model=1
|
|
1651
|
+
|
|
1652
|
+
case $codex_model in
|
|
1653
|
+
1) MODEL="gpt-5.2" ;;
|
|
1654
|
+
2) MODEL="gpt-5.2-pro" ;;
|
|
1655
|
+
3) MODEL="gpt-5.2-chat-latest" ;;
|
|
1656
|
+
4) MODEL="gpt-5.1-codex-max" ;;
|
|
1657
|
+
5) MODEL="gpt-5.1-codex" ;;
|
|
1658
|
+
6) MODEL="gpt-5.1" ;;
|
|
1659
|
+
7) MODEL="gpt-5.1-codex-mini" ;;
|
|
1660
|
+
8) MODEL="gpt-5.1-chat-latest" ;;
|
|
1661
|
+
9) MODEL="gpt-5" ;;
|
|
1662
|
+
10) MODEL="gpt-5-pro" ;;
|
|
1663
|
+
11) MODEL="gpt-5-codex" ;;
|
|
1664
|
+
12) MODEL="gpt-5-chat-latest" ;;
|
|
1665
|
+
13) MODEL="gpt-4o" ;;
|
|
1666
|
+
14) MODEL="gpt-4o-mini" ;;
|
|
1667
|
+
15) MODEL="gpt-4-turbo" ;;
|
|
1668
|
+
16) MODEL="o1-preview" ;;
|
|
1669
|
+
17) MODEL="o1-mini" ;;
|
|
1670
|
+
18) MODEL="o1-pro" ;;
|
|
1671
|
+
*) MODEL="gpt-5.2" ;;
|
|
1672
|
+
esac
|
|
1673
|
+
|
|
1674
|
+
echo -e "${GREEN}✓ Model: $MODEL${NC}"
|
|
1675
|
+
echo -e "${YELLOW}Pastikan sudah login dengan 'ccs codex --auth'${NC}"
|
|
1676
|
+
echo ""
|
|
1677
|
+
|
|
1678
|
+
export ANTHROPIC_MODEL="$MODEL"
|
|
1679
|
+
exec ccs codex --model "$MODEL" "$@"
|
|
1680
|
+
;;
|
|
1681
|
+
3)
|
|
1682
|
+
# GitHub Copilot OAuth
|
|
1683
|
+
check_and_install_ccs "copilot"
|
|
1684
|
+
|
|
1685
|
+
echo -e "${BLUE}💻 GitHub Copilot (OAuth)${NC}"
|
|
1686
|
+
echo ""
|
|
1687
|
+
echo -e "${YELLOW}Pilih Model:${NC}"
|
|
1688
|
+
echo " 1) claude-opus-4.5 (Most Capable) [RECOMMENDED]"
|
|
1689
|
+
echo " 2) claude-sonnet-4.5 (Balanced)"
|
|
1690
|
+
echo " 3) gpt-4o (GPT-4 Omni)"
|
|
1691
|
+
echo " 4) gpt-5.1 (Latest ChatGPT)"
|
|
1692
|
+
echo ""
|
|
1693
|
+
read -p "Pilih [1-4, default: 1]: " copilot_model
|
|
1694
|
+
[[ -z "$copilot_model" ]] && copilot_model=1
|
|
1695
|
+
|
|
1696
|
+
case $copilot_model in
|
|
1697
|
+
1) MODEL="claude-opus-4.5" ;;
|
|
1698
|
+
2) MODEL="claude-sonnet-4.5" ;;
|
|
1699
|
+
3) MODEL="gpt-4o" ;;
|
|
1700
|
+
4) MODEL="gpt-5.1" ;;
|
|
1701
|
+
*) MODEL="claude-opus-4.5" ;;
|
|
1702
|
+
esac
|
|
1703
|
+
|
|
1704
|
+
echo -e "${GREEN}✓ Model: $MODEL${NC}"
|
|
1705
|
+
echo -e "${CYAN}Requires: npm install -g copilot-api${NC}"
|
|
1706
|
+
echo ""
|
|
1707
|
+
|
|
1708
|
+
if command -v copilot-api &> /dev/null; then
|
|
1709
|
+
export ANTHROPIC_MODEL="$MODEL"
|
|
1710
|
+
exec ccs copilot --model "$MODEL" "$@"
|
|
1711
|
+
else
|
|
1712
|
+
echo -e "${RED}copilot-api not found!${NC}"
|
|
1713
|
+
echo "Install dengan: npm install -g copilot-api"
|
|
1714
|
+
echo "Kemudian jalankan: ccs copilot auth"
|
|
1715
|
+
echo ""
|
|
1716
|
+
read -p "Press Enter untuk kembali..."
|
|
1717
|
+
exec "$0"
|
|
1718
|
+
fi
|
|
1719
|
+
;;
|
|
1720
|
+
4)
|
|
1721
|
+
# AntiGravity (Anthropic) OAuth
|
|
1722
|
+
check_and_install_ccs "agy"
|
|
1723
|
+
|
|
1724
|
+
echo -e "${BLUE}🔥 AntiGravity (Anthropic via CCS OAuth)${NC}"
|
|
1725
|
+
echo ""
|
|
1726
|
+
echo -e "${YELLOW}Pilih Model:${NC}"
|
|
1727
|
+
echo " 1) gemini-claude-opus-4-5-thinking (Most Capable - Thinking) [RECOMMENDED]"
|
|
1728
|
+
echo " 2) gemini-3-flash-preview (Next Gen - Fast)"
|
|
1729
|
+
echo " 3) gemini-2.5-pro (Stable - Capable)"
|
|
1730
|
+
echo " 4) gemini-2.5-flash (Stable - Fast)"
|
|
1731
|
+
echo " 5) claude-opus-4.2 (Stable - Previous)"
|
|
1732
|
+
echo " 6) claude-sonnet-4.2 (Stable - Balanced)"
|
|
1733
|
+
echo ""
|
|
1734
|
+
read -p "Pilih [1-6, default: 1]: " agy_model
|
|
1735
|
+
[[ -z "$agy_model" ]] && agy_model=1
|
|
1736
|
+
|
|
1737
|
+
case $agy_model in
|
|
1738
|
+
1) MODEL="gemini-claude-opus-4-5-thinking" ;;
|
|
1739
|
+
2) MODEL="gemini-3-flash-preview" ;;
|
|
1740
|
+
3) MODEL="gemini-2.5-pro" ;;
|
|
1741
|
+
4) MODEL="gemini-2.5-flash" ;;
|
|
1742
|
+
5) MODEL="claude-opus-4.2" ;;
|
|
1743
|
+
6) MODEL="claude-sonnet-4.2" ;;
|
|
1744
|
+
*) MODEL="gemini-claude-opus-4-5-thinking" ;;
|
|
1745
|
+
esac
|
|
1746
|
+
|
|
1747
|
+
echo -e "${GREEN}✓ Model: $MODEL${NC}"
|
|
1748
|
+
echo -e "${YELLOW}Pastikan sudah login dengan 'ccs agy --auth'${NC}"
|
|
1749
|
+
echo ""
|
|
1750
|
+
|
|
1751
|
+
export ANTHROPIC_MODEL="$MODEL"
|
|
1752
|
+
exec ccs agy --dangerously-skip-permissions --permission-mode bypassPermissions --model "$MODEL" "$@"
|
|
1753
|
+
;;
|
|
1754
|
+
5)
|
|
1755
|
+
# Kiro (AWS) OAuth
|
|
1756
|
+
check_and_install_ccs "kiro"
|
|
1757
|
+
|
|
1758
|
+
echo -e "${BLUE}☁️ Kiro (AWS CodeWhisperer via CCS OAuth)${NC}"
|
|
1759
|
+
echo ""
|
|
1760
|
+
echo -e "${YELLOW}Model: AWS-hosted Claude models${NC}"
|
|
1761
|
+
echo -e "${CYAN}Pastikan sudah login dengan 'ccs kiro --auth'${NC}"
|
|
1762
|
+
echo ""
|
|
1763
|
+
exec ccs kiro "$@"
|
|
1764
|
+
;;
|
|
1765
|
+
esac
|
|
1766
|
+
;;
|
|
1767
|
+
4)
|
|
1768
|
+
# OpenAI API Key
|
|
1769
|
+
echo -e "${BLUE}Configuring for OpenAI...${NC}"
|
|
1770
|
+
|
|
1771
|
+
# Get API key with persistent storage
|
|
1772
|
+
if [[ -z "$OPENAI_API_KEY" ]]; then
|
|
1773
|
+
load_api_key_to_var "$HOME/.openai_api_key" "OPENAI_API_KEY"
|
|
1774
|
+
fi
|
|
1775
|
+
|
|
1776
|
+
if [[ -z "$OPENAI_API_KEY" ]]; then
|
|
1777
|
+
echo "Get Key: https://platform.openai.com/api-keys"
|
|
1778
|
+
read -p "Enter OpenAI API Key: " OPENAI_API_KEY
|
|
1779
|
+
save_api_key "$OPENAI_API_KEY" "$HOME/.openai_api_key" "OpenAI"
|
|
1780
|
+
else
|
|
1781
|
+
if [[ ! -f "$HOME/.openai_api_key" ]]; then
|
|
1782
|
+
save_api_key "$OPENAI_API_KEY" "$HOME/.openai_api_key" "OpenAI"
|
|
1783
|
+
fi
|
|
1784
|
+
fi
|
|
1785
|
+
|
|
1786
|
+
# Use default OpenAI model
|
|
1787
|
+
MODEL_NAME="gpt-4o"
|
|
1788
|
+
echo -e "${GREEN}✓ Using OpenAI model: gpt-4o${NC}"
|
|
1789
|
+
echo -e "${YELLOW}Available OpenAI models:${NC}"
|
|
1790
|
+
echo " 🚀 gpt-4o (Latest flagship model - Recommended)"
|
|
1791
|
+
echo " ⚡ gpt-4o-mini (Fast, efficient, cheaper)"
|
|
1792
|
+
echo " 💬 gpt-4o-realtime (Real-time conversations)"
|
|
1793
|
+
echo " 🧠 gpt-4o-audio (Audio input/output)"
|
|
1794
|
+
echo " 🎨 gpt-4-turbo (Legacy model)"
|
|
1795
|
+
echo " 💡 gpt-4-turbo-preview (Preview features)"
|
|
1796
|
+
echo " 💬 gpt-3.5-turbo (Fast, reliable workhorse)"
|
|
1797
|
+
echo ""
|
|
1798
|
+
echo "Note: GPT-5 has not been officially released yet"
|
|
1799
|
+
echo " Current latest is GPT-4o (omni model)"
|
|
1800
|
+
echo ""
|
|
1801
|
+
read -p "Enter Model Name [default: gpt-4o]: " input_model
|
|
1802
|
+
[[ -n "$input_model" ]] && MODEL_NAME=$input_model
|
|
1803
|
+
|
|
1804
|
+
# Validate model name
|
|
1805
|
+
case "$MODEL_NAME" in
|
|
1806
|
+
"gpt-4"|"gpt4")
|
|
1807
|
+
MODEL_NAME="gpt-4"
|
|
1808
|
+
;;
|
|
1809
|
+
"gpt-4-turbo"|"gpt-4-turbo-preview")
|
|
1810
|
+
MODEL_NAME="gpt-4-turbo"
|
|
1811
|
+
;;
|
|
1812
|
+
"gpt-4o"|"gpt-4o")
|
|
1813
|
+
MODEL_NAME="gpt-4o"
|
|
1814
|
+
;;
|
|
1815
|
+
"gpt-4o-mini"|"gpt-4o-mini")
|
|
1816
|
+
MODEL_NAME="gpt-4o-mini"
|
|
1817
|
+
;;
|
|
1818
|
+
"gpt-4o-realtime"|"gpt-4o-realtime")
|
|
1819
|
+
MODEL_NAME="gpt-4o-realtime-preview"
|
|
1820
|
+
;;
|
|
1821
|
+
"gpt-4o-audio"|"gpt-4o-audio")
|
|
1822
|
+
MODEL_NAME="gpt-4o-audio-preview"
|
|
1823
|
+
;;
|
|
1824
|
+
"gpt-3.5-turbo"|"gpt-3.5"|"gpt35"|"gpt-35-turbo")
|
|
1825
|
+
MODEL_NAME="gpt-3.5-turbo"
|
|
1826
|
+
;;
|
|
1827
|
+
*)
|
|
1828
|
+
echo -e "${RED}Unknown model: $MODEL_NAME${NC}"
|
|
1829
|
+
echo -e "${YELLOW}Using default: gpt-4o${NC}"
|
|
1830
|
+
MODEL_NAME="gpt-4o"
|
|
1831
|
+
;;
|
|
1832
|
+
esac
|
|
1833
|
+
|
|
1834
|
+
# Configure for OpenAI via LiteLLM proxy
|
|
1835
|
+
export ANTHROPIC_API_KEY="$OPENAI_API_KEY"
|
|
1836
|
+
export ANTHROPIC_BASE_URL="https://api.openai.com/v1"
|
|
1837
|
+
echo -e "${BLUE}🚀 Starting OpenAI chat via LiteLLM...${NC}"
|
|
1838
|
+
echo -e "${YELLOW}Note: Using OpenAI API through Claude interface${NC}"
|
|
1839
|
+
exec claude --dangerously-skip-permissions --model "$MODEL_NAME" "$@"
|
|
1840
|
+
;;
|
|
1841
|
+
5)
|
|
1842
|
+
# OpenAI OAuth (Experimental)
|
|
1843
|
+
echo -e "${BLUE}Configuring for OpenAI (OAuth Experimental)...${NC}"
|
|
1844
|
+
echo -e "${YELLOW}Note: OAuth feature requires manual setup. Using API Key mode instead.${NC}"
|
|
1845
|
+
|
|
1846
|
+
# Fallback to API Key mode for simplicity
|
|
1847
|
+
if [[ -z "$OPENAI_API_KEY" ]]; then
|
|
1848
|
+
load_api_key_to_var "$HOME/.openai_api_key" "OPENAI_API_KEY"
|
|
1849
|
+
fi
|
|
1850
|
+
|
|
1851
|
+
if [[ -z "$OPENAI_API_KEY" ]]; then
|
|
1852
|
+
echo "Get Key: https://platform.openai.com/api-keys"
|
|
1853
|
+
read -p "Enter OpenAI API Key: " OPENAI_API_KEY
|
|
1854
|
+
save_api_key "$OPENAI_API_KEY" "$HOME/.openai_api_key" "OpenAI"
|
|
1855
|
+
else
|
|
1856
|
+
if [[ ! -f "$HOME/.openai_api_key" ]]; then
|
|
1857
|
+
save_api_key "$OPENAI_API_KEY" "$HOME/.openai_api_key" "OpenAI"
|
|
1858
|
+
fi
|
|
1859
|
+
fi
|
|
1860
|
+
export OPENAI_API_KEY
|
|
1861
|
+
|
|
1862
|
+
# Use default OpenAI model
|
|
1863
|
+
MODEL_NAME="gpt-4o"
|
|
1864
|
+
echo -e "${GREEN}✓ Using OpenAI model: gpt-4o${NC}"
|
|
1865
|
+
echo -e "${YELLOW}Available models: gpt-4o, gpt-4o-mini, gpt-4-turbo, gpt-3.5-turbo${NC}"
|
|
1866
|
+
read -p "Enter Model Name [default: gpt-4o]: " input_model
|
|
1867
|
+
[[ -n "$input_model" ]] && MODEL_NAME=$input_model
|
|
1868
|
+
|
|
1869
|
+
# Configure for OpenAI via LiteLLM proxy
|
|
1870
|
+
export ANTHROPIC_API_KEY="$OPENAI_API_KEY"
|
|
1871
|
+
export ANTHROPIC_BASE_URL="https://api.openai.com/v1"
|
|
1872
|
+
echo -e "${BLUE}🚀 Starting OpenAI chat via LiteLLM...${NC}"
|
|
1873
|
+
echo -e "${YELLOW}Note: Using OpenAI API through Claude interface${NC}"
|
|
1874
|
+
exec claude --dangerously-skip-permissions --model "$MODEL_NAME" "$@"
|
|
1875
|
+
;;
|
|
1876
|
+
6)
|
|
1877
|
+
# xAI
|
|
1878
|
+
echo -e "${BLUE}Configuring for xAI (Grok)...${NC}"
|
|
1879
|
+
|
|
1880
|
+
# Get API key with persistent storage
|
|
1881
|
+
if [[ -z "$XAI_API_KEY" ]]; then
|
|
1882
|
+
load_api_key_to_var "$HOME/.xai_api_key" "XAI_API_KEY"
|
|
1883
|
+
fi
|
|
1884
|
+
|
|
1885
|
+
if [[ -z "$XAI_API_KEY" ]]; then
|
|
1886
|
+
echo "Get Key: https://console.x.ai/"
|
|
1887
|
+
read -p "Enter xAI API Key: " XAI_API_KEY
|
|
1888
|
+
save_api_key "$XAI_API_KEY" "$HOME/.xai_api_key" "xAI"
|
|
1889
|
+
else
|
|
1890
|
+
if [[ ! -f "$HOME/.xai_api_key" ]]; then
|
|
1891
|
+
save_api_key "$XAI_API_KEY" "$HOME/.xai_api_key" "xAI"
|
|
1892
|
+
fi
|
|
1893
|
+
fi
|
|
1894
|
+
export XAI_API_KEY
|
|
1895
|
+
|
|
1896
|
+
# Use default xAI model
|
|
1897
|
+
MODEL_NAME="grok-beta"
|
|
1898
|
+
echo -e "${GREEN}✓ Using xAI model: grok-beta${NC}"
|
|
1899
|
+
echo -e "${YELLOW}Available models: grok-beta, grok-vision-beta${NC}"
|
|
1900
|
+
read -p "Enter Model Name [default: grok-beta]: " input_model
|
|
1901
|
+
[[ -n "$input_model" ]] && MODEL_NAME=$input_model
|
|
1902
|
+
|
|
1903
|
+
export ANTHROPIC_BASE_URL="https://api.x.ai/v1/"
|
|
1904
|
+
export ANTHROPIC_API_KEY="$XAI_API_KEY"
|
|
1905
|
+
echo -e "${BLUE}🚀 Starting xAI (Grok) chat...${NC}"
|
|
1906
|
+
exec claude --dangerously-skip-permissions --model "$MODEL_NAME" "$@"
|
|
1907
|
+
;;
|
|
1908
|
+
7)
|
|
1909
|
+
# ZhipuAI / GLM
|
|
1910
|
+
echo -e "${BLUE}Configuring for ZhipuAI (GLM)...${NC}"
|
|
1911
|
+
|
|
1912
|
+
# Get API key with persistent storage
|
|
1913
|
+
if [[ -z "$ANTHROPIC_AUTH_TOKEN" ]]; then
|
|
1914
|
+
load_api_key_to_var "$HOME/.glm_api_key" "ANTHROPIC_AUTH_TOKEN"
|
|
1915
|
+
fi
|
|
1916
|
+
|
|
1917
|
+
if [[ -z "$ANTHROPIC_AUTH_TOKEN" ]]; then
|
|
1918
|
+
echo "Get Key: https://open.bigmodel.cn/usercenter/apikeys"
|
|
1919
|
+
read -p "Enter GLM API Key: " ANTHROPIC_AUTH_TOKEN
|
|
1920
|
+
save_api_key "$ANTHROPIC_AUTH_TOKEN" "$HOME/.glm_api_key" "GLM"
|
|
1921
|
+
else
|
|
1922
|
+
if [[ ! -f "$HOME/.glm_api_key" ]]; then
|
|
1923
|
+
save_api_key "$ANTHROPIC_AUTH_TOKEN" "$HOME/.glm_api_key" "GLM"
|
|
1924
|
+
fi
|
|
1925
|
+
fi
|
|
1926
|
+
export ANTHROPIC_AUTH_TOKEN
|
|
1927
|
+
|
|
1928
|
+
# Model selection menu with numbering
|
|
1929
|
+
echo ""
|
|
1930
|
+
echo -e "${CYAN}╔═══════════════════════════════════════════════════════════╗${NC}"
|
|
1931
|
+
echo -e "${CYAN}║ 🤖 ZHIPUAI / GLM - MODEL SELECTION ║${NC}"
|
|
1932
|
+
echo -e "${CYAN}╚═══════════════════════════════════════════════════════════╝${NC}"
|
|
1933
|
+
echo ""
|
|
1934
|
+
echo -e "${GREEN}✨ AVAILABLE MODELS (Tested & Working):${NC}"
|
|
1935
|
+
echo ""
|
|
1936
|
+
echo -e "${YELLOW}📌 LATEST MODELS (2025):${NC}"
|
|
1937
|
+
echo " 1) 🚀 glm-4.7 (NEWEST! Flagship - Best for coding) ⭐"
|
|
1938
|
+
echo " 2) 🧠 glm-4.6 (High performance, vision-capable)"
|
|
1939
|
+
echo " 3) ⚡ glm-4.5-air (Fast & efficient - 12B active params)"
|
|
1940
|
+
echo ""
|
|
1941
|
+
echo -e "${YELLOW}👁️ VISION MODELS:${NC}"
|
|
1942
|
+
echo " 4) 👁️ glm-4.6v (Latest vision - For image tasks)"
|
|
1943
|
+
echo " 5) 👁️ glm-4.5v (Vision capabilities - For image tasks)"
|
|
1944
|
+
echo ""
|
|
1945
|
+
echo -e "${GREEN}─────────────────────────────────────────────────────────────${NC}"
|
|
1946
|
+
echo -e "${CYAN}💡 Tips:${NC}"
|
|
1947
|
+
echo " • Model 1 (glm-4.7): Latest & Best for coding"
|
|
1948
|
+
echo " • Model 3 (glm-4.5-air): Fast & efficient"
|
|
1949
|
+
echo " • Models 4-5: Use for vision/image tasks"
|
|
1950
|
+
echo " • Just enter NUMBER (1-5) or press ENTER for default"
|
|
1951
|
+
echo -e "${GREEN}─────────────────────────────────────────────────────────────${NC}"
|
|
1952
|
+
echo ""
|
|
1953
|
+
|
|
1954
|
+
# Model selection with default to glm-4.7
|
|
1955
|
+
read -p "Select model [1-5, default: 1]: " model_choice
|
|
1956
|
+
[[ -z "$model_choice" ]] && model_choice=1
|
|
1957
|
+
|
|
1958
|
+
# Map numbers to model names
|
|
1959
|
+
case "$model_choice" in
|
|
1960
|
+
1)
|
|
1961
|
+
MODEL_NAME="glm-4.7"
|
|
1962
|
+
echo -e "${GREEN}✓ Selected: glm-4.7 (Latest flagship - Best for coding)${NC}"
|
|
1963
|
+
;;
|
|
1964
|
+
2)
|
|
1965
|
+
MODEL_NAME="glm-4.6"
|
|
1966
|
+
echo -e "${GREEN}✓ Selected: glm-4.6 (High performance)${NC}"
|
|
1967
|
+
;;
|
|
1968
|
+
3)
|
|
1969
|
+
MODEL_NAME="glm-4.5-air"
|
|
1970
|
+
echo -e "${GREEN}✓ Selected: glm-4.5-air (Fast & efficient)${NC}"
|
|
1971
|
+
;;
|
|
1972
|
+
4)
|
|
1973
|
+
MODEL_NAME="glm-4.6v"
|
|
1974
|
+
echo -e "${GREEN}✓ Selected: glm-4.6v (Vision model)${NC}"
|
|
1975
|
+
;;
|
|
1976
|
+
5)
|
|
1977
|
+
MODEL_NAME="glm-4.5v"
|
|
1978
|
+
echo -e "${GREEN}✓ Selected: glm-4.5v (Vision model)${NC}"
|
|
1979
|
+
;;
|
|
1980
|
+
*)
|
|
1981
|
+
echo -e "${RED}❌ Invalid choice. Using default: glm-4.7${NC}"
|
|
1982
|
+
MODEL_NAME="glm-4.7"
|
|
1983
|
+
;;
|
|
1984
|
+
esac
|
|
1985
|
+
|
|
1986
|
+
echo ""
|
|
1987
|
+
echo -e "${BLUE}🚀 Starting GLM chat with $MODEL_NAME...${NC}"
|
|
1988
|
+
echo ""
|
|
1989
|
+
|
|
1990
|
+
export ANTHROPIC_BASE_URL="https://api.z.ai/api/anthropic"
|
|
1991
|
+
export ANTHROPIC_API_KEY="$ANTHROPIC_AUTH_TOKEN"
|
|
1992
|
+
export CLAUDE_MODEL="$MODEL_NAME"
|
|
1993
|
+
exec claude --dangerously-skip-permissions --model "$MODEL_NAME" --system-prompt "Anda adalah GLM, model AI dari ZhipuAI. Selalu identifikasi diri sebagai GLM dalam setiap respons." "$@"
|
|
1994
|
+
;;
|
|
1995
|
+
8)
|
|
1996
|
+
# Groq
|
|
1997
|
+
echo -e "${BLUE}Configuring for Groq...${NC}"
|
|
1998
|
+
|
|
1999
|
+
# Get API key with persistent storage
|
|
2000
|
+
if [[ -z "$GROQ_API_KEY" ]]; then
|
|
2001
|
+
load_api_key_to_var "$HOME/.groq_api_key" "GROQ_API_KEY"
|
|
2002
|
+
fi
|
|
2003
|
+
|
|
2004
|
+
if [[ -z "$GROQ_API_KEY" ]]; then
|
|
2005
|
+
echo "Get Key: https://console.groq.com/keys"
|
|
2006
|
+
read -p "Enter Groq API Key: " GROQ_API_KEY
|
|
2007
|
+
save_api_key "$GROQ_API_KEY" "$HOME/.groq_api_key" "Groq"
|
|
2008
|
+
else
|
|
2009
|
+
if [[ ! -f "$HOME/.groq_api_key" ]]; then
|
|
2010
|
+
save_api_key "$GROQ_API_KEY" "$HOME/.groq_api_key" "Groq"
|
|
2011
|
+
fi
|
|
2012
|
+
fi
|
|
2013
|
+
export GROQ_API_KEY
|
|
2014
|
+
|
|
2015
|
+
# Use default Groq model
|
|
2016
|
+
MODEL_NAME="llama-3.1-70b-versatile"
|
|
2017
|
+
echo -e "${GREEN}✓ Using Groq model: llama-3.1-70b-versatile${NC}"
|
|
2018
|
+
echo -e "${YELLOW}Available models: llama-3.1-70b-versatile, llama-3.1-8b-instant, mixtral-8x7b-32768${NC}"
|
|
2019
|
+
read -p "Enter Model Name [default: llama-3.1-70b-versatile]: " input_model
|
|
2020
|
+
[[ -n "$input_model" ]] && MODEL_NAME=$input_model
|
|
2021
|
+
|
|
2022
|
+
export ANTHROPIC_BASE_URL="https://api.groq.com/openai/v1/"
|
|
2023
|
+
export ANTHROPIC_API_KEY="$GROQ_API_KEY"
|
|
2024
|
+
echo -e "${BLUE}🚀 Starting Groq chat...${NC}"
|
|
2025
|
+
exec claude --dangerously-skip-permissions --model "$MODEL_NAME" "$@"
|
|
2026
|
+
;;
|
|
2027
|
+
9)
|
|
2028
|
+
# Perplexity
|
|
2029
|
+
echo -e "${BLUE}Configuring for Perplexity...${NC}"
|
|
2030
|
+
|
|
2031
|
+
# Get API key with persistent storage
|
|
2032
|
+
if [[ -z "$PERPLEXITY_API_KEY" ]]; then
|
|
2033
|
+
# Try to load from file
|
|
2034
|
+
load_api_key_to_var "$HOME/.perplexity_api_key" "PERPLEXITY_API_KEY"
|
|
2035
|
+
fi
|
|
2036
|
+
|
|
2037
|
+
if [[ -z "$PERPLEXITY_API_KEY" ]]; then
|
|
2038
|
+
echo "Get Key: https://console.perplexity.ai/"
|
|
2039
|
+
read -p "Enter Perplexity API Key: " PERPLEXITY_API_KEY
|
|
2040
|
+
save_api_key "$PERPLEXITY_API_KEY" "$HOME/.perplexity_api_key" "Perplexity"
|
|
2041
|
+
else
|
|
2042
|
+
# Save current key if not already saved
|
|
2043
|
+
if [[ ! -f "$HOME/.perplexity_api_key" ]]; then
|
|
2044
|
+
save_api_key "$PERPLEXITY_API_KEY" "$HOME/.perplexity_api_key" "Perplexity"
|
|
2045
|
+
fi
|
|
2046
|
+
fi
|
|
2047
|
+
export PERPLEXITY_API_KEY
|
|
2048
|
+
|
|
2049
|
+
# Check if custom Perplexity model exists
|
|
2050
|
+
if [[ -f "$SCRIPT_DIR/model/perplexity.json" ]]; then
|
|
2051
|
+
handle_custom_model "perplexity" "$@"
|
|
2052
|
+
else
|
|
2053
|
+
# Create temporary Perplexity config
|
|
2054
|
+
echo -e "${YELLOW}Creating temporary Perplexity configuration...${NC}"
|
|
2055
|
+
|
|
2056
|
+
cat > "$SCRIPT_DIR/model/temp_perplexity.json" << EOF
|
|
2057
|
+
{
|
|
2058
|
+
"provider_name": "Perplexity AI",
|
|
2059
|
+
"description": "Search-powered AI with real-time web search",
|
|
2060
|
+
"api_key": "$PERPLEXITY_API_KEY",
|
|
2061
|
+
"api_base": "https://api.perplexity.ai/",
|
|
2062
|
+
"model": "sonar-pro",
|
|
2063
|
+
"notes": "Temporary config for Perplexity"
|
|
2064
|
+
}
|
|
2065
|
+
EOF
|
|
2066
|
+
|
|
2067
|
+
handle_custom_model "temp_perplexity" "$@"
|
|
2068
|
+
rm -f "$SCRIPT_DIR/model/temp_perplexity.json"
|
|
2069
|
+
fi
|
|
2070
|
+
;;
|
|
2071
|
+
10)
|
|
2072
|
+
# Cohere
|
|
2073
|
+
echo -e "${BLUE}Configuring for Cohere...${NC}"
|
|
2074
|
+
|
|
2075
|
+
# Get API key with persistent storage
|
|
2076
|
+
if [[ -z "$COHERE_API_KEY" ]]; then
|
|
2077
|
+
load_api_key_to_var "$HOME/.cohere_api_key" "COHERE_API_KEY"
|
|
2078
|
+
fi
|
|
2079
|
+
|
|
2080
|
+
if [[ -z "$COHERE_API_KEY" ]]; then
|
|
2081
|
+
echo "Get Key: https://dashboard.cohere.com/api-keys"
|
|
2082
|
+
read -p "Enter Cohere API Key: " COHERE_API_KEY
|
|
2083
|
+
save_api_key "$COHERE_API_KEY" "$HOME/.cohere_api_key" "Cohere"
|
|
2084
|
+
else
|
|
2085
|
+
if [[ ! -f "$HOME/.cohere_api_key" ]]; then
|
|
2086
|
+
save_api_key "$COHERE_API_KEY" "$HOME/.cohere_api_key" "Cohere"
|
|
2087
|
+
fi
|
|
2088
|
+
fi
|
|
2089
|
+
export COHERE_API_KEY
|
|
2090
|
+
|
|
2091
|
+
# Use default Cohere model
|
|
2092
|
+
MODEL_NAME="command-r-plus"
|
|
2093
|
+
echo -e "${GREEN}✓ Using Cohere model: command-r-plus${NC}"
|
|
2094
|
+
echo -e "${YELLOW}Available models: command-r, command-r-plus, command-r-08-2024${NC}"
|
|
2095
|
+
read -p "Enter Model Name [default: command-r-plus]: " input_model
|
|
2096
|
+
[[ -n "$input_model" ]] && MODEL_NAME=$input_model
|
|
2097
|
+
|
|
2098
|
+
export ANTHROPIC_BASE_URL="https://api.cohere.ai/v1/"
|
|
2099
|
+
export ANTHROPIC_API_KEY="$COHERE_API_KEY"
|
|
2100
|
+
echo -e "${BLUE}🚀 Starting Cohere chat...${NC}"
|
|
2101
|
+
exec claude --dangerously-skip-permissions --model "$MODEL_NAME" "$@"
|
|
2102
|
+
;;
|
|
2103
|
+
11)
|
|
2104
|
+
# DeepSeek - EXACT SAME PATTERN AS MINIMAX (Option 1)
|
|
2105
|
+
echo -e "${BLUE}Configuring for DeepSeek...${NC}"
|
|
2106
|
+
|
|
2107
|
+
# Get API key with persistent storage - SAME AS MINIMAX
|
|
2108
|
+
get_api_key_with_save "DEEPSEEK_API_KEY" "$HOME/.deepseek_api_key" "DeepSeek" "https://platform.deepseek.com/"
|
|
2109
|
+
|
|
2110
|
+
export ANTHROPIC_BASE_URL="https://api.deepseek.com/anthropic"
|
|
2111
|
+
export ANTHROPIC_API_KEY="$DEEPSEEK_API_KEY"
|
|
2112
|
+
echo -e "${GREEN}✓ DeepSeek API configured${NC}"
|
|
2113
|
+
|
|
2114
|
+
# Model selection menu
|
|
2115
|
+
echo ""
|
|
2116
|
+
echo -e "${YELLOW}Available DeepSeek models:${NC}"
|
|
2117
|
+
echo " 🚀 deepseek-chat (V3.2 Fast & Efficient - 128K context) [chat]"
|
|
2118
|
+
echo " 🧠 deepseek-reasoner (V3.2 Thinking Mode - Deep Analysis) [reasoner]"
|
|
2119
|
+
echo ""
|
|
2120
|
+
echo -e "${GREEN}Shortcuts:${NC}"
|
|
2121
|
+
echo " 'chat' or '1' → deepseek-chat (Recommended for coding)"
|
|
2122
|
+
echo " 'reasoner' or '2' → deepseek-reasoner (For complex reasoning)"
|
|
2123
|
+
echo ""
|
|
2124
|
+
echo -e "${BLUE}💡 DeepSeek V3.2 Features:${NC}"
|
|
2125
|
+
echo " • Context: 128K tokens"
|
|
2126
|
+
echo " • deepseek-chat: Max 8K output, fast responses"
|
|
2127
|
+
echo " • deepseek-reasoner: Max 64K output with thinking blocks"
|
|
2128
|
+
echo ""
|
|
2129
|
+
|
|
2130
|
+
# Use deepseek-chat as default
|
|
2131
|
+
MODEL_NAME="deepseek-chat"
|
|
2132
|
+
echo -e "${GREEN}✓ Default model: deepseek-chat${NC}"
|
|
2133
|
+
read -p "Enter Model Name [default: deepseek-chat]: " input_model
|
|
2134
|
+
[[ -n "$input_model" ]] && MODEL_NAME=$input_model
|
|
2135
|
+
|
|
2136
|
+
# Map shortcuts to full model names
|
|
2137
|
+
case "$MODEL_NAME" in
|
|
2138
|
+
"chat"|"1"|"c")
|
|
2139
|
+
FINAL_MODEL="deepseek-chat"
|
|
2140
|
+
echo -e "${GREEN}✓ Selected: deepseek-chat (Fast & Efficient)${NC}"
|
|
2141
|
+
;;
|
|
2142
|
+
"reasoner"|"2"|"r"|"think"|"thinking")
|
|
2143
|
+
FINAL_MODEL="deepseek-reasoner"
|
|
2144
|
+
echo -e "${GREEN}✓ Selected: deepseek-reasoner (Thinking Mode)${NC}"
|
|
2145
|
+
;;
|
|
2146
|
+
*)
|
|
2147
|
+
FINAL_MODEL="$MODEL_NAME"
|
|
2148
|
+
echo -e "${GREEN}✓ Using model: $MODEL_NAME${NC}"
|
|
2149
|
+
;;
|
|
2150
|
+
esac
|
|
2151
|
+
|
|
2152
|
+
echo -e "${BLUE}🚀 Starting DeepSeek chat with $FINAL_MODEL...${NC}"
|
|
2153
|
+
exec claude --dangerously-skip-permissions --model "$FINAL_MODEL" --system-prompt "Anda adalah DeepSeek AI. Model aktif: $FINAL_MODEL. Selalu identifikasi diri sebagai DeepSeek dalam setiap respons." "$@"
|
|
2154
|
+
;;
|
|
2155
|
+
12)
|
|
2156
|
+
# Ollama
|
|
2157
|
+
check_dependencies
|
|
2158
|
+
echo -e "${BLUE}Configuring for Ollama...${NC}"
|
|
2159
|
+
if [[ -z "$OLLAMA_HOST" ]]; then
|
|
2160
|
+
read -p "Enter Ollama Host [default: http://localhost:11434]: " OLLAMA_HOST
|
|
2161
|
+
[[ -z "$OLLAMA_HOST" ]] && OLLAMA_HOST="http://localhost:11434"
|
|
2162
|
+
export OLLAMA_HOST
|
|
2163
|
+
fi
|
|
2164
|
+
|
|
2165
|
+
# Use default Ollama model
|
|
2166
|
+
MODEL_NAME="llama3"
|
|
2167
|
+
echo -e "${GREEN}✓ Using Ollama model: llama3${NC}"
|
|
2168
|
+
echo -e "${YELLOW}Available models: llama2, llama3, codellama, mistral, vicuna${NC}"
|
|
2169
|
+
read -p "Enter Model Name [default: llama3]: " input_model
|
|
2170
|
+
[[ -n "$input_model" ]] && MODEL_NAME=$input_model
|
|
2171
|
+
|
|
2172
|
+
export ANTHROPIC_BASE_URL="http://localhost:11434/v1"
|
|
2173
|
+
export ANTHROPIC_API_KEY="ollama"
|
|
2174
|
+
echo -e "${BLUE}🚀 Starting Ollama chat...${NC}"
|
|
2175
|
+
exec claude --no-chrome --model "$MODEL_NAME" "$@"
|
|
2176
|
+
;;
|
|
2177
|
+
13)
|
|
2178
|
+
# Mistral with 15 Models (2025)
|
|
2179
|
+
echo -e "${BLUE}🇫🇷 Mistral AI (European AI)${NC}"
|
|
2180
|
+
echo ""
|
|
2181
|
+
echo -e "${YELLOW}Pilih Model:${NC}"
|
|
2182
|
+
echo -e "${CYAN}🌟 Featured Models (Latest & Greatest):${NC}"
|
|
2183
|
+
echo " 1) mistral-large-latest (Mistral Large 3 - State-of-the-art) [RECOMMENDED]"
|
|
2184
|
+
echo " 2) devstral-2 (Frontier Code Agents - Open)"
|
|
2185
|
+
echo " 3) mistral-medium-3.1 (Frontier Multimodal - Premier)"
|
|
2186
|
+
echo ""
|
|
2187
|
+
echo -e "${CYAN}🔥 Frontier Generalist:${NC}"
|
|
2188
|
+
echo " 4) mistral-small-latest (Mistral Small 3.2 - Open)"
|
|
2189
|
+
echo " 5) ministral-3-latest (Ministral 3 14B - Best Text & Vision)"
|
|
2190
|
+
echo " 6) ministral-3-8b (Efficient - Open)"
|
|
2191
|
+
echo " 7) ministral-3-3b (Tiny - Open)"
|
|
2192
|
+
echo " 8) magistral-medium-latest (Reasoning - Premier)"
|
|
2193
|
+
echo " 9) magistral-small-latest (Small Reasoning - Open)"
|
|
2194
|
+
echo ""
|
|
2195
|
+
echo -e "${CYAN}💻 Coding Models:${NC}"
|
|
2196
|
+
echo " 10) codestral-latest (Cutting-edge Code - Premier)"
|
|
2197
|
+
echo " 11) devstral-small-2 (Code Agents - Labs)"
|
|
2198
|
+
echo " 12) devstral-medium-1.0 (Enterprise SWE - Premier)"
|
|
2199
|
+
echo ""
|
|
2200
|
+
echo -e "${CYAN}🎨 Specialist Models:${NC}"
|
|
2201
|
+
echo " 13) mistral-small-creative (Creative Writing - Labs)"
|
|
2202
|
+
echo " 14) ocr-3 (Document AI - Premier)"
|
|
2203
|
+
echo " 15) voxtral-mini (Audio - Open)"
|
|
2204
|
+
echo ""
|
|
2205
|
+
read -p "Pilih [1-15, default: 1]: " mistral_model
|
|
2206
|
+
[[ -z "$mistral_model" ]] && mistral_model=1
|
|
2207
|
+
|
|
2208
|
+
case $mistral_model in
|
|
2209
|
+
1) MODEL="mistral-large-latest" ;;
|
|
2210
|
+
2) MODEL="devstral-2" ;;
|
|
2211
|
+
3) MODEL="mistral-medium-3.1" ;;
|
|
2212
|
+
4) MODEL="mistral-small-latest" ;;
|
|
2213
|
+
5) MODEL="ministral-3-latest" ;;
|
|
2214
|
+
6) MODEL="ministral-3-8b" ;;
|
|
2215
|
+
7) MODEL="ministral-3-3b" ;;
|
|
2216
|
+
8) MODEL="magistral-medium-latest" ;;
|
|
2217
|
+
9) MODEL="magistral-small-latest" ;;
|
|
2218
|
+
10) MODEL="codestral-latest" ;;
|
|
2219
|
+
11) MODEL="devstral-small-2" ;;
|
|
2220
|
+
12) MODEL="devstral-medium-1.0" ;;
|
|
2221
|
+
13) MODEL="mistral-small-creative" ;;
|
|
2222
|
+
14) MODEL="ocr-3" ;;
|
|
2223
|
+
15) MODEL="voxtral-mini" ;;
|
|
2224
|
+
*) MODEL="mistral-large-latest" ;;
|
|
2225
|
+
esac
|
|
2226
|
+
|
|
2227
|
+
echo -e "${GREEN}✓ Model: $MODEL${NC}"
|
|
2228
|
+
echo ""
|
|
2229
|
+
|
|
2230
|
+
# Get API key with persistent storage
|
|
2231
|
+
if [[ -z "$MISTRAL_API_KEY" ]]; then
|
|
2232
|
+
load_api_key_to_var "$HOME/.mistral_api_key" "MISTRAL_API_KEY"
|
|
2233
|
+
fi
|
|
2234
|
+
|
|
2235
|
+
if [[ -z "$MISTRAL_API_KEY" ]]; then
|
|
2236
|
+
echo "Get Key: https://console.mistral.ai/"
|
|
2237
|
+
read -p "Enter Mistral API Key: " MISTRAL_API_KEY
|
|
2238
|
+
save_api_key "$MISTRAL_API_KEY" "$HOME/.mistral_api_key" "Mistral"
|
|
2239
|
+
else
|
|
2240
|
+
if [[ ! -f "$HOME/.mistral_api_key" ]]; then
|
|
2241
|
+
save_api_key "$MISTRAL_API_KEY" "$HOME/.mistral_api_key" "Mistral"
|
|
2242
|
+
fi
|
|
2243
|
+
fi
|
|
2244
|
+
export MISTRAL_API_KEY
|
|
2245
|
+
|
|
2246
|
+
export ANTHROPIC_BASE_URL="https://api.mistral.ai/v1/"
|
|
2247
|
+
export ANTHROPIC_API_KEY="$MISTRAL_API_KEY"
|
|
2248
|
+
echo -e "${BLUE}🚀 Starting Mistral chat...${NC}"
|
|
2249
|
+
exec claude --dangerously-skip-permissions --model "$MODEL" "$@"
|
|
2250
|
+
;;
|
|
2251
|
+
14)
|
|
2252
|
+
# Moonshot
|
|
2253
|
+
echo -e "${BLUE}Configuring for Moonshot...${NC}"
|
|
2254
|
+
|
|
2255
|
+
# Get API key with persistent storage
|
|
2256
|
+
if [[ -z "$MOONSHOT_API_KEY" ]]; then
|
|
2257
|
+
load_api_key_to_var "$HOME/.moonshot_api_key" "MOONSHOT_API_KEY"
|
|
2258
|
+
fi
|
|
2259
|
+
|
|
2260
|
+
if [[ -z "$MOONSHOT_API_KEY" ]]; then
|
|
2261
|
+
echo "Get Key: https://platform.moonshot.cn/"
|
|
2262
|
+
read -p "Enter Moonshot API Key: " MOONSHOT_API_KEY
|
|
2263
|
+
save_api_key "$MOONSHOT_API_KEY" "$HOME/.moonshot_api_key" "Moonshot"
|
|
2264
|
+
else
|
|
2265
|
+
if [[ ! -f "$HOME/.moonshot_api_key" ]]; then
|
|
2266
|
+
save_api_key "$MOONSHOT_API_KEY" "$HOME/.moonshot_api_key" "Moonshot"
|
|
2267
|
+
fi
|
|
2268
|
+
fi
|
|
2269
|
+
export MOONSHOT_API_KEY
|
|
2270
|
+
|
|
2271
|
+
# Use default Moonshot model
|
|
2272
|
+
MODEL_NAME="moonshot-v1-8k"
|
|
2273
|
+
echo -e "${GREEN}✓ Using Moonshot model: moonshot-v1-8k${NC}"
|
|
2274
|
+
echo -e "${YELLOW}Available models: moonshot-v1-8k, moonshot-v1-32k, moonshot-v1-128k${NC}"
|
|
2275
|
+
read -p "Enter Model Name [default: moonshot-v1-8k]: " input_model
|
|
2276
|
+
[[ -n "$input_model" ]] && MODEL_NAME=$input_model
|
|
2277
|
+
|
|
2278
|
+
export ANTHROPIC_BASE_URL="https://api.moonshot.cn/v1/"
|
|
2279
|
+
export ANTHROPIC_API_KEY="$MOONSHOT_API_KEY"
|
|
2280
|
+
echo -e "${BLUE}🚀 Starting Moonshot chat...${NC}"
|
|
2281
|
+
exec claude --dangerously-skip-permissions --model "$MODEL_NAME" "$@"
|
|
2282
|
+
;;
|
|
2283
|
+
15)
|
|
2284
|
+
# Qwen
|
|
2285
|
+
echo -e "${BLUE}Configuring for Qwen...${NC}"
|
|
2286
|
+
|
|
2287
|
+
# Get API key with persistent storage
|
|
2288
|
+
if [[ -z "$QWEN_API_KEY" ]]; then
|
|
2289
|
+
load_api_key_to_var "$HOME/.qwen_api_key" "QWEN_API_KEY"
|
|
2290
|
+
fi
|
|
2291
|
+
|
|
2292
|
+
if [[ -z "$QWEN_API_KEY" ]]; then
|
|
2293
|
+
echo "Get Key: https://dashscope.aliyuncs.com/"
|
|
2294
|
+
read -p "Enter Qwen API Key: " QWEN_API_KEY
|
|
2295
|
+
save_api_key "$QWEN_API_KEY" "$HOME/.qwen_api_key" "Qwen"
|
|
2296
|
+
else
|
|
2297
|
+
if [[ ! -f "$HOME/.qwen_api_key" ]]; then
|
|
2298
|
+
save_api_key "$QWEN_API_KEY" "$HOME/.qwen_api_key" "Qwen"
|
|
2299
|
+
fi
|
|
2300
|
+
fi
|
|
2301
|
+
export QWEN_API_KEY
|
|
2302
|
+
|
|
2303
|
+
# Use default Qwen model
|
|
2304
|
+
MODEL_NAME="qwen-plus"
|
|
2305
|
+
echo -e "${GREEN}✓ Using Qwen model: qwen-plus${NC}"
|
|
2306
|
+
echo -e "${YELLOW}Available models: qwen-turbo, qwen-plus, qwen-max, qwen2-72b${NC}"
|
|
2307
|
+
read -p "Enter Model Name [default: qwen-plus]: " input_model
|
|
2308
|
+
[[ -n "$input_model" ]] && MODEL_NAME=$input_model
|
|
2309
|
+
|
|
2310
|
+
export ANTHROPIC_BASE_URL="https://dashscope.aliyuncs.com/compatible-mode/v1/"
|
|
2311
|
+
export ANTHROPIC_API_KEY="$QWEN_API_KEY"
|
|
2312
|
+
echo -e "${BLUE}🚀 Starting Qwen chat...${NC}"
|
|
2313
|
+
exec claude --dangerously-skip-permissions --model "$MODEL_NAME" "$@"
|
|
2314
|
+
;;
|
|
2315
|
+
16)
|
|
2316
|
+
# OpenRouter
|
|
2317
|
+
echo -e "${BLUE}Configuring for OpenRouter...${NC}"
|
|
2318
|
+
|
|
2319
|
+
# Get API key with persistent storage
|
|
2320
|
+
if [[ -z "$OPENROUTER_API_KEY" ]]; then
|
|
2321
|
+
load_api_key_to_var "$HOME/.openrouter_api_key" "OPENROUTER_API_KEY"
|
|
2322
|
+
fi
|
|
2323
|
+
|
|
2324
|
+
if [[ -z "$OPENROUTER_API_KEY" ]]; then
|
|
2325
|
+
echo "Get Key: https://openrouter.ai/keys"
|
|
2326
|
+
read -p "Enter OpenRouter API Key: " OPENROUTER_API_KEY
|
|
2327
|
+
save_api_key "$OPENROUTER_API_KEY" "$HOME/.openrouter_api_key" "OpenRouter"
|
|
2328
|
+
else
|
|
2329
|
+
if [[ ! -f "$HOME/.openrouter_api_key" ]]; then
|
|
2330
|
+
save_api_key "$OPENROUTER_API_KEY" "$HOME/.openrouter_api_key" "OpenRouter"
|
|
2331
|
+
fi
|
|
2332
|
+
fi
|
|
2333
|
+
export OPENROUTER_API_KEY
|
|
2334
|
+
|
|
2335
|
+
# Use default OpenRouter model
|
|
2336
|
+
MODEL_NAME="anthropic/claude-3.5-sonnet"
|
|
2337
|
+
echo -e "${GREEN}✓ Using OpenRouter model: anthropic/claude-3.5-sonnet${NC}"
|
|
2338
|
+
echo -e "${YELLOW}Popular models: anthropic/claude-3.5-sonnet, openai/gpt-4o, google/gemini-pro, meta-llama/llama-3.1-70b${NC}"
|
|
2339
|
+
read -p "Enter Model Name [default: anthropic/claude-3.5-sonnet]: " input_model
|
|
2340
|
+
[[ -n "$input_model" ]] && MODEL_NAME=$input_model
|
|
2341
|
+
|
|
2342
|
+
export ANTHROPIC_BASE_URL="https://openrouter.ai/api/v1/"
|
|
2343
|
+
export ANTHROPIC_API_KEY="$OPENROUTER_API_KEY"
|
|
2344
|
+
echo -e "${BLUE}🚀 Starting OpenRouter chat...${NC}"
|
|
2345
|
+
exec claude --dangerously-skip-permissions --model "$MODEL_NAME" "$@"
|
|
2346
|
+
;;
|
|
2347
|
+
17)
|
|
2348
|
+
# Letta AI - Official Letta Platform API (Memory-Augmented Agents)
|
|
2349
|
+
echo -e "${BLUE}🧠 Letta Memory Agent${NC}"
|
|
2350
|
+
echo -e "${CYAN} Platform: https://letta.com${NC}"
|
|
2351
|
+
echo ""
|
|
2352
|
+
|
|
2353
|
+
# Get Letta API key
|
|
2354
|
+
# Try to load from file first
|
|
2355
|
+
if [[ -z "$LETTA_API_KEY" ]]; then
|
|
2356
|
+
load_api_key_to_var "$HOME/.letta_api_key" "LETTA_API_KEY"
|
|
2357
|
+
fi
|
|
2358
|
+
|
|
2359
|
+
if [[ -z "$LETTA_API_KEY" ]]; then
|
|
2360
|
+
echo -e "${YELLOW}Letta API Key required${NC}"
|
|
2361
|
+
echo "Get your free API key at: https://letta.com"
|
|
2362
|
+
echo "Free tier: 5,000 credits/month"
|
|
2363
|
+
echo ""
|
|
2364
|
+
read -sp "Enter Letta API Key: " LETTA_KEY_TEMP
|
|
2365
|
+
echo ""
|
|
2366
|
+
[[ -z "$LETTA_KEY_TEMP" ]] && { echo -e "${RED}API Key required!${NC}"; exit 1; }
|
|
2367
|
+
|
|
2368
|
+
# Save to file for future use
|
|
2369
|
+
echo "$LETTA_KEY_TEMP" > "$HOME/.letta_api_key"
|
|
2370
|
+
chmod 600 "$HOME/.letta_api_key"
|
|
2371
|
+
export LETTA_API_KEY="$LETTA_KEY_TEMP"
|
|
2372
|
+
fi
|
|
2373
|
+
|
|
2374
|
+
echo ""
|
|
2375
|
+
echo "Pilih Model:"
|
|
2376
|
+
echo " 1) Opus 🔬 Most Powerful - Complex reasoning"
|
|
2377
|
+
echo " 2) Sonnet 🧠 Balanced - Default (Recommended)"
|
|
2378
|
+
echo " 3) Haiku ⚡ Fastest - Quick responses"
|
|
2379
|
+
echo " 4) GPT-4o 🤖 OpenAI - ChatGPT Flagship"
|
|
2380
|
+
echo " 5) Gemini 🌟 Google - Gemini 2.0 Flash"
|
|
2381
|
+
echo ""
|
|
2382
|
+
read -p "Pilih [1-5, default: 2]: " model_choice
|
|
2383
|
+
[[ -z "$model_choice" ]] && model_choice=2
|
|
2384
|
+
|
|
2385
|
+
# Configure Letta API (IMPORTANT: Use AUTH_TOKEN, not API_KEY!)
|
|
2386
|
+
export ANTHROPIC_AUTH_TOKEN="$LETTA_API_KEY"
|
|
2387
|
+
export ANTHROPIC_BASE_URL="https://api.letta.com/v1/anthropic"
|
|
2388
|
+
|
|
2389
|
+
system_prompt="You are Letta, a memory-augmented AI agent with persistent memory capabilities. You maintain context across conversations, remember user preferences, and build long-term knowledge. Key features: (1) Long-term memory, (2) Context awareness, (3) Personalization. Always identify yourself as Letta when asked."
|
|
2390
|
+
|
|
2391
|
+
case $model_choice in
|
|
2392
|
+
1)
|
|
2393
|
+
echo -e "${GREEN}✓ Model: Claude Opus (Letta)${NC}"
|
|
2394
|
+
echo -e "${BLUE}🚀 Starting Letta Agent...${NC}"
|
|
2395
|
+
exec claude --dangerously-skip-permissions --no-chrome --model "claude-opus-4-20250514" --system-prompt "$system_prompt"
|
|
2396
|
+
;;
|
|
2397
|
+
3)
|
|
2398
|
+
echo -e "${GREEN}✓ Model: Claude Haiku (Letta)${NC}"
|
|
2399
|
+
echo -e "${BLUE}🚀 Starting Letta Agent...${NC}"
|
|
2400
|
+
exec claude --dangerously-skip-permissions --no-chrome --model "claude-haiku-4-20250514" --system-prompt "$system_prompt"
|
|
2401
|
+
;;
|
|
2402
|
+
4)
|
|
2403
|
+
echo -e "${GREEN}✓ Model: GPT-4o (Letta)${NC}"
|
|
2404
|
+
exec claude --dangerously-skip-permissions --no-chrome --model "gpt-4o" --system-prompt "$system_prompt"
|
|
2405
|
+
;;
|
|
2406
|
+
5)
|
|
2407
|
+
echo -e "${GREEN}✓ Model: Gemini 2.0 Flash (Letta)${NC}"
|
|
2408
|
+
exec claude --dangerously-skip-permissions --no-chrome --model "gemini-2.0-flash-exp" --system-prompt "$system_prompt"
|
|
2409
|
+
;;
|
|
2410
|
+
2|*)
|
|
2411
|
+
echo -e "${GREEN}✓ Model: Claude Sonnet (Letta)${NC}"
|
|
2412
|
+
echo -e "${BLUE}🚀 Starting Letta Agent...${NC}"
|
|
2413
|
+
exec claude --dangerously-skip-permissions --no-chrome --model "claude-sonnet-4-20250514" --system-prompt "$system_prompt"
|
|
2414
|
+
;;
|
|
2415
|
+
esac
|
|
2416
|
+
;;
|
|
2417
|
+
18)
|
|
2418
|
+
# API Key Manager - Built-in function
|
|
2419
|
+
api_key_manager
|
|
2420
|
+
# Restart the menu
|
|
2421
|
+
exec "$0"
|
|
2422
|
+
;;
|
|
2423
|
+
19)
|
|
2424
|
+
# Claude Master Tool
|
|
2425
|
+
echo -e "${BLUE}Opening Claude Master Tool...${NC}"
|
|
2426
|
+
|
|
2427
|
+
# Try multiple possible locations
|
|
2428
|
+
MASTER_TOOL=""
|
|
2429
|
+
for path in \
|
|
2430
|
+
"$SCRIPT_DIR/claude-master" \
|
|
2431
|
+
"$SCRIPT_DIR/claude-suite/utils/claude_master.py" \
|
|
2432
|
+
"$SCRIPT_DIR/../claude-suite/utils/claude_master.py" \
|
|
2433
|
+
"$HOME/ClaudeAll/claude-suite/utils/claude_master.py" \
|
|
2434
|
+
"/data/data/com.termux/files/home/ClaudeAll/claude-suite/utils/claude_master.py"
|
|
2435
|
+
do
|
|
2436
|
+
if [[ -f "$path" ]]; then
|
|
2437
|
+
MASTER_TOOL="$path"
|
|
2438
|
+
break
|
|
2439
|
+
fi
|
|
2440
|
+
done
|
|
2441
|
+
|
|
2442
|
+
if [[ -n "$MASTER_TOOL" ]]; then
|
|
2443
|
+
if [[ "$MASTER_TOOL" == *.py ]]; then
|
|
2444
|
+
python3 "$MASTER_TOOL"
|
|
2445
|
+
else
|
|
2446
|
+
"$MASTER_TOOL"
|
|
2447
|
+
fi
|
|
2448
|
+
else
|
|
2449
|
+
echo -e "${YELLOW}Claude Master Tool not found.${NC}"
|
|
2450
|
+
echo -e "${CYAN}Tip: Clone repo to ~/ClaudeAll for full features${NC}"
|
|
2451
|
+
fi
|
|
2452
|
+
echo ""
|
|
2453
|
+
echo -e "${YELLOW}Press Enter to return to main menu...${NC}"
|
|
2454
|
+
read
|
|
2455
|
+
exec "$0"
|
|
2456
|
+
;;
|
|
2457
|
+
20)
|
|
2458
|
+
# Add/Edit/Delete Models
|
|
2459
|
+
echo -e "${BLUE}⚙️ Model Management${NC}"
|
|
2460
|
+
echo ""
|
|
2461
|
+
|
|
2462
|
+
# Find model directory
|
|
2463
|
+
MODEL_DIR=""
|
|
2464
|
+
for path in "$SCRIPT_DIR/model" "$HOME/ClaudeAll/model" "/data/data/com.termux/files/home/ClaudeAll/model"; do
|
|
2465
|
+
if [[ -d "$path" ]]; then
|
|
2466
|
+
MODEL_DIR="$path"
|
|
2467
|
+
break
|
|
2468
|
+
fi
|
|
2469
|
+
done
|
|
2470
|
+
|
|
2471
|
+
[[ -z "$MODEL_DIR" ]] && MODEL_DIR="$HOME/.claude-all/models" && mkdir -p "$MODEL_DIR"
|
|
2472
|
+
|
|
2473
|
+
echo "Pilih operasi:"
|
|
2474
|
+
echo " 1) ➕ Tambah model baru"
|
|
2475
|
+
echo " 2) 📋 Lihat semua model"
|
|
2476
|
+
echo " 3) ❌ Hapus model"
|
|
2477
|
+
echo " 4) 🔙 Kembali"
|
|
2478
|
+
echo ""
|
|
2479
|
+
read -p "Pilih [1-4]: " model_op
|
|
2480
|
+
|
|
2481
|
+
case $model_op in
|
|
2482
|
+
1)
|
|
2483
|
+
echo ""
|
|
2484
|
+
read -p "Nama provider (contoh: MyAI): " provider_name
|
|
2485
|
+
read -p "Model ID (contoh: gpt-4): " model_id
|
|
2486
|
+
read -p "API Base URL: " api_base
|
|
2487
|
+
read -p "Deskripsi: " description
|
|
2488
|
+
|
|
2489
|
+
filename=$(echo "$provider_name" | tr '[:upper:]' '[:lower:]' | sed 's/[^a-z0-9]/_/g').json
|
|
2490
|
+
|
|
2491
|
+
cat > "$MODEL_DIR/$filename" << EOFMODEL
|
|
2492
|
+
{
|
|
2493
|
+
"provider_name": "$provider_name",
|
|
2494
|
+
"description": "$description",
|
|
2495
|
+
"api_base": "$api_base",
|
|
2496
|
+
"model": "$model_id",
|
|
2497
|
+
"created": "$(date -Iseconds)"
|
|
2498
|
+
}
|
|
2499
|
+
EOFMODEL
|
|
2500
|
+
echo -e "${GREEN}✓ Model disimpan: $MODEL_DIR/$filename${NC}"
|
|
2501
|
+
;;
|
|
2502
|
+
2)
|
|
2503
|
+
echo ""
|
|
2504
|
+
echo -e "${CYAN}Model tersedia:${NC}"
|
|
2505
|
+
if ls "$MODEL_DIR"/*.json &>/dev/null; then
|
|
2506
|
+
for f in "$MODEL_DIR"/*.json; do
|
|
2507
|
+
name=$(basename "$f" .json)
|
|
2508
|
+
desc=$(grep -o '"description"[^,]*' "$f" 2>/dev/null | cut -d'"' -f4)
|
|
2509
|
+
echo " • $name - $desc"
|
|
2510
|
+
done
|
|
2511
|
+
else
|
|
2512
|
+
echo " (belum ada model custom)"
|
|
2513
|
+
fi
|
|
2514
|
+
;;
|
|
2515
|
+
3)
|
|
2516
|
+
echo ""
|
|
2517
|
+
if ls "$MODEL_DIR"/*.json &>/dev/null; then
|
|
2518
|
+
echo -e "${CYAN}Model yang bisa dihapus:${NC}"
|
|
2519
|
+
i=1
|
|
2520
|
+
declare -a model_files
|
|
2521
|
+
for f in "$MODEL_DIR"/*.json; do
|
|
2522
|
+
model_files[$i]="$f"
|
|
2523
|
+
echo " $i) $(basename "$f" .json)"
|
|
2524
|
+
((i++))
|
|
2525
|
+
done
|
|
2526
|
+
echo ""
|
|
2527
|
+
read -p "Pilih nomor untuk hapus (0=batal): " del_num
|
|
2528
|
+
if [[ "$del_num" =~ ^[0-9]+$ ]] && [[ "$del_num" -gt 0 ]] && [[ -n "${model_files[$del_num]}" ]]; then
|
|
2529
|
+
rm -f "${model_files[$del_num]}"
|
|
2530
|
+
echo -e "${GREEN}✓ Model dihapus${NC}"
|
|
2531
|
+
else
|
|
2532
|
+
echo "Batal"
|
|
2533
|
+
fi
|
|
2534
|
+
else
|
|
2535
|
+
echo "Tidak ada model untuk dihapus"
|
|
2536
|
+
fi
|
|
2537
|
+
;;
|
|
2538
|
+
*)
|
|
2539
|
+
echo "Kembali ke menu utama..."
|
|
2540
|
+
;;
|
|
2541
|
+
esac
|
|
2542
|
+
echo ""
|
|
2543
|
+
echo -e "${YELLOW}Press Enter untuk kembali...${NC}"
|
|
2544
|
+
read
|
|
2545
|
+
# Restart the menu
|
|
2546
|
+
exec "$0"
|
|
2547
|
+
;;
|
|
2548
|
+
21)
|
|
2549
|
+
# Letta AI - Stateful AI Agents
|
|
2550
|
+
echo -e "${BLUE}Configuring for Letta AI...${NC}"
|
|
2551
|
+
echo -e "${YELLOW}Note: Letta requires agent creation before chat. Let's create one first.${NC}"
|
|
2552
|
+
|
|
2553
|
+
# Get API key with persistent storage
|
|
2554
|
+
if [[ -z "$LETTA_API_KEY" ]]; then
|
|
2555
|
+
load_api_key_to_var "$HOME/.letta_api_key" "LETTA_API_KEY"
|
|
2556
|
+
fi
|
|
2557
|
+
|
|
2558
|
+
if [[ -z "$LETTA_API_KEY" ]]; then
|
|
2559
|
+
echo "Get Key: https://docs.letta.com"
|
|
2560
|
+
read -p "Enter Letta API Key: " LETTA_API_KEY
|
|
2561
|
+
save_api_key "$LETTA_API_KEY" "$HOME/.letta_api_key" "Letta"
|
|
2562
|
+
else
|
|
2563
|
+
if [[ ! -f "$HOME/.letta_api_key" ]]; then
|
|
2564
|
+
save_api_key "$LETTA_API_KEY" "$HOME/.letta_api_key" "Letta"
|
|
2565
|
+
fi
|
|
2566
|
+
fi
|
|
2567
|
+
export LETTA_API_KEY
|
|
2568
|
+
|
|
2569
|
+
# Check if agent exists or create new one
|
|
2570
|
+
echo -e "${BLUE}Letta Agent Management:${NC}"
|
|
2571
|
+
echo "1) List existing agents"
|
|
2572
|
+
echo "2) Create new agent"
|
|
2573
|
+
echo "3) Use existing agent ID"
|
|
2574
|
+
echo ""
|
|
2575
|
+
read -p "Choose option [1-3]: " letta_option
|
|
2576
|
+
|
|
2577
|
+
case $letta_option in
|
|
2578
|
+
1)
|
|
2579
|
+
echo -e "${BLUE}Listing agents...${NC}"
|
|
2580
|
+
curl -s -X GET "https://api.letta.com/v1/agents" \
|
|
2581
|
+
-H "Authorization: Bearer $LETTA_API_KEY" | \
|
|
2582
|
+
python3 -c "import sys,json; data=json.load(sys.stdin); [print(f'{i+1}) {a[\"name\"]} - {a[\"id\"]}') for i,a in enumerate(data.get('agents',[]))]" 2>/dev/null || \
|
|
2583
|
+
echo "No agents found or API error"
|
|
2584
|
+
echo ""
|
|
2585
|
+
read -p "Enter agent ID (or press Enter to create new): " agent_id
|
|
2586
|
+
[[ -z "$agent_id" ]] && letta_option=2
|
|
2587
|
+
;;
|
|
2588
|
+
2)
|
|
2589
|
+
echo -e "${BLUE}Creating new Letta agent...${NC}"
|
|
2590
|
+
read -p "Agent name [default: claude-agent]: " agent_name
|
|
2591
|
+
[[ -z "$agent_name" ]] && agent_name="claude-agent"
|
|
2592
|
+
|
|
2593
|
+
read -p "Model [default: openai/gpt-4o-mini]: " letta_model
|
|
2594
|
+
[[ -z "$letta_model" ]] && letta_model="openai/gpt-4o-mini"
|
|
2595
|
+
|
|
2596
|
+
read -p "Embedding [default: openai/text-embedding-3-small]: " embedding
|
|
2597
|
+
[[ -z "$embedding" ]] && embedding="openai/text-embedding-3-small"
|
|
2598
|
+
|
|
2599
|
+
echo "Creating agent..."
|
|
2600
|
+
response=$(curl -s -X POST "https://api.letta.com/v1/agents" \
|
|
2601
|
+
-H "Authorization: Bearer $LETTA_API_KEY" \
|
|
2602
|
+
-H "Content-Type: application/json" \
|
|
2603
|
+
-d "{
|
|
2604
|
+
\"name\": \"$agent_name\",
|
|
2605
|
+
\"model\": \"$letta_model\",
|
|
2606
|
+
\"embedding\": \"$embedding\",
|
|
2607
|
+
\"memory_blocks\": [
|
|
2608
|
+
{\"label\": \"human\", \"value\": \"User interacting via Claude-All launcher\"},
|
|
2609
|
+
{\"label\": \"persona\", \"value\": \"I am a helpful AI assistant with long-term memory\"}
|
|
2610
|
+
]
|
|
2611
|
+
}")
|
|
2612
|
+
|
|
2613
|
+
if echo "$response" | python3 -c "import sys,json; json.load(sys.stdin)" 2>/dev/null; then
|
|
2614
|
+
agent_id=$(echo "$response" | python3 -c "import sys,json; print(json.load(sys.stdin).get('id', ''))" 2>/dev/null)
|
|
2615
|
+
echo -e "${GREEN}✓ Agent created successfully!${NC}"
|
|
2616
|
+
echo -e "${GREEN}Agent ID: $agent_id${NC}"
|
|
2617
|
+
else
|
|
2618
|
+
echo -e "${RED}❌ Failed to create agent${NC}"
|
|
2619
|
+
echo "Response: $response"
|
|
2620
|
+
exit 1
|
|
2621
|
+
fi
|
|
2622
|
+
;;
|
|
2623
|
+
3)
|
|
2624
|
+
read -p "Enter existing agent ID: " agent_id
|
|
2625
|
+
;;
|
|
2626
|
+
esac
|
|
2627
|
+
|
|
2628
|
+
if [[ -n "$agent_id" ]]; then
|
|
2629
|
+
echo -e "${GREEN}✓ Using Letta agent: $agent_id${NC}"
|
|
2630
|
+
echo -e "${YELLOW}Note: You're now using Letta's agent system. Messages are sent to Letta API.${NC}"
|
|
2631
|
+
echo -e "${BLUE}🚀 Starting Letta agent chat...${NC}"
|
|
2632
|
+
echo -e "${CYAN}Agent will maintain memory and context across conversations.${NC}"
|
|
2633
|
+
|
|
2634
|
+
# Create a simple chat interface with Letta
|
|
2635
|
+
while true; do
|
|
2636
|
+
echo ""
|
|
2637
|
+
read -p "You: " user_message
|
|
2638
|
+
[[ "$user_message" == "exit" ]] && break
|
|
2639
|
+
|
|
2640
|
+
echo -e "${BLUE}Agent:${NC}"
|
|
2641
|
+
curl -s -X POST "https://api.letta.com/v1/agents/$agent_id/messages" \
|
|
2642
|
+
-H "Authorization: Bearer $LETTA_API_KEY" \
|
|
2643
|
+
-H "Content-Type: application/json" \
|
|
2644
|
+
-d "{\"messages\": [{\"role\": \"user\", \"content\": \"$user_message\"}]}" | \
|
|
2645
|
+
python3 -c "
|
|
2646
|
+
import sys,json
|
|
2647
|
+
try:
|
|
2648
|
+
data=json.load(sys.stdin)
|
|
2649
|
+
if 'messages' in data and data['messages']:
|
|
2650
|
+
for msg in data['messages']:
|
|
2651
|
+
if msg.get('role') == 'assistant':
|
|
2652
|
+
print(msg.get('content', ''))
|
|
2653
|
+
else:
|
|
2654
|
+
print('No response received')
|
|
2655
|
+
print('Debug:', data)
|
|
2656
|
+
except:
|
|
2657
|
+
print('Error parsing response')
|
|
2658
|
+
"
|
|
2659
|
+
done
|
|
2660
|
+
else
|
|
2661
|
+
echo -e "${RED}No agent ID provided. Exiting...${NC}"
|
|
2662
|
+
fi
|
|
2663
|
+
;;
|
|
2664
|
+
22)
|
|
2665
|
+
# Custom API Endpoint
|
|
2666
|
+
check_dependencies
|
|
2667
|
+
echo -e "${BLUE}Configuring Custom API Endpoint...${NC}"
|
|
2668
|
+
read -p "Enter API Base URL (e.g. https://api.example.com/v1): " CUSTOM_BASE
|
|
2669
|
+
read -p "Enter API Key: " CUSTOM_KEY
|
|
2670
|
+
read -p "Enter Model Name: " MODEL_NAME
|
|
2671
|
+
|
|
2672
|
+
export ANTHROPIC_BASE_URL="$CUSTOM_BASE"
|
|
2673
|
+
export ANTHROPIC_API_KEY="$CUSTOM_KEY"
|
|
2674
|
+
echo -e "${BLUE}🚀 Starting with custom endpoint...${NC}"
|
|
2675
|
+
exec claude --no-chrome --model "$MODEL_NAME" "$@"
|
|
2676
|
+
;;
|
|
2677
|
+
esac
|
|
2678
|
+
|
|
2679
|
+
# Handle custom models (22+) but exclude model manager
|
|
2680
|
+
if [[ "$choice" =~ ^[0-9]+$ ]] && [[ $choice -ge 22 ]] && [[ -n "$model_manager_num" ]] && [[ $choice -lt $model_manager_num ]]; then
|
|
2681
|
+
custom_index=$((choice - 22))
|
|
2682
|
+
count=0
|
|
2683
|
+
while IFS= read -r model_info; do
|
|
2684
|
+
if [[ -n "$model_info" ]]; then
|
|
2685
|
+
if [[ $count -eq $custom_index ]]; then
|
|
2686
|
+
IFS=':' read -r filename provider_name description <<< "$model_info"
|
|
2687
|
+
echo -e "${BLUE}Using ${provider_name}...${NC}"
|
|
2688
|
+
handle_custom_model "$filename" "$@"
|
|
2689
|
+
exit 0
|
|
2690
|
+
fi
|
|
2691
|
+
((count++))
|
|
2692
|
+
fi
|
|
2693
|
+
done < <(get_custom_models)
|
|
2694
|
+
fi
|
|
2695
|
+
|
|
2696
|
+
# Handle model manager - check dynamic number
|
|
2697
|
+
if [[ "$choice" -eq "$model_manager_num" ]]; then
|
|
2698
|
+
if [[ -f "$SCRIPT_DIR/claude-suite/models/add-model-manual.sh" ]]; then
|
|
2699
|
+
exec "$SCRIPT_DIR/claude-suite/models/add-model-manual.sh"
|
|
2700
|
+
else
|
|
2701
|
+
echo -e "${RED}Error: add-model-manual.sh not found in claude-suite/models/${NC}"
|
|
2702
|
+
exit 1
|
|
2703
|
+
fi
|
|
2704
|
+
fi
|
|
2705
|
+
|
|
2706
|
+
echo "Invalid choice"
|
|
2707
|
+
exit 1
|