create-openclaw-bot 4.0.7 → 4.0.9
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/CHANGELOG.md +21 -6
- package/CHANGELOG.vi.md +21 -6
- package/README.md +13 -9
- package/README.vi.md +13 -11
- package/cli.js +171 -28
- package/index.html +9 -4
- package/package.json +1 -1
- package/setup.js +49 -234
package/CHANGELOG.md
CHANGED
|
@@ -2,13 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
-
## [4.0.
|
|
5
|
+
## [4.0.9] — 2026-04-01
|
|
6
6
|
|
|
7
|
-
###
|
|
8
|
-
- **
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
11
|
-
|
|
7
|
+
### 🔄 Dynamic Smart Route (Real-time Provider Sync)
|
|
8
|
+
- **Zero-Waste Routing**: The `smart-route` combo is no longer a static list of 100+ models. A background sync loop now queries 9Router's `/api/providers` every 30 seconds and dynamically builds the combo from **only connected + enabled providers**. This eliminates `404 No active credentials` errors entirely.
|
|
9
|
+
- **Instant Provider Toggle**: Toggle providers on/off in the 9Router Dashboard — the combo updates automatically within 30s. No restart required.
|
|
10
|
+
- **Smart Mapping**: Full provider-to-model mapping covering 25+ providers (Codex, Claude Code, GitHub Copilot, Cursor, Kilo, Cline, Gemini CLI, iFlow, Qwen, Kiro, Ollama, GLM, MiniMax, DeepSeek, xAI, Mistral, Groq, etc.).
|
|
11
|
+
|
|
12
|
+
### 🐳 Docker Auto-Install
|
|
13
|
+
- **Zero-Prerequisite Setup**: `npx create-openclaw-bot` now detects if Docker is installed. If missing, it offers to install automatically via `winget` (Windows), `brew` (macOS), or the official Docker install script (Linux).
|
|
14
|
+
- **Guided Recovery**: Clear instructions and download links if automatic installation fails.
|
|
15
|
+
|
|
16
|
+
## [4.0.8] — 2026-03-31
|
|
17
|
+
|
|
18
|
+
### ✨ 9Router Stability & Ollama Cloud
|
|
19
|
+
- **Stable 9Router Integration (Zero Config)**: The 9Router proxy is now fully stabilized and runs securely within the Docker network via `sk-no-key`. External configuration (API keys, manual routing) is removed from `.env` and elegantly managed via the [9Router Dashboard](http://localhost:20128/dashboard).
|
|
20
|
+
- **Expanded Model Connectivity**: Added comprehensive support for Ollama Cloud models (*Qwen 3.5, GLM-5, MiniMax, GPT-OSS*), Kiro Haiku, Qwen Flash, and extended iFlow free tiers.
|
|
21
|
+
- **Smart Routing Injection**: The configuration dynamically injects the `smart-route` combination to balance logic workload across Codex, Claude Code, Gemini, and iFlow.
|
|
22
|
+
|
|
23
|
+
### 🧹 Clean Workspace & Cross-Platform Auto-Setup
|
|
24
|
+
- **Zero-Clutter Generation**: Eliminated all redundant `.env.example` and static `docker-compose` sample templates. The `.bat` / CLI wizard now dynamically constructs the precise Docker environment necessary.
|
|
25
|
+
- **Cross-Platform Auto Browser**: Added a native macOS/Linux `start-chrome-debug.sh` boot script alongside the Windows `.bat`, providing instant 1-click Chrome Debug Mode initialization.
|
|
26
|
+
- **CLI Feature Parity**: `npx create-openclaw-bot` now prompts for User Identity and Bot Persona, matching the GUI Web UI capabilities exactly.
|
|
12
27
|
|
|
13
28
|
## [4.0.1] — 2026-03-31
|
|
14
29
|
|
package/CHANGELOG.vi.md
CHANGED
|
@@ -2,13 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
Tất cả những thay đổi nổi bật của dự án sẽ được ghi chép trong file này.
|
|
4
4
|
|
|
5
|
-
## [4.0.
|
|
5
|
+
## [4.0.9] — 2026-04-01
|
|
6
6
|
|
|
7
|
-
###
|
|
8
|
-
- **
|
|
9
|
-
- **
|
|
10
|
-
- **
|
|
11
|
-
|
|
7
|
+
### 🔄 Dynamic Smart Route (Đồng bộ Provider Realtime)
|
|
8
|
+
- **Routing Thông Minh**: Combo `smart-route` không còn là danh sách cứng 100+ model. Script đồng bộ chạy ngầm mỗi 30 giây sẽ tự động quét `/api/providers` của 9Router và chỉ đưa vào combo **những provider đã kết nối VÀ đang bật**. Triệt tiêu hoàn toàn lỗi `404 No active credentials`.
|
|
9
|
+
- **Bật/Tắt Tức Thì**: Bật hoặc tắt provider trên Dashboard 9Router — combo tự cập nhật trong vòng 30 giây, không cần restart container.
|
|
10
|
+
- **Mapping Đầy Đủ**: Hỗ trợ 25+ provider (Codex, Claude Code, GitHub Copilot, Cursor, Kilo, Cline, Gemini CLI, iFlow, Qwen, Kiro, Ollama, GLM, MiniMax, DeepSeek, xAI, Mistral, Groq...).
|
|
11
|
+
|
|
12
|
+
### 🐳 Tự Động Cài Docker
|
|
13
|
+
- **Zero-Prerequisite**: `npx create-openclaw-bot` tự phát hiện Docker chưa cài → tự tải + cài qua `winget` (Windows), `brew` (macOS), hoặc script chính thức Docker (Linux).
|
|
14
|
+
- **Hướng Dẫn Rõ Ràng**: Nếu cài tự động thất bại, hiển thị link tải trực tiếp kèm hướng dẫn chi tiết.
|
|
15
|
+
|
|
16
|
+
## [4.0.8] — 2026-03-31
|
|
17
|
+
|
|
18
|
+
### ✨ Tối ưu 9Router & Mở rộng Ollama Cloud
|
|
19
|
+
- **Tích hợp 9Router cực kỳ Ổn định (Zero Config)**: Proxy 9Router hiện được tự động kích hoạt bảo mật bên trong mạng Docker network qua cổng `sk-no-key`. Toàn bộ thiết đặt API keys thủ công và định tuyến models được gỡ bỏ khỏi `.env` để nhường chỗ cho hệ thống quản lý tập trung và thông minh hơn qua [9Router Dashboard](http://localhost:20128/dashboard).
|
|
20
|
+
- **Mở Rộng Kết Nối Models**: Đưa vào danh sách hỗ trợ trọn bộ hệ sinh thái Ollama Cloud (*Qwen 3.5, GLM-5, MiniMax, GPT-OSS*), Kiro Haiku, Qwen Flash, cùng toàn bộ iFlow models hoàn toàn miễn phí.
|
|
21
|
+
- **Tự động Inject Smart Routing**: Cấu hình tự động gài sẵn combo luân chuyển linh hoạt `smart-route` giúp cân bằng tải công việc qua lại mượt mà giữa Codex, Claude Code, Gemini, và iFlow.
|
|
22
|
+
|
|
23
|
+
### 🧹 Clean Workspace & Auto-Setup Đa Nền Tảng
|
|
24
|
+
- **Zero-Clutter Generation**: Dọn sạch hoàn toàn các template làm mẫu như `.env.example` hay các file cấu hình `docker-compose` tĩnh dư thừa. Script setup sẽ tự khởi tạo linh động các file thực thụ ngay lúc chạy cho một workspace gọn gàng nhất.
|
|
25
|
+
- **Auto Browser Đa Nền Tảng**: Bổ sung `start-chrome-debug.sh` mới đét cho macOS/Linux đồng bộ hoàn hảo với file `.bat` thiết lập chạy Automation trên Windows, mở ra kỷ nguyên Auto-Browser tiện lợi.
|
|
26
|
+
- **Auto Prompt CLI**: `npx create-openclaw-bot` hiện đã hoàn chỉnh về feature-parity với Web UI, hỗ trợ tra vấn thông tin thiết lập User Identity và Persona của Bot trực tiếp ở bảng console.
|
|
12
27
|
|
|
13
28
|
## [4.0.1] — 2026-03-31
|
|
14
29
|
|
package/README.md
CHANGED
|
@@ -3,17 +3,16 @@
|
|
|
3
3
|
# 🦞 OpenClaw Setup
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
6
|
-
<a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v4.0.
|
|
6
|
+
<a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v4.0.9-0EA5E9?style=for-the-badge" alt="Version 4.0.9" /></a>
|
|
7
7
|
<a href="https://github.com/tuanminhhole/openclaw-setup?tab=MIT-1-ov-file"><img src="https://img.shields.io/badge/LICENSE-MIT-success?style=for-the-badge" alt="MIT License" /></a>
|
|
8
8
|
<a href="https://www.npmjs.com/package/create-openclaw-bot"><img src="https://img.shields.io/npm/v/create-openclaw-bot?style=for-the-badge&label=CLI&color=2563EB&logo=npm&logoColor=white" alt="NPM Version" /></a>
|
|
9
|
-
<a href="https://www.npmjs.com/package/create-openclaw-bot"><img src="https://img.shields.io/npm/dm/create-openclaw-bot?style=for-the-badge&color=22c55e" alt="NPM Downloads" /></a>
|
|
10
9
|
<a href="https://github.com/tuanminhhole/openclaw-setup/stargazers"><img src="https://img.shields.io/github/stars/tuanminhhole/openclaw-setup?style=for-the-badge&color=eab308&logo=github&logoColor=white" alt="GitHub Stars" /></a>
|
|
11
10
|
</p>
|
|
12
11
|
|
|
13
12
|
An interactive <strong>CLI tool</strong> and <strong>Setup Wizard</strong> to deploy your own free AI Bot on Telegram or Zalo in minutes.
|
|
14
13
|
|
|
15
14
|
<a href="https://github.com/tuanminhhole/openclaw-setup">
|
|
16
|
-
<img src="docs/preview.png" alt="OpenClaw Setup Hero Image" width="100%" style="border-radius: 8px; margin: 16px 0; border: 1px solid #333;" />
|
|
15
|
+
<img src="https://raw.githubusercontent.com/tuanminhhole/openclaw-setup/main/docs/preview.png" alt="OpenClaw Setup Hero Image" width="100%" style="border-radius: 8px; margin: 16px 0; border: 1px solid #333;" />
|
|
17
16
|
</a>
|
|
18
17
|
|
|
19
18
|
<p style="margin-top: 16px;">
|
|
@@ -25,11 +24,14 @@ An interactive <strong>CLI tool</strong> and <strong>Setup Wizard</strong> to de
|
|
|
25
24
|
|
|
26
25
|
---
|
|
27
26
|
|
|
28
|
-
## 🆕 What's new in v4
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
-
|
|
27
|
+
## 🆕 What's new in OpenClaw v4
|
|
28
|
+
|
|
29
|
+
> **A massive leap in automation, stability, and provider connectivity!**
|
|
30
|
+
|
|
31
|
+
- 🚀 **Zero-Config `npx` Deployment**: Say goodbye to manually extracting `.zip` files and confusing `.env` configurations. We've introduced a fully interactive CLI `npx create-openclaw-bot` and Web Wizard that builds the entire Docker workspace dynamically!
|
|
32
|
+
- 🔀 **Simplified 9Router Smart Routing**: We've optimized the AI routing to default to a single `smart-route` option. OpenClaw now flawlessly load-balances across top-tier models from Anthropic, OpenAI Codex, Gemini, and Qwen, managing fallback automatically without needing you to input individual API keys.
|
|
33
|
+
- 🌐 **Instant Browser Automation**: Deploying Web Search and automated Browser skills is now fully handled during setup. We added built-in support for both Windows (`.bat` files) and macOS/Linux (`.sh` files) to instantly attach your local Chrome instances.
|
|
34
|
+
- 🧹 **Zero-Clutter Repository**: Eliminated dummy `.env.example` templates and static docker-compose files. The setup now generates precisely what you need, minimizing security risks and permission errors on native OS setups.
|
|
33
35
|
|
|
34
36
|
---
|
|
35
37
|
|
|
@@ -98,6 +100,7 @@ The fastest way to install OpenClaw is using the interactive NPM package.
|
|
|
98
100
|
<br>
|
|
99
101
|
|
|
100
102
|
1. **Clone this repo:**
|
|
103
|
+
|
|
101
104
|
```bash
|
|
102
105
|
git clone https://github.com/tuanminhhole/openclaw-setup.git
|
|
103
106
|
cd openclaw-setup
|
|
@@ -116,7 +119,7 @@ The fastest way to install OpenClaw is using the interactive NPM package.
|
|
|
116
119
|
2. Open this repo as workspace
|
|
117
120
|
3. Paste into chat:
|
|
118
121
|
```text
|
|
119
|
-
Read SETUP.md and set up OpenClaw v4.0.
|
|
122
|
+
Read SETUP.md and set up OpenClaw v4.0.9 for me.
|
|
120
123
|
My bot token is X, my 9Router proxy doesn't need a key.
|
|
121
124
|
My project folder: <YOUR_PATH>
|
|
122
125
|
```
|
|
@@ -157,6 +160,7 @@ On your computer inside a Docker container. When your PC is off, the bot is off.
|
|
|
157
160
|
docker compose down # Stop
|
|
158
161
|
docker compose up -d # Start
|
|
159
162
|
```
|
|
163
|
+
|
|
160
164
|
</details>
|
|
161
165
|
|
|
162
166
|
<details>
|
package/README.vi.md
CHANGED
|
@@ -3,17 +3,16 @@
|
|
|
3
3
|
# 🦞 OpenClaw Setup
|
|
4
4
|
|
|
5
5
|
<p align="center">
|
|
6
|
-
<a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v4.0.
|
|
6
|
+
<a href="https://github.com/tuanminhhole/openclaw-setup/releases"><img src="https://img.shields.io/badge/RELEASE-v4.0.9-0EA5E9?style=for-the-badge" alt="Version 4.0.9" /></a>
|
|
7
7
|
<a href="https://github.com/tuanminhhole/openclaw-setup?tab=MIT-1-ov-file"><img src="https://img.shields.io/badge/LICENSE-MIT-success?style=for-the-badge" alt="MIT License" /></a>
|
|
8
8
|
<a href="https://www.npmjs.com/package/create-openclaw-bot"><img src="https://img.shields.io/npm/v/create-openclaw-bot?style=for-the-badge&label=CLI&color=2563EB&logo=npm&logoColor=white" alt="NPM Version" /></a>
|
|
9
|
-
<a href="https://www.npmjs.com/package/create-openclaw-bot"><img src="https://img.shields.io/npm/dm/create-openclaw-bot?style=for-the-badge&color=22c55e" alt="NPM Downloads" /></a>
|
|
10
9
|
<a href="https://github.com/tuanminhhole/openclaw-setup/stargazers"><img src="https://img.shields.io/github/stars/tuanminhhole/openclaw-setup?style=for-the-badge&color=eab308&logo=github&logoColor=white" alt="GitHub Stars" /></a>
|
|
11
10
|
</p>
|
|
12
11
|
|
|
13
12
|
Một công cụ trực quan <strong>Setup Wizard (UI)</strong> & <strong>CLI</strong> để tự tay build Bot AI trên Telegram và Zalo chỉ trong vài phút.
|
|
14
13
|
|
|
15
14
|
<a href="https://github.com/tuanminhhole/openclaw-setup">
|
|
16
|
-
<img src="docs/preview.png" alt="OpenClaw Setup Hero Image" width="100%" style="border-radius: 8px; margin: 16px 0; border: 1px solid #333;" />
|
|
15
|
+
<img src="https://raw.githubusercontent.com/tuanminhhole/openclaw-setup/main/docs/preview.png" alt="OpenClaw Setup Hero Image" width="100%" style="border-radius: 8px; margin: 16px 0; border: 1px solid #333;" />
|
|
17
16
|
</a>
|
|
18
17
|
|
|
19
18
|
<p style="margin-top: 16px;">
|
|
@@ -25,12 +24,14 @@ Một công cụ trực quan <strong>Setup Wizard (UI)</strong> & <strong>CLI</s
|
|
|
25
24
|
|
|
26
25
|
---
|
|
27
26
|
|
|
28
|
-
## 🆕 Có gì mới ở bản
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
-
|
|
33
|
-
|
|
27
|
+
## 🆕 Có gì mới ở bản OpenClaw Setup v4
|
|
28
|
+
|
|
29
|
+
> **Bản cập nhật lớn nhất về Tự động hóa, Ổn định và Định tuyến AI!**
|
|
30
|
+
|
|
31
|
+
- 🚀 **Cài đặt Tự động với `npx`**: Tạm biệt việc tải file `.zip` thủ công hay cấu hình `.env` phức tạp. Giờ đây bạn chỉ cần chạy lệnh CLI `npx create-openclaw-bot` hoặc dùng Web Wizard để hệ thống tự động sinh ra toàn bộ file cần thiết!
|
|
32
|
+
- 🔀 **Đơn giản hóa 9Router Smart Routing**: Hệ thống định tuyến AI giờ đây mặc định trỏ về `smart-route`. Nền tảng tự động luân chuyển và dự phòng (fallback) qua các model flagship (Anthropic, OpenAI Codex, Gemini, Qwen) mà không cần cấu hình thêm API key rườm rà.
|
|
33
|
+
- 🌐 **Browser Automation Đa nền tảng**: Tích hợp sẵn tính năng Web Search và Tự động hóa trình duyệt ngay lúc cài đặt. Không chỉ hỗ trợ Windows (file `.bat`), mà còn bổ sung file `.sh` giúp Mac/Linux chạy mượt mà.
|
|
34
|
+
- 🧹 **Tối ưu triệt để Workspace**: Xoá hoàn toàn các file "rác" như `.env.example` hay docker template dư thừa. Setup Wizard chỉ giữ lại những gì thực sự hoạt động, tối ưu bảo mật và triệt tiêu mọi lỗi khi chạy.
|
|
34
35
|
|
|
35
36
|
## ✨ Tính năng
|
|
36
37
|
|
|
@@ -97,6 +98,7 @@ Dùng NPX là cách cài chuẩn nhất:
|
|
|
97
98
|
<br>
|
|
98
99
|
|
|
99
100
|
1. **Clone repo:**
|
|
101
|
+
|
|
100
102
|
```bash
|
|
101
103
|
git clone https://github.com/tuanminhhole/openclaw-setup.git
|
|
102
104
|
cd openclaw-setup
|
|
@@ -110,14 +112,13 @@ Dùng NPX là cách cài chuẩn nhất:
|
|
|
110
112
|
|
|
111
113
|
</details>
|
|
112
114
|
|
|
113
|
-
|
|
114
115
|
### 3️⃣ Cách C — Dùng AI Agent (Antigravity)
|
|
115
116
|
|
|
116
117
|
1. Mở [Antigravity IDE](https://antigravity.dev/)
|
|
117
118
|
2. Mở repo này làm workspace
|
|
118
119
|
3. Paste vào chat:
|
|
119
120
|
```text
|
|
120
|
-
Read SETUP.md and install OpenClaw 4.0.
|
|
121
|
+
Read SETUP.md and install OpenClaw 4.0.9 for me.
|
|
121
122
|
My bot token is X, my 9Router proxy doesn't need a key.
|
|
122
123
|
My project folder: <THƯ_MỤC_CỦA_BẠN>
|
|
123
124
|
```
|
|
@@ -158,6 +159,7 @@ Trên máy tính của bạn trong Docker container. Khi tắt máy, bot cũng t
|
|
|
158
159
|
docker compose down # Tắt
|
|
159
160
|
docker compose up -d # Bật
|
|
160
161
|
```
|
|
162
|
+
|
|
161
163
|
</details>
|
|
162
164
|
|
|
163
165
|
<details>
|
package/cli.js
CHANGED
|
@@ -4,7 +4,57 @@ import { input, select, checkbox, confirm } from '@inquirer/prompts';
|
|
|
4
4
|
import fs from 'fs-extra';
|
|
5
5
|
import path from 'path';
|
|
6
6
|
import chalk from 'chalk';
|
|
7
|
-
import { spawn } from 'child_process';
|
|
7
|
+
import { spawn, execSync } from 'child_process';
|
|
8
|
+
|
|
9
|
+
// ─── Docker Auto-Detection ───────────────────────────────────────────────────
|
|
10
|
+
function isDockerInstalled() {
|
|
11
|
+
try {
|
|
12
|
+
execSync('docker --version', { stdio: 'ignore' });
|
|
13
|
+
return true;
|
|
14
|
+
} catch { return false; }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async function ensureDocker(isVi) {
|
|
18
|
+
if (isDockerInstalled()) return true;
|
|
19
|
+
|
|
20
|
+
console.log(chalk.yellow(`\n⚠️ ${isVi ? 'Docker chưa được cài đặt trên máy!' : 'Docker is not installed on this machine!'}`));
|
|
21
|
+
|
|
22
|
+
const shouldInstall = await confirm({
|
|
23
|
+
message: isVi ? 'Bạn có muốn tự động cài Docker không?' : 'Do you want to install Docker automatically?',
|
|
24
|
+
default: true
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
if (!shouldInstall) {
|
|
28
|
+
console.log(chalk.cyan(isVi
|
|
29
|
+
? '👉 Tải Docker Desktop tại: https://www.docker.com/products/docker-desktop/'
|
|
30
|
+
: '👉 Download Docker Desktop at: https://www.docker.com/products/docker-desktop/'));
|
|
31
|
+
process.exit(0);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const platform = process.platform;
|
|
35
|
+
try {
|
|
36
|
+
if (platform === 'win32') {
|
|
37
|
+
console.log(chalk.cyan(isVi ? '🐳 Đang tải Docker Desktop cho Windows (qua winget)...' : '🐳 Downloading Docker Desktop for Windows (via winget)...'));
|
|
38
|
+
execSync('winget install -e --id Docker.DockerDesktop --accept-source-agreements --accept-package-agreements', { stdio: 'inherit' });
|
|
39
|
+
} else if (platform === 'darwin') {
|
|
40
|
+
console.log(chalk.cyan(isVi ? '🐳 Đang tải Docker Desktop cho macOS (qua Homebrew)...' : '🐳 Downloading Docker Desktop for macOS (via Homebrew)...'));
|
|
41
|
+
execSync('brew install --cask docker', { stdio: 'inherit' });
|
|
42
|
+
} else {
|
|
43
|
+
console.log(chalk.cyan(isVi ? '🐳 Đang cài Docker cho Linux...' : '🐳 Installing Docker for Linux...'));
|
|
44
|
+
execSync('curl -fsSL https://get.docker.com | sh', { stdio: 'inherit' });
|
|
45
|
+
}
|
|
46
|
+
console.log(chalk.green(isVi ? '✅ Docker đã cài xong! Vui lòng khởi động Docker Desktop rồi chạy lại lệnh này.' : '✅ Docker installed! Please start Docker Desktop and re-run this command.'));
|
|
47
|
+
if (platform === 'win32' || platform === 'darwin') {
|
|
48
|
+
console.log(chalk.yellow(isVi ? '⚠️ Bạn cần mở Docker Desktop và đợi nó khởi động xong trước khi tiếp tục.' : '⚠️ Please open Docker Desktop and wait for it to finish starting.'));
|
|
49
|
+
process.exit(0);
|
|
50
|
+
}
|
|
51
|
+
return true;
|
|
52
|
+
} catch (e) {
|
|
53
|
+
console.log(chalk.red(isVi ? '❌ Không thể tự cài Docker. Vui lòng tải thủ công:' : '❌ Could not install Docker automatically. Please download manually:'));
|
|
54
|
+
console.log(chalk.cyan(' https://www.docker.com/products/docker-desktop/'));
|
|
55
|
+
process.exit(1);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
8
58
|
|
|
9
59
|
const LOGO = `
|
|
10
60
|
████████╗██╗ ██╗ █████╗ ███╗ ██╗███╗ ███╗██╗███╗ ██╗██╗ ██╗██╗ ██╗ ██████╗ ██╗ ███████╗
|
|
@@ -53,6 +103,9 @@ async function main() {
|
|
|
53
103
|
});
|
|
54
104
|
const isVi = lang === 'vi';
|
|
55
105
|
|
|
106
|
+
// 1b. Docker check
|
|
107
|
+
await ensureDocker(isVi);
|
|
108
|
+
|
|
56
109
|
// 2. Channel
|
|
57
110
|
const channelKey = await select({
|
|
58
111
|
message: isVi ? 'Chọn nền tảng bot:' : 'Select bot platform:',
|
|
@@ -109,20 +162,7 @@ async function main() {
|
|
|
109
162
|
// 5b. User Info
|
|
110
163
|
const userInfo = await input({ message: isVi ? '👤 Thông tin về bạn (ngôn ngữ, múi giờ, sở thích...) — bỏ trống OK:' : '👤 About you (language, timezone, interests...) — leave empty OK:', default: '' });
|
|
111
164
|
|
|
112
|
-
// 5c. 9Router
|
|
113
|
-
let routerApiKey = '';
|
|
114
|
-
if (providerKey === '9router') {
|
|
115
|
-
const wantSecurity = await confirm({
|
|
116
|
-
message: isVi ? '🔐 Bảo mật 9Router? (tự tạo API Key, khuyên dùng khi chạy trên VPS)' : '🔐 Secure 9Router? (auto-generates API Key, recommended for VPS)',
|
|
117
|
-
default: false
|
|
118
|
-
});
|
|
119
|
-
if (wantSecurity) {
|
|
120
|
-
const { randomUUID } = await import('crypto');
|
|
121
|
-
routerApiKey = 'oc9r-' + randomUUID().replace(/-/g, '');
|
|
122
|
-
console.log(chalk.magenta(` 🎲 ${isVi ? 'API Key đã tạo:' : 'Generated API Key:'} ${routerApiKey}`));
|
|
123
|
-
console.log(chalk.gray(` ${isVi ? '(Lưu lại nếu cần — key này được cấu hình tự động)' : '(Save if needed — this key is auto-configured)'}`));
|
|
124
|
-
}
|
|
125
|
-
}
|
|
165
|
+
// 5c. 9Router info (API keys are managed via dashboard after Docker starts)
|
|
126
166
|
|
|
127
167
|
// 6. Project Dir
|
|
128
168
|
let defaultDir = process.cwd();
|
|
@@ -147,9 +187,6 @@ async function main() {
|
|
|
147
187
|
} else if (!provider.isProxy) {
|
|
148
188
|
envContent += `${provider.envKey}=${providerKeyVal}\n`;
|
|
149
189
|
}
|
|
150
|
-
if (providerKey === '9router' && routerApiKey) {
|
|
151
|
-
envContent += `\n# 9Router API Key\nROUTER_API_KEY=${routerApiKey}\n`;
|
|
152
|
-
}
|
|
153
190
|
|
|
154
191
|
if (channelKey === 'telegram') {
|
|
155
192
|
envContent += `TELEGRAM_BOT_TOKEN=${botToken}\n`;
|
|
@@ -184,6 +221,87 @@ CMD sh -c "node -e \\"eval(Buffer.from('${b64Patch}','base64').toString())\\" &&
|
|
|
184
221
|
|
|
185
222
|
const agentId = botName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/-$/, '') || 'chat';
|
|
186
223
|
|
|
224
|
+
// ─── Dynamic Smart Route Sync Script ────────────────────────────────────────
|
|
225
|
+
// This script runs inside the 9Router container as a background loop.
|
|
226
|
+
// Every 30s it queries /api/providers, filters for active+enabled providers,
|
|
227
|
+
// and updates the smart-route combo to ONLY include models from those providers.
|
|
228
|
+
const syncComboScript = `
|
|
229
|
+
#!/bin/sh
|
|
230
|
+
# sync-combo: dynamically builds smart-route combo from connected providers
|
|
231
|
+
ROUTER=http://localhost:20128
|
|
232
|
+
INTERVAL=30
|
|
233
|
+
|
|
234
|
+
# Wait for 9router to be ready
|
|
235
|
+
echo "[sync-combo] Waiting for 9Router to start..."
|
|
236
|
+
while ! wget -qO- \$ROUTER/api/version >/dev/null 2>&1; do sleep 2; done
|
|
237
|
+
echo "[sync-combo] 9Router is ready. Starting sync loop (every \${INTERVAL}s)..."
|
|
238
|
+
|
|
239
|
+
while true; do
|
|
240
|
+
PROVIDERS_JSON=\$(wget -qO- \$ROUTER/api/providers 2>/dev/null || echo '{}')
|
|
241
|
+
COMBO_JSON=\$(node -e "
|
|
242
|
+
const PROVIDER_MODELS = {
|
|
243
|
+
codex: ['cx/gpt-5.4','cx/gpt-5.3-codex','cx/gpt-5.3-codex-high','cx/gpt-5.2-codex','cx/gpt-5.2','cx/gpt-5.1-codex-max','cx/gpt-5.1-codex','cx/gpt-5.1','cx/gpt-5-codex','cx/gpt-5-codex-mini'],
|
|
244
|
+
'claude-code': ['cc/claude-opus-4-6','cc/claude-sonnet-4-6','cc/claude-opus-4-5-20251101','cc/claude-sonnet-4-5-20250929','cc/claude-haiku-4-5-20251001'],
|
|
245
|
+
github: ['gh/gpt-5.4','gh/gpt-5.3-codex','gh/gpt-5.2-codex','gh/gpt-5.2','gh/gpt-5.1-codex-max','gh/gpt-5.1-codex','gh/gpt-5.1','gh/gpt-5','gh/gpt-5-mini','gh/gpt-5-codex','gh/gpt-4.1','gh/gpt-4o','gh/claude-opus-4.6','gh/claude-sonnet-4.6','gh/claude-sonnet-4.5','gh/claude-opus-4.5','gh/claude-haiku-4.5','gh/gemini-3-pro-preview','gh/gemini-3-flash-preview','gh/gemini-2.5-pro'],
|
|
246
|
+
cursor: ['cu/default','cu/claude-4.6-opus-max','cu/claude-4.5-opus-high-thinking','cu/claude-4.5-sonnet-thinking','cu/claude-4.5-sonnet','cu/gpt-5.3-codex','cu/gpt-5.2-codex','cu/gemini-3-flash-preview'],
|
|
247
|
+
kilo: ['kc/anthropic/claude-sonnet-4-20250514','kc/anthropic/claude-opus-4-20250514','kc/google/gemini-2.5-pro','kc/google/gemini-2.5-flash','kc/openai/gpt-4.1','kc/openai/o3','kc/deepseek/deepseek-chat'],
|
|
248
|
+
cline: ['cl/anthropic/claude-sonnet-4.6','cl/anthropic/claude-opus-4.6','cl/openai/gpt-5.3-codex','cl/openai/gpt-5.4','cl/google/gemini-3.1-pro-preview'],
|
|
249
|
+
'gemini-cli': ['gc/gemini-3-flash-preview','gc/gemini-3-pro-preview'],
|
|
250
|
+
iflow: ['if/qwen3-coder-plus','if/kimi-k2','if/kimi-k2-thinking','if/glm-4.7','if/deepseek-r1','if/deepseek-v3.2','if/deepseek-v3','if/qwen3-max','if/qwen3-235b','if/iflow-rome-30ba3b'],
|
|
251
|
+
qwen: ['qw/qwen3-coder-plus','qw/qwen3-coder-flash','qw/vision-model','qw/coder-model'],
|
|
252
|
+
kiro: ['kr/claude-sonnet-4.5','kr/claude-haiku-4.5','kr/deepseek-3.2','kr/deepseek-3.1','kr/qwen3-coder-next'],
|
|
253
|
+
ollama: ['ollama/qwen3.5','ollama/kimi-k2.5','ollama/glm-5','ollama/glm-4.7-flash','ollama/minimax-m2.5','ollama/gpt-oss:120b'],
|
|
254
|
+
'kimi-coding': ['kmc/kimi-k2.5','kmc/kimi-k2.5-thinking','kmc/kimi-latest'],
|
|
255
|
+
glm: ['glm/glm-5.1','glm/glm-5','glm/glm-4.7'],
|
|
256
|
+
'glm-cn': ['glm/glm-5.1','glm/glm-5','glm/glm-4.7'],
|
|
257
|
+
minimax: ['minimax/MiniMax-M2.7','minimax/MiniMax-M2.5','minimax/MiniMax-M2.1'],
|
|
258
|
+
kimi: ['kimi/kimi-k2.5','kimi/kimi-k2.5-thinking','kimi/kimi-latest'],
|
|
259
|
+
deepseek: ['deepseek/deepseek-chat','deepseek/deepseek-reasoner'],
|
|
260
|
+
xai: ['xai/grok-4','xai/grok-4-fast-reasoning','xai/grok-code-fast-1'],
|
|
261
|
+
mistral: ['mistral/mistral-large-latest','mistral/codestral-latest'],
|
|
262
|
+
groq: ['groq/llama-3.3-70b-versatile','groq/openai/gpt-oss-120b'],
|
|
263
|
+
cerebras: ['cerebras/gpt-oss-120b'],
|
|
264
|
+
alicode: ['alicode/qwen3.5-plus','alicode/qwen3-coder-plus'],
|
|
265
|
+
openai: ['openai/gpt-4o','openai/gpt-4.1','openai/o3-mini'],
|
|
266
|
+
anthropic: ['anthropic/claude-sonnet-4','anthropic/claude-haiku-3.5'],
|
|
267
|
+
gemini: ['gemini/gemini-2.5-flash','gemini/gemini-2.5-pro'],
|
|
268
|
+
};
|
|
269
|
+
try {
|
|
270
|
+
const data = \$PROVIDERS_JSON;
|
|
271
|
+
const active = (data.connections||[]).filter(c => c.isActive).map(c => c.provider);
|
|
272
|
+
if (active.length === 0) { process.exit(1); }
|
|
273
|
+
const models = active.flatMap(p => PROVIDER_MODELS[p]||[]);
|
|
274
|
+
if (models.length === 0) { process.exit(1); }
|
|
275
|
+
console.log(JSON.stringify({id:'smart-route',name:'smart-route',alias:'smart-route',models:models}));
|
|
276
|
+
} catch(e) { process.exit(1); }
|
|
277
|
+
" 2>/dev/null)
|
|
278
|
+
if [ -n "\$COMBO_JSON" ]; then
|
|
279
|
+
# Read existing db.json, update/add the smart-route combo, write back
|
|
280
|
+
node -e "
|
|
281
|
+
const fs = require('fs');
|
|
282
|
+
const dbPath = '/root/.9router/db.json';
|
|
283
|
+
let db = {};
|
|
284
|
+
try { db = JSON.parse(fs.readFileSync(dbPath,'utf8')); } catch(e) {}
|
|
285
|
+
const newCombo = \$COMBO_JSON;
|
|
286
|
+
if (!db.combos) db.combos = [];
|
|
287
|
+
const idx = db.combos.findIndex(c => c.id === 'smart-route');
|
|
288
|
+
if (idx >= 0) {
|
|
289
|
+
if (JSON.stringify(db.combos[idx].models) !== JSON.stringify(newCombo.models)) {
|
|
290
|
+
db.combos[idx] = newCombo;
|
|
291
|
+
fs.writeFileSync(dbPath, JSON.stringify(db, null, 2));
|
|
292
|
+
console.log('[sync-combo] Updated smart-route: ' + newCombo.models.length + ' models from ' + new Set(newCombo.models.map(m=>m.split('/')[0])).size + ' providers');
|
|
293
|
+
}
|
|
294
|
+
} else {
|
|
295
|
+
db.combos.push(newCombo);
|
|
296
|
+
fs.writeFileSync(dbPath, JSON.stringify(db, null, 2));
|
|
297
|
+
console.log('[sync-combo] Created smart-route: ' + newCombo.models.length + ' models');
|
|
298
|
+
}
|
|
299
|
+
" 2>/dev/null
|
|
300
|
+
fi
|
|
301
|
+
sleep \$INTERVAL
|
|
302
|
+
done
|
|
303
|
+
`.trim().replace(/\n/g, '\\n');
|
|
304
|
+
|
|
187
305
|
let compose = '';
|
|
188
306
|
if (providerKey === '9router') {
|
|
189
307
|
compose = `name: oc-${agentId}
|
|
@@ -203,16 +321,14 @@ ${selectedSkills.includes('browser') ? ` extra_hosts:
|
|
|
203
321
|
|
|
204
322
|
9router:
|
|
205
323
|
image: node:22-slim
|
|
206
|
-
container_name: 9router
|
|
324
|
+
container_name: 9router-${agentId}
|
|
207
325
|
restart: always
|
|
208
326
|
entrypoint: >
|
|
209
|
-
/bin/sh -c "npm install -g 9router &&
|
|
327
|
+
/bin/sh -c "npm install -g 9router && (echo '${syncComboScript}' > /tmp/sync-combo.sh && chmod +x /tmp/sync-combo.sh && /bin/sh /tmp/sync-combo.sh &) && 9router"
|
|
210
328
|
environment:
|
|
211
329
|
- PORT=20128
|
|
212
330
|
- HOSTNAME=0.0.0.0
|
|
213
|
-
- CI=true
|
|
214
|
-
env_file:
|
|
215
|
-
- .env
|
|
331
|
+
- CI=true
|
|
216
332
|
volumes:
|
|
217
333
|
- 9router-data:/root/.9router
|
|
218
334
|
ports:
|
|
@@ -238,9 +354,9 @@ ${selectedSkills.includes('browser') ? ` extra_hosts:
|
|
|
238
354
|
|
|
239
355
|
let authProfilesJson = {};
|
|
240
356
|
if (providerKey && !provider.isLocal) {
|
|
241
|
-
const authProviderName = providerKey === '9router' ? '9router' : 'openai';
|
|
357
|
+
const authProviderName = providerKey === '9router' ? '9router' : 'openai';
|
|
242
358
|
const authProfileId = providerKey === '9router' ? '9router-proxy' : `${authProviderName}:default`;
|
|
243
|
-
const authKeyValue = providerKey === '9router' ?
|
|
359
|
+
const authKeyValue = providerKey === '9router' ? 'sk-no-key' : providerKeyVal;
|
|
244
360
|
|
|
245
361
|
authProfilesJson = {
|
|
246
362
|
version: 1,
|
|
@@ -287,10 +403,11 @@ ${selectedSkills.includes('browser') ? ` extra_hosts:
|
|
|
287
403
|
providers: {
|
|
288
404
|
'9router': {
|
|
289
405
|
baseUrl: 'http://9router:20128/v1',
|
|
290
|
-
apiKey:
|
|
406
|
+
apiKey: 'sk-no-key',
|
|
291
407
|
api: 'openai-completions',
|
|
292
408
|
models: [
|
|
293
409
|
{ id: 'smart-route', name: 'Smart Proxy (Auto Route)', contextWindow: 200000, maxTokens: 8192 },
|
|
410
|
+
// OAuth Providers
|
|
294
411
|
{ id: 'cc/claude-opus-4-6', name: 'Claude Opus 4.6', contextWindow: 200000, maxTokens: 8192 },
|
|
295
412
|
{ id: 'cc/claude-sonnet-4-6', name: 'Claude Sonnet 4.6', contextWindow: 200000, maxTokens: 8192 },
|
|
296
413
|
{ id: 'cx/gpt-5.4', name: 'GPT 5.4 (Codex)', contextWindow: 128000, maxTokens: 8192 },
|
|
@@ -298,14 +415,28 @@ ${selectedSkills.includes('browser') ? ` extra_hosts:
|
|
|
298
415
|
{ id: 'gh/gpt-5.4', name: 'GPT 5.4 (Copilot)', contextWindow: 128000, maxTokens: 8192 },
|
|
299
416
|
{ id: 'gh/claude-opus-4.6', name: 'Claude Opus 4.6 (Copilot)', contextWindow: 200000, maxTokens: 8192 },
|
|
300
417
|
{ id: 'gc/gemini-3-flash-preview', name: 'Gemini 3 Flash (FREE)', contextWindow: 1000000, maxTokens: 8192 },
|
|
301
|
-
|
|
418
|
+
// Free Tier Providers
|
|
419
|
+
{ id: 'if/qwen3-coder-plus', name: 'Qwen3 Coder+ (iFlow FREE)', contextWindow: 128000, maxTokens: 8192 },
|
|
302
420
|
{ id: 'if/kimi-k2', name: 'Kimi K2 (iFlow FREE)', contextWindow: 128000, maxTokens: 8192 },
|
|
421
|
+
{ id: 'if/kimi-k2-thinking', name: 'Kimi K2 Thinking (iFlow FREE)', contextWindow: 128000, maxTokens: 8192 },
|
|
303
422
|
{ id: 'if/glm-4.7', name: 'GLM 4.7 (iFlow FREE)', contextWindow: 128000, maxTokens: 8192 },
|
|
423
|
+
{ id: 'if/minimax-m2', name: 'MiniMax M2 (iFlow FREE)', contextWindow: 1000000, maxTokens: 8192 },
|
|
304
424
|
{ id: 'if/deepseek-r1', name: 'DeepSeek R1 (iFlow FREE)', contextWindow: 128000, maxTokens: 8192 },
|
|
305
|
-
{ id: 'qw/qwen3-coder-plus', name: 'Qwen3 Coder
|
|
425
|
+
{ id: 'qw/qwen3-coder-plus', name: 'Qwen3 Coder+ (Qwen FREE)', contextWindow: 128000, maxTokens: 8192 },
|
|
426
|
+
{ id: 'qw/qwen3-coder-flash', name: 'Qwen3 Coder Flash (Qwen FREE)', contextWindow: 128000, maxTokens: 8192 },
|
|
306
427
|
{ id: 'kr/claude-sonnet-4.5', name: 'Claude Sonnet 4.5 (Kiro FREE)', contextWindow: 200000, maxTokens: 8192 },
|
|
428
|
+
{ id: 'kr/claude-haiku-4.5', name: 'Claude Haiku 4.5 (Kiro FREE)', contextWindow: 200000, maxTokens: 8192 },
|
|
429
|
+
// Ollama Cloud
|
|
430
|
+
{ id: 'ollama/qwen3.5', name: 'Qwen 3.5 (Ollama Cloud)', contextWindow: 128000, maxTokens: 8192 },
|
|
431
|
+
{ id: 'ollama/kimi-k2.5', name: 'Kimi K2.5 (Ollama Cloud)', contextWindow: 128000, maxTokens: 8192 },
|
|
432
|
+
{ id: 'ollama/glm-5', name: 'GLM 5 (Ollama Cloud)', contextWindow: 128000, maxTokens: 8192 },
|
|
433
|
+
{ id: 'ollama/glm-4.7-flash', name: 'GLM 4.7 Flash (Ollama Cloud)', contextWindow: 128000, maxTokens: 8192 },
|
|
434
|
+
{ id: 'ollama/minimax-m2.5', name: 'MiniMax M2.5 (Ollama Cloud)', contextWindow: 128000, maxTokens: 8192 },
|
|
435
|
+
{ id: 'ollama/gpt-oss:120b', name: 'GPT-OSS 120B (Ollama Cloud)', contextWindow: 128000, maxTokens: 8192 },
|
|
436
|
+
// API Key Providers
|
|
307
437
|
{ id: 'glm/glm-4.7', name: 'GLM 4.7 ($0.6/1M)', contextWindow: 128000, maxTokens: 8192 },
|
|
308
438
|
{ id: 'minimax/MiniMax-M2.1', name: 'MiniMax M2.1 ($0.20/1M)', contextWindow: 1000000, maxTokens: 8192 },
|
|
439
|
+
{ id: 'kimi/kimi-latest', name: 'Kimi Latest ($0.90/1M)', contextWindow: 128000, maxTokens: 8192 },
|
|
309
440
|
{ id: 'deepseek/deepseek-chat', name: 'DeepSeek V3.2 Chat', contextWindow: 128000, maxTokens: 8192 },
|
|
310
441
|
]
|
|
311
442
|
}
|
|
@@ -425,6 +556,18 @@ fi
|
|
|
425
556
|
if (code === 0) {
|
|
426
557
|
console.log(chalk.green(`\n🎉 ${isVi ? 'Setup hoàn tất! Bot đang chạy.' : 'Setup complete! Bot is running.'}`));
|
|
427
558
|
|
|
559
|
+
if (providerKey === '9router') {
|
|
560
|
+
console.log(chalk.yellow(`\n🔀 ${isVi
|
|
561
|
+
? '9Router Dashboard: http://localhost:20128/dashboard'
|
|
562
|
+
: '9Router Dashboard: http://localhost:20128/dashboard'}`));
|
|
563
|
+
console.log(chalk.gray(isVi
|
|
564
|
+
? ' → Mở dashboard → đăng nhập OAuth để kết nối các Provider (iFlow, Gemini CLI, Claude Code...)'
|
|
565
|
+
: ' → Open dashboard → OAuth login to connect Providers (iFlow, Gemini CLI, Claude Code...)'));
|
|
566
|
+
console.log(chalk.gray(isVi
|
|
567
|
+
? ' → Sau khi kết nối provider, bot sẽ tự động hoạt động qua combo "smart-route"'
|
|
568
|
+
: ' → After connecting providers, bot works automatically via "smart-route" combo'));
|
|
569
|
+
}
|
|
570
|
+
|
|
428
571
|
if (channelKey === 'telegram') {
|
|
429
572
|
console.log(chalk.cyan(`\n💬 ${isVi
|
|
430
573
|
? 'Nhắn tin cho bot trên Telegram là dùng được ngay!'
|
package/index.html
CHANGED
|
@@ -119,7 +119,7 @@
|
|
|
119
119
|
<!-- ─── 3. Bot Identity (Name, Role, Emoji, Vibe) ─── -->
|
|
120
120
|
<div class="identity-grid">
|
|
121
121
|
<div class="form-group">
|
|
122
|
-
<label class="form-group__label" for="cfg-name" data-vi="Tên Bot" data-en="Bot Name">Tên Bot
|
|
122
|
+
<label class="form-group__label" for="cfg-name" data-vi="Tên Bot" data-en="Bot Name">Tên Bot <span style="color: var(--danger, #ef4444);">*</span></label>
|
|
123
123
|
<input type="text" class="form-input" id="cfg-name" placeholder="VD: Williams, Jarvis, Luna..." oninput="window.__validateKeys()">
|
|
124
124
|
</div>
|
|
125
125
|
<div class="form-group">
|
|
@@ -145,7 +145,7 @@
|
|
|
145
145
|
|
|
146
146
|
<!-- ─── 4b. User Info (→ USER.md) ─── -->
|
|
147
147
|
<div class="form-group">
|
|
148
|
-
<label class="form-group__label" for="cfg-user-info" data-vi="👤 Thông tin về bạn (để bot hiểu bạn hơn)" data-en="👤 About You (so the bot replies better)">👤 Thông tin về bạn (để bot hiểu bạn hơn)
|
|
148
|
+
<label class="form-group__label" for="cfg-user-info" data-vi="👤 Thông tin về bạn (để bot hiểu bạn hơn)" data-en="👤 About You (so the bot replies better)">👤 Thông tin về bạn (để bot hiểu bạn hơn) <span style="color: var(--danger, #ef4444);">*</span></label>
|
|
149
149
|
<textarea class="form-textarea" id="cfg-user-info" placeholder="VD: Mình là dev, thích code Python, múi giờ UTC+7. Thích câu trả lời đi thẳng vào vấn đề, không rào trước đón sau..." style="min-height: 100px;"></textarea>
|
|
150
150
|
<div class="prompt-notice">
|
|
151
151
|
<span class="prompt-notice__icon">👤</span>
|
|
@@ -201,7 +201,8 @@
|
|
|
201
201
|
<!-- ===== Step 3: API Keys & Thư Mục ===== -->
|
|
202
202
|
<section class="step" data-step="3">
|
|
203
203
|
<h2 class="step__title" data-vi="Nhập API Keys & Thư mục" data-en="Enter API Keys & Folder">Nhập API Keys & Thư mục</h2>
|
|
204
|
-
<p class="step__description" data-vi="Nhập key trực tiếp + chọn nơi lưu project — wizard lo phần còn lại." data-en="Enter keys + choose project folder — the wizard handles the rest.">Nhập key trực tiếp + chọn nơi lưu project — wizard lo phần còn lại.</p>
|
|
204
|
+
<p class="step__description" style="margin-bottom: 4px;" data-vi="Nhập key trực tiếp + chọn nơi lưu project — wizard lo phần còn lại." data-en="Enter keys + choose project folder — the wizard handles the rest.">Nhập key trực tiếp + chọn nơi lưu project — wizard lo phần còn lại.</p>
|
|
205
|
+
<p style="font-size: 13px; color: var(--danger, #ef4444); margin-top: 0; margin-bottom: 20px;" data-vi="Các trường có dấu <span style='color:var(--danger,#ef4444)'>*</span> là bắt buộc điền." data-en="Fields marked with <span style='color:var(--danger,#ef4444)'>*</span> are required.">Các trường có dấu <span style="color:var(--danger,#ef4444)">*</span> là bắt buộc điền.</p>
|
|
205
206
|
|
|
206
207
|
<!-- Section 1: AI Provider (9Router / Direct API / Ollama) -->
|
|
207
208
|
<div id="key-section-provider" style="margin-bottom: 20px;"></div>
|
|
@@ -214,7 +215,7 @@
|
|
|
214
215
|
|
|
215
216
|
<!-- Project Path Input -->
|
|
216
217
|
<div class="form-group" style="margin-top: 24px; padding-top: 20px; border-top: 1px solid rgba(255,255,255,0.06);">
|
|
217
|
-
<label class="form-group__label" data-vi="Thư mục lưu trữ Bot (Trên máy chứa Docker)" data-en="Bot Directory (On Docker host)">Thư mục lưu trữ Bot (Trên máy chứa Docker)
|
|
218
|
+
<label class="form-group__label" data-vi="Thư mục lưu trữ Bot (Trên máy chứa Docker) <span style='color:var(--danger,#ef4444)'>*</span>" data-en="Bot Directory (On Docker host) <span style='color:var(--danger,#ef4444)'>*</span>">Thư mục lưu trữ Bot (Trên máy chứa Docker) <span style='color:var(--danger,#ef4444)'>*</span></label>
|
|
218
219
|
<input type="text" class="form-input" id="cfg-project-path" value="D:\openclaw-setup" placeholder="VD: D:\openclaw-setup hoặc /home/user/openclaw-setup" style="font-family: monospace;">
|
|
219
220
|
<p class="form-group__hint" data-vi="Script sẽ tự động tạo thư mục này và sinh các file config bên trong." data-en="The script will auto-create this folder and generate config files inside.">Script sẽ tự động tạo thư mục này và sinh các file config bên trong.</p>
|
|
220
221
|
</div>
|
|
@@ -246,6 +247,10 @@
|
|
|
246
247
|
<span data-vi="📥 Download setup-openclaw.bat" data-en="📥 Download setup-openclaw.bat">📥 Download setup-openclaw.bat</span>
|
|
247
248
|
</button>
|
|
248
249
|
</div>
|
|
250
|
+
<div style="font-size: 12.5px; color: var(--warning, #ffc107); margin: 10px 0 8px; text-align: center; padding: 6px; background: rgba(255, 193, 7, 0.08); border-radius: 6px; border: 1px solid rgba(255, 193, 7, 0.2);">
|
|
251
|
+
⚠️ <strong data-vi="Lưu ý quan trọng:" data-en="Important notice:">Lưu ý quan trọng:</strong>
|
|
252
|
+
<span data-vi="Click chuột phải vào file .bat → Properties (Thuộc tính) → tick Unblock (Mở khóa) trước khi chạy!" data-en="Right-click the .bat file → Properties → check Unblock before running!">Click chuột phải vào file .bat → Properties (Thuộc tính) → tick Unblock (Mở khóa) trước khi chạy!</span>
|
|
253
|
+
</div>
|
|
249
254
|
<p style="font-size: 12px; color: var(--text-muted); margin: 0; text-align: center;" data-vi="Yêu cầu: Docker Desktop đã cài và đang chạy" data-en="Requires: Docker Desktop installed and running">Yêu cầu: Docker Desktop đã cài và đang chạy</p>
|
|
250
255
|
</div>
|
|
251
256
|
|
package/package.json
CHANGED
package/setup.js
CHANGED
|
@@ -129,172 +129,7 @@
|
|
|
129
129
|
free: true,
|
|
130
130
|
isProxy: true,
|
|
131
131
|
models: [
|
|
132
|
-
|
|
133
|
-
{ id: '9router/smart-route', name: 'Smart Proxy (Auto Route)', descVi: 'Tự động luân chuyển FREE models — không tốn xu', descEn: 'Auto-routing across FREE providers — zero cost', badgeVi: '🌟 Khuyên dùng', badgeEn: '🌟 Recommended' },
|
|
134
|
-
|
|
135
|
-
// ── OAuth: Claude Code (cc/) ──
|
|
136
|
-
{ id: '9router/cc/claude-opus-4-6', name: 'Claude Opus 4.6', descVi: 'Mạnh nhất Anthropic', descEn: 'Strongest Anthropic', badge: '✨ Claude Code' },
|
|
137
|
-
{ id: '9router/cc/claude-sonnet-4-6', name: 'Claude Sonnet 4.6', descVi: 'Nhanh, thông minh', descEn: 'Fast & smart', badge: '✨ Claude Code' },
|
|
138
|
-
{ id: '9router/cc/claude-opus-4-5-20251101', name: 'Claude 4.5 Opus', descVi: 'Phiên bản 4.5 ổn định', descEn: 'Stable 4.5 version', badge: '✨ Claude Code' },
|
|
139
|
-
{ id: '9router/cc/claude-sonnet-4-5-20250929', name: 'Claude 4.5 Sonnet', descVi: 'Cân bằng tốc độ-chất lượng', descEn: 'Speed-quality balance', badge: '✨ Claude Code' },
|
|
140
|
-
{ id: '9router/cc/claude-haiku-4-5-20251001', name: 'Claude 4.5 Haiku', descVi: 'Siêu nhanh, nhẹ', descEn: 'Ultra fast & light', badge: '✨ Claude Code' },
|
|
141
|
-
|
|
142
|
-
// ── OAuth: OpenAI Codex (cx/) ──
|
|
143
|
-
{ id: '9router/cx/gpt-5.4', name: 'GPT 5.4', descVi: 'Flagship mới nhất OpenAI', descEn: 'Latest OpenAI flagship', badge: '🤖 Codex' },
|
|
144
|
-
{ id: '9router/cx/gpt-5.3-codex', name: 'GPT 5.3 Codex', descVi: 'Tối ưu code generation', descEn: 'Code generation optimized', badge: '🤖 Codex' },
|
|
145
|
-
{ id: '9router/cx/gpt-5.3-codex-xhigh', name: 'GPT 5.3 Codex (xHigh)', descVi: 'Suy luận tối đa', descEn: 'Maximum reasoning', badge: '🤖 Codex' },
|
|
146
|
-
{ id: '9router/cx/gpt-5.3-codex-high', name: 'GPT 5.3 Codex (High)', descVi: 'Suy luận cao', descEn: 'High reasoning', badge: '🤖 Codex' },
|
|
147
|
-
{ id: '9router/cx/gpt-5.3-codex-low', name: 'GPT 5.3 Codex (Low)', descVi: 'Nhanh, tiết kiệm', descEn: 'Fast & economical', badge: '🤖 Codex' },
|
|
148
|
-
{ id: '9router/cx/gpt-5.3-codex-none', name: 'GPT 5.3 Codex (None)', descVi: 'Không thinking, nhanh nhất', descEn: 'No thinking, fastest', badge: '🤖 Codex' },
|
|
149
|
-
{ id: '9router/cx/gpt-5.3-codex-spark', name: 'GPT 5.3 Codex Spark', descVi: 'Phiên bản Spark', descEn: 'Spark edition', badge: '🤖 Codex' },
|
|
150
|
-
{ id: '9router/cx/gpt-5.1-codex-mini', name: 'GPT 5.1 Codex Mini', descVi: 'Mini, siêu nhanh', descEn: 'Mini, ultra fast', badge: '🤖 Codex' },
|
|
151
|
-
{ id: '9router/cx/gpt-5.1-codex-mini-high', name: 'GPT 5.1 Codex Mini (High)', descVi: 'Mini + suy luận cao', descEn: 'Mini + high reasoning', badge: '🤖 Codex' },
|
|
152
|
-
{ id: '9router/cx/gpt-5.2-codex', name: 'GPT 5.2 Codex', descVi: 'Ổn định, code tốt', descEn: 'Stable, great coding', badge: '🤖 Codex' },
|
|
153
|
-
{ id: '9router/cx/gpt-5.2', name: 'GPT 5.2', descVi: 'Đa năng', descEn: 'Versatile', badge: '🤖 Codex' },
|
|
154
|
-
{ id: '9router/cx/gpt-5.1-codex-max', name: 'GPT 5.1 Codex Max', descVi: 'Sức mạnh tối đa 5.1', descEn: 'Max power 5.1', badge: '🤖 Codex' },
|
|
155
|
-
{ id: '9router/cx/gpt-5.1-codex', name: 'GPT 5.1 Codex', descVi: 'Codex 5.1', descEn: 'Codex 5.1', badge: '🤖 Codex' },
|
|
156
|
-
{ id: '9router/cx/gpt-5.1', name: 'GPT 5.1', descVi: 'GPT 5.1 base', descEn: 'GPT 5.1 base', badge: '🤖 Codex' },
|
|
157
|
-
{ id: '9router/cx/gpt-5-codex', name: 'GPT 5 Codex', descVi: 'GPT 5 Codex', descEn: 'GPT 5 Codex', badge: '🤖 Codex' },
|
|
158
|
-
{ id: '9router/cx/gpt-5-codex-mini', name: 'GPT 5 Codex Mini', descVi: 'GPT 5 Mini', descEn: 'GPT 5 Mini', badge: '🤖 Codex' },
|
|
159
|
-
|
|
160
|
-
// ── OAuth: Gemini CLI (gc/) — FREE 180K/month ──
|
|
161
|
-
{ id: '9router/gc/gemini-3-flash-preview', name: 'Gemini 3 Flash Preview', descVi: 'Google miễn phí 180K/tháng', descEn: 'Google free 180K/month', badge: '🆓 Gemini CLI' },
|
|
162
|
-
{ id: '9router/gc/gemini-3-pro-preview', name: 'Gemini 3 Pro Preview', descVi: 'Gemini Pro miễn phí', descEn: 'Gemini Pro free', badge: '🆓 Gemini CLI' },
|
|
163
|
-
|
|
164
|
-
// ── OAuth: GitHub Copilot (gh/) ──
|
|
165
|
-
{ id: '9router/gh/gpt-5.4', name: 'GPT 5.4 (Copilot)', descVi: 'Flagship qua Copilot', descEn: 'Flagship via Copilot', badge: '💻 Copilot' },
|
|
166
|
-
{ id: '9router/gh/gpt-5.3-codex', name: 'GPT 5.3 Codex (Copilot)', descVi: 'Codex qua Copilot', descEn: 'Codex via Copilot', badge: '💻 Copilot' },
|
|
167
|
-
{ id: '9router/gh/gpt-5.2-codex', name: 'GPT 5.2 Codex (Copilot)', descVi: 'GPT 5.2 Codex', descEn: 'GPT 5.2 Codex', badge: '💻 Copilot' },
|
|
168
|
-
{ id: '9router/gh/gpt-5.2', name: 'GPT 5.2 (Copilot)', descVi: 'GPT 5.2', descEn: 'GPT 5.2', badge: '💻 Copilot' },
|
|
169
|
-
{ id: '9router/gh/gpt-5.1-codex-max', name: 'GPT 5.1 Codex Max (Copilot)', descVi: 'Max thinking', descEn: 'Max thinking', badge: '💻 Copilot' },
|
|
170
|
-
{ id: '9router/gh/gpt-5.1-codex', name: 'GPT 5.1 Codex (Copilot)', descVi: 'Codex 5.1', descEn: 'Codex 5.1', badge: '💻 Copilot' },
|
|
171
|
-
{ id: '9router/gh/gpt-5.1-codex-mini', name: 'GPT 5.1 Codex Mini (Copilot)', descVi: 'Mini 5.1', descEn: 'Mini 5.1', badge: '💻 Copilot' },
|
|
172
|
-
{ id: '9router/gh/gpt-5.1', name: 'GPT 5.1 (Copilot)', descVi: 'GPT 5.1', descEn: 'GPT 5.1', badge: '💻 Copilot' },
|
|
173
|
-
{ id: '9router/gh/gpt-5', name: 'GPT 5 (Copilot)', descVi: 'GPT 5', descEn: 'GPT 5', badge: '💻 Copilot' },
|
|
174
|
-
{ id: '9router/gh/gpt-5-mini', name: 'GPT 5 Mini (Copilot)', descVi: 'GPT 5 Mini', descEn: 'GPT 5 Mini', badge: '💻 Copilot' },
|
|
175
|
-
{ id: '9router/gh/gpt-5-codex', name: 'GPT 5 Codex (Copilot)', descVi: 'GPT 5 Codex', descEn: 'GPT 5 Codex', badge: '💻 Copilot' },
|
|
176
|
-
{ id: '9router/gh/gpt-4.1', name: 'GPT 4.1 (Copilot)', descVi: 'GPT 4.1', descEn: 'GPT 4.1', badge: '💻 Copilot' },
|
|
177
|
-
{ id: '9router/gh/gpt-4o', name: 'GPT 4o (Copilot)', descVi: 'GPT 4o', descEn: 'GPT 4o', badge: '💻 Copilot' },
|
|
178
|
-
{ id: '9router/gh/gpt-4o-mini', name: 'GPT 4o Mini (Copilot)', descVi: 'GPT 4o Mini', descEn: 'GPT 4o Mini', badge: '💻 Copilot' },
|
|
179
|
-
{ id: '9router/gh/gpt-4', name: 'GPT 4 (Copilot)', descVi: 'GPT 4', descEn: 'GPT 4', badge: '💻 Copilot' },
|
|
180
|
-
{ id: '9router/gh/gpt-3.5-turbo', name: 'GPT 3.5 Turbo (Copilot)', descVi: 'GPT 3.5 Turbo', descEn: 'GPT 3.5 Turbo', badge: '💻 Copilot' },
|
|
181
|
-
{ id: '9router/gh/claude-opus-4.6', name: 'Claude Opus 4.6 (Copilot)', descVi: 'Claude Opus qua Copilot', descEn: 'Claude Opus via Copilot', badge: '💻 Copilot' },
|
|
182
|
-
{ id: '9router/gh/claude-sonnet-4.6', name: 'Claude Sonnet 4.6 (Copilot)', descVi: 'Claude Sonnet qua Copilot', descEn: 'Claude Sonnet via Copilot', badge: '💻 Copilot' },
|
|
183
|
-
{ id: '9router/gh/claude-sonnet-4.5', name: 'Claude Sonnet 4.5 (Copilot)', descVi: 'Claude 4.5 Sonnet', descEn: 'Claude 4.5 Sonnet', badge: '💻 Copilot' },
|
|
184
|
-
{ id: '9router/gh/claude-opus-4.5', name: 'Claude Opus 4.5 (Copilot)', descVi: 'Claude 4.5 Opus', descEn: 'Claude 4.5 Opus', badge: '💻 Copilot' },
|
|
185
|
-
{ id: '9router/gh/claude-opus-4.1', name: 'Claude Opus 4.1 (Copilot)', descVi: 'Claude 4.1 Opus', descEn: 'Claude 4.1 Opus', badge: '💻 Copilot' },
|
|
186
|
-
{ id: '9router/gh/claude-sonnet-4', name: 'Claude Sonnet 4 (Copilot)', descVi: 'Claude 4 Sonnet', descEn: 'Claude 4 Sonnet', badge: '💻 Copilot' },
|
|
187
|
-
{ id: '9router/gh/claude-haiku-4.5', name: 'Claude Haiku 4.5 (Copilot)', descVi: 'Claude 4.5 Haiku', descEn: 'Claude 4.5 Haiku', badge: '💻 Copilot' },
|
|
188
|
-
{ id: '9router/gh/gemini-3-pro-preview', name: 'Gemini 3 Pro (Copilot)', descVi: 'Gemini Pro qua Copilot', descEn: 'Gemini Pro via Copilot', badge: '💻 Copilot' },
|
|
189
|
-
{ id: '9router/gh/gemini-3-flash-preview', name: 'Gemini 3 Flash (Copilot)', descVi: 'Gemini Flash qua Copilot', descEn: 'Gemini Flash via Copilot', badge: '💻 Copilot' },
|
|
190
|
-
{ id: '9router/gh/gemini-2.5-pro', name: 'Gemini 2.5 Pro (Copilot)', descVi: 'Gemini 2.5 Pro', descEn: 'Gemini 2.5 Pro', badge: '💻 Copilot' },
|
|
191
|
-
{ id: '9router/gh/grok-code-fast-1', name: 'Grok Code Fast (Copilot)', descVi: 'xAI Grok qua Copilot', descEn: 'xAI Grok via Copilot', badge: '💻 Copilot' },
|
|
192
|
-
{ id: '9router/gh/oswe-vscode-prime', name: 'Raptor Mini (Copilot)', descVi: 'Raptor Mini', descEn: 'Raptor Mini', badge: '💻 Copilot' },
|
|
193
|
-
|
|
194
|
-
// ── OAuth: Cursor IDE (cu/) ──
|
|
195
|
-
{ id: '9router/cu/default', name: 'Cursor Auto', descVi: 'Server tự chọn model', descEn: 'Server picks model', badge: '🎯 Cursor' },
|
|
196
|
-
{ id: '9router/cu/claude-4.6-opus-max', name: 'Claude 4.6 Opus Max (Cursor)', descVi: 'Opus Max, mạnh nhất', descEn: 'Opus Max, strongest', badge: '🎯 Cursor' },
|
|
197
|
-
{ id: '9router/cu/claude-4.6-sonnet-medium-thinking', name: 'Claude 4.6 Sonnet Thinking (Cursor)', descVi: 'Sonnet + thinking', descEn: 'Sonnet + thinking', badge: '🎯 Cursor' },
|
|
198
|
-
{ id: '9router/cu/claude-4.5-opus-high-thinking', name: 'Claude 4.5 Opus High Thinking (Cursor)', descVi: 'Opus 4.5 + thinking', descEn: 'Opus 4.5 + thinking', badge: '🎯 Cursor' },
|
|
199
|
-
{ id: '9router/cu/claude-4.5-opus-high', name: 'Claude 4.5 Opus High (Cursor)', descVi: 'Opus 4.5 High', descEn: 'Opus 4.5 High', badge: '🎯 Cursor' },
|
|
200
|
-
{ id: '9router/cu/claude-4.5-sonnet-thinking', name: 'Claude 4.5 Sonnet Thinking (Cursor)', descVi: 'Sonnet 4.5 + thinking', descEn: 'Sonnet 4.5 + thinking', badge: '🎯 Cursor' },
|
|
201
|
-
{ id: '9router/cu/claude-4.5-sonnet', name: 'Claude 4.5 Sonnet (Cursor)', descVi: 'Sonnet 4.5', descEn: 'Sonnet 4.5', badge: '🎯 Cursor' },
|
|
202
|
-
{ id: '9router/cu/claude-4.5-haiku', name: 'Claude 4.5 Haiku (Cursor)', descVi: 'Haiku 4.5', descEn: 'Haiku 4.5', badge: '🎯 Cursor' },
|
|
203
|
-
{ id: '9router/cu/claude-4.5-opus', name: 'Claude 4.5 Opus (Cursor)', descVi: 'Opus 4.5', descEn: 'Opus 4.5', badge: '🎯 Cursor' },
|
|
204
|
-
{ id: '9router/cu/gpt-5.3-codex', name: 'GPT 5.3 Codex (Cursor)', descVi: 'GPT 5.3 Codex', descEn: 'GPT 5.3 Codex', badge: '🎯 Cursor' },
|
|
205
|
-
{ id: '9router/cu/gpt-5.2-codex', name: 'GPT 5.2 Codex (Cursor)', descVi: 'GPT 5.2 Codex', descEn: 'GPT 5.2 Codex', badge: '🎯 Cursor' },
|
|
206
|
-
{ id: '9router/cu/gpt-5.2', name: 'GPT 5.2 (Cursor)', descVi: 'GPT 5.2', descEn: 'GPT 5.2', badge: '🎯 Cursor' },
|
|
207
|
-
{ id: '9router/cu/kimi-k2.5', name: 'Kimi K2.5 (Cursor)', descVi: 'Kimi K2.5', descEn: 'Kimi K2.5', badge: '🎯 Cursor' },
|
|
208
|
-
{ id: '9router/cu/gemini-3-flash-preview', name: 'Gemini 3 Flash (Cursor)', descVi: 'Gemini Flash', descEn: 'Gemini Flash', badge: '🎯 Cursor' },
|
|
209
|
-
|
|
210
|
-
// ── OAuth: KiloCode (kc/) ──
|
|
211
|
-
{ id: '9router/kc/anthropic/claude-sonnet-4-20250514', name: 'Claude Sonnet 4 (KiloCode)', descVi: 'Claude Sonnet 4', descEn: 'Claude Sonnet 4', badge: '🔷 KiloCode' },
|
|
212
|
-
{ id: '9router/kc/anthropic/claude-opus-4-20250514', name: 'Claude Opus 4 (KiloCode)', descVi: 'Claude Opus 4', descEn: 'Claude Opus 4', badge: '🔷 KiloCode' },
|
|
213
|
-
{ id: '9router/kc/google/gemini-2.5-pro', name: 'Gemini 2.5 Pro (KiloCode)', descVi: 'Gemini 2.5 Pro', descEn: 'Gemini 2.5 Pro', badge: '🔷 KiloCode' },
|
|
214
|
-
{ id: '9router/kc/google/gemini-2.5-flash', name: 'Gemini 2.5 Flash (KiloCode)', descVi: 'Gemini 2.5 Flash', descEn: 'Gemini 2.5 Flash', badge: '🔷 KiloCode' },
|
|
215
|
-
{ id: '9router/kc/openai/gpt-4.1', name: 'GPT 4.1 (KiloCode)', descVi: 'GPT 4.1', descEn: 'GPT 4.1', badge: '🔷 KiloCode' },
|
|
216
|
-
{ id: '9router/kc/openai/o3', name: 'O3 (KiloCode)', descVi: 'O3 Reasoning', descEn: 'O3 Reasoning', badge: '🔷 KiloCode' },
|
|
217
|
-
{ id: '9router/kc/deepseek/deepseek-chat', name: 'DeepSeek Chat (KiloCode)', descVi: 'DeepSeek V3.2', descEn: 'DeepSeek V3.2', badge: '🔷 KiloCode' },
|
|
218
|
-
{ id: '9router/kc/deepseek/deepseek-reasoner', name: 'DeepSeek Reasoner (KiloCode)', descVi: 'DeepSeek Reasoner', descEn: 'DeepSeek Reasoner', badge: '🔷 KiloCode' },
|
|
219
|
-
|
|
220
|
-
// ── OAuth: Cline (cl/) ──
|
|
221
|
-
{ id: '9router/cl/anthropic/claude-sonnet-4.6', name: 'Claude Sonnet 4.6 (Cline)', descVi: 'Sonnet 4.6 qua Cline', descEn: 'Sonnet 4.6 via Cline', badge: '🔶 Cline' },
|
|
222
|
-
{ id: '9router/cl/anthropic/claude-opus-4.6', name: 'Claude Opus 4.6 (Cline)', descVi: 'Opus 4.6 qua Cline', descEn: 'Opus 4.6 via Cline', badge: '🔶 Cline' },
|
|
223
|
-
{ id: '9router/cl/openai/gpt-5.3-codex', name: 'GPT 5.3 Codex (Cline)', descVi: 'GPT 5.3 qua Cline', descEn: 'GPT 5.3 via Cline', badge: '🔶 Cline' },
|
|
224
|
-
{ id: '9router/cl/openai/gpt-5.4', name: 'GPT 5.4 (Cline)', descVi: 'GPT 5.4 qua Cline', descEn: 'GPT 5.4 via Cline', badge: '🔶 Cline' },
|
|
225
|
-
{ id: '9router/cl/google/gemini-3.1-pro-preview', name: 'Gemini 3.1 Pro (Cline)', descVi: 'Gemini 3.1 Pro', descEn: 'Gemini 3.1 Pro', badge: '🔶 Cline' },
|
|
226
|
-
{ id: '9router/cl/google/gemini-3.1-flash-lite-preview', name: 'Gemini 3.1 Flash Lite (Cline)', descVi: 'Gemini 3.1 Flash Lite', descEn: 'Gemini 3.1 Flash Lite', badge: '🔶 Cline' },
|
|
227
|
-
{ id: '9router/cl/kwaipilot/kat-coder-pro', name: 'KAT Coder Pro (Cline)', descVi: 'KAT Coder Pro', descEn: 'KAT Coder Pro', badge: '🔶 Cline' },
|
|
228
|
-
|
|
229
|
-
// ── OAuth FREE: iFlow (if/) — Unlimited ──
|
|
230
|
-
{ id: '9router/if/qwen3-coder-plus', name: 'Qwen3 Coder Plus (iFlow)', descVi: 'Miễn phí không giới hạn', descEn: 'Free unlimited', badge: '🆓 iFlow' },
|
|
231
|
-
{ id: '9router/if/kimi-k2', name: 'Kimi K2 (iFlow)', descVi: 'Kimi K2 miễn phí', descEn: 'Kimi K2 free', badge: '🆓 iFlow' },
|
|
232
|
-
{ id: '9router/if/glm-4.7', name: 'GLM 4.7 (iFlow)', descVi: 'GLM miễn phí', descEn: 'GLM free', badge: '🆓 iFlow' },
|
|
233
|
-
{ id: '9router/if/deepseek-r1', name: 'DeepSeek R1 (iFlow)', descVi: 'DeepSeek R1 miễn phí', descEn: 'DeepSeek R1 free', badge: '🆓 iFlow' },
|
|
234
|
-
{ id: '9router/if/deepseek-v3.2', name: 'DeepSeek V3.2 (iFlow)', descVi: 'V3.2 miễn phí', descEn: 'V3.2 free', badge: '🆓 iFlow' },
|
|
235
|
-
{ id: '9router/if/deepseek-v3.1', name: 'DeepSeek V3.1 (iFlow)', descVi: 'V3.1 miễn phí', descEn: 'V3.1 free', badge: '🆓 iFlow' },
|
|
236
|
-
{ id: '9router/if/deepseek-v3', name: 'DeepSeek V3 (iFlow)', descVi: 'V3 miễn phí', descEn: 'V3 free', badge: '🆓 iFlow' },
|
|
237
|
-
{ id: '9router/if/qwen3-max', name: 'Qwen3 Max (iFlow)', descVi: 'Qwen3 Max free', descEn: 'Qwen3 Max free', badge: '🆓 iFlow' },
|
|
238
|
-
{ id: '9router/if/qwen3-235b', name: 'Qwen3 235B (iFlow)', descVi: '235B params free', descEn: '235B params free', badge: '🆓 iFlow' },
|
|
239
|
-
{ id: '9router/if/qwen3-32b', name: 'Qwen3 32B (iFlow)', descVi: 'Qwen3 32B free', descEn: 'Qwen3 32B free', badge: '🆓 iFlow' },
|
|
240
|
-
{ id: '9router/if/iflow-rome-30ba3b', name: 'iFlow ROME (iFlow)', descVi: 'Agentic model', descEn: 'Agentic model', badge: '🆓 iFlow' },
|
|
241
|
-
|
|
242
|
-
// ── OAuth FREE: Qwen Code (qw/) — Unlimited ──
|
|
243
|
-
{ id: '9router/qw/qwen3-coder-plus', name: 'Qwen3 Coder Plus', descVi: 'Alibaba miễn phí', descEn: 'Alibaba free', badge: '🆓 Qwen' },
|
|
244
|
-
{ id: '9router/qw/qwen3-coder-flash', name: 'Qwen3 Coder Flash', descVi: 'Nhanh, miễn phí', descEn: 'Fast, free', badge: '🆓 Qwen' },
|
|
245
|
-
{ id: '9router/qw/vision-model', name: 'Qwen3 Vision', descVi: 'Vision model', descEn: 'Vision model', badge: '🆓 Qwen' },
|
|
246
|
-
{ id: '9router/qw/coder-model', name: 'Qwen3.5 Coder', descVi: 'Qwen3.5 Coder', descEn: 'Qwen3.5 Coder', badge: '🆓 Qwen' },
|
|
247
|
-
|
|
248
|
-
// ── OAuth FREE: Kiro (kr/) — Unlimited ──
|
|
249
|
-
{ id: '9router/kr/claude-sonnet-4.5', name: 'Claude Sonnet 4.5 (Kiro)', descVi: 'Claude miễn phí qua AWS', descEn: 'Free Claude via AWS', badge: '🆓 Kiro' },
|
|
250
|
-
{ id: '9router/kr/claude-haiku-4.5', name: 'Claude Haiku 4.5 (Kiro)', descVi: 'Haiku miễn phí', descEn: 'Haiku free', badge: '🆓 Kiro' },
|
|
251
|
-
{ id: '9router/kr/deepseek-3.2', name: 'DeepSeek 3.2 (Kiro)', descVi: 'DeepSeek via Kiro', descEn: 'DeepSeek via Kiro', badge: '🆓 Kiro' },
|
|
252
|
-
{ id: '9router/kr/deepseek-3.1', name: 'DeepSeek 3.1 (Kiro)', descVi: 'DeepSeek via Kiro', descEn: 'DeepSeek via Kiro', badge: '🆓 Kiro' },
|
|
253
|
-
{ id: '9router/kr/qwen3-coder-next', name: 'Qwen3 Coder Next (Kiro)', descVi: 'Qwen Next via Kiro', descEn: 'Qwen Next via Kiro', badge: '🆓 Kiro' },
|
|
254
|
-
|
|
255
|
-
// ── OAuth FREE: Kimi Coding (kmc/) ──
|
|
256
|
-
{ id: '9router/kmc/kimi-k2.5', name: 'Kimi K2.5 (Kimi Coding)', descVi: 'K2.5 miễn phí', descEn: 'K2.5 free', badge: '🆓 Kimi' },
|
|
257
|
-
{ id: '9router/kmc/kimi-k2.5-thinking', name: 'Kimi K2.5 Thinking', descVi: 'K2.5 + suy luận', descEn: 'K2.5 + thinking', badge: '🆓 Kimi' },
|
|
258
|
-
{ id: '9router/kmc/kimi-latest', name: 'Kimi Latest', descVi: 'Phiên bản mới nhất', descEn: 'Latest version', badge: '🆓 Kimi' },
|
|
259
|
-
|
|
260
|
-
// ── API Key: GLM (glm/) — Cheap ──
|
|
261
|
-
{ id: '9router/glm/glm-5.1', name: 'GLM 5.1', descVi: 'Zhipu AI mới nhất', descEn: 'Zhipu AI latest', badge: '💰 GLM' },
|
|
262
|
-
{ id: '9router/glm/glm-5', name: 'GLM 5', descVi: 'GLM 5', descEn: 'GLM 5', badge: '💰 GLM' },
|
|
263
|
-
{ id: '9router/glm/glm-4.7', name: 'GLM 4.7', descVi: '$0.6/1M tokens', descEn: '$0.6/1M tokens', badge: '💰 GLM' },
|
|
264
|
-
|
|
265
|
-
// ── API Key: MiniMax (minimax/) — Cheap ──
|
|
266
|
-
{ id: '9router/minimax/MiniMax-M2.7', name: 'MiniMax M2.7', descVi: 'Mới nhất MiniMax', descEn: 'Latest MiniMax', badge: '💰 MiniMax' },
|
|
267
|
-
{ id: '9router/minimax/MiniMax-M2.5', name: 'MiniMax M2.5', descVi: 'MiniMax M2.5', descEn: 'MiniMax M2.5', badge: '💰 MiniMax' },
|
|
268
|
-
{ id: '9router/minimax/MiniMax-M2.1', name: 'MiniMax M2.1', descVi: '$0.20/1M tokens', descEn: '$0.20/1M tokens', badge: '💰 MiniMax' },
|
|
269
|
-
|
|
270
|
-
// ── API Key: Kimi (kimi/) ──
|
|
271
|
-
{ id: '9router/kimi/kimi-k2.5', name: 'Kimi K2.5', descVi: 'Kimi K2.5 API', descEn: 'Kimi K2.5 API', badge: '💰 Kimi' },
|
|
272
|
-
{ id: '9router/kimi/kimi-k2.5-thinking', name: 'Kimi K2.5 Thinking', descVi: 'K2.5 + suy luận', descEn: 'K2.5 + thinking', badge: '💰 Kimi' },
|
|
273
|
-
{ id: '9router/kimi/kimi-latest', name: 'Kimi Latest', descVi: 'Phiên bản mới nhất', descEn: 'Latest version', badge: '💰 Kimi' },
|
|
274
|
-
|
|
275
|
-
// ── API Key: DeepSeek (deepseek/) ──
|
|
276
|
-
{ id: '9router/deepseek/deepseek-chat', name: 'DeepSeek V3.2 Chat', descVi: 'DeepSeek Chat', descEn: 'DeepSeek Chat', badge: '💰 DeepSeek' },
|
|
277
|
-
{ id: '9router/deepseek/deepseek-reasoner', name: 'DeepSeek V3.2 Reasoner', descVi: 'DeepSeek Reasoner', descEn: 'DeepSeek Reasoner', badge: '💰 DeepSeek' },
|
|
278
|
-
|
|
279
|
-
// ── API Key: xAI (xai/) ──
|
|
280
|
-
{ id: '9router/xai/grok-4', name: 'Grok 4', descVi: 'xAI flagship', descEn: 'xAI flagship', badge: '💰 xAI' },
|
|
281
|
-
{ id: '9router/xai/grok-4-fast-reasoning', name: 'Grok 4 Fast Reasoning', descVi: 'Suy luận nhanh', descEn: 'Fast reasoning', badge: '💰 xAI' },
|
|
282
|
-
{ id: '9router/xai/grok-code-fast-1', name: 'Grok Code Fast', descVi: 'Code nhanh', descEn: 'Fast coding', badge: '💰 xAI' },
|
|
283
|
-
|
|
284
|
-
// ── API Key: Mistral (mistral/) ──
|
|
285
|
-
{ id: '9router/mistral/mistral-large-latest', name: 'Mistral Large 3', descVi: 'Mistral flagship', descEn: 'Mistral flagship', badge: '💰 Mistral' },
|
|
286
|
-
{ id: '9router/mistral/codestral-latest', name: 'Codestral', descVi: 'Code-optimized', descEn: 'Code-optimized', badge: '💰 Mistral' },
|
|
287
|
-
|
|
288
|
-
// ── API Key: Groq (groq/) ──
|
|
289
|
-
{ id: '9router/groq/llama-3.3-70b-versatile', name: 'Llama 3.3 70B (Groq)', descVi: 'Siêu nhanh qua Groq', descEn: 'Ultra fast via Groq', badge: '⚡ Groq' },
|
|
290
|
-
{ id: '9router/groq/openai/gpt-oss-120b', name: 'GPT OSS 120B (Groq)', descVi: 'GPT OSS qua Groq', descEn: 'GPT OSS via Groq', badge: '⚡ Groq' },
|
|
291
|
-
|
|
292
|
-
// ── API Key: Cerebras (cerebras/) ──
|
|
293
|
-
{ id: '9router/cerebras/gpt-oss-120b', name: 'GPT OSS 120B (Cerebras)', descVi: 'Siêu nhanh Cerebras', descEn: 'Ultra fast Cerebras', badge: '⚡ Cerebras' },
|
|
294
|
-
|
|
295
|
-
// ── API Key: AliCode (alicode/) ──
|
|
296
|
-
{ id: '9router/alicode/qwen3.5-plus', name: 'Qwen3.5 Plus (AliCode)', descVi: 'Alibaba Cloud mới nhất', descEn: 'Alibaba Cloud latest', badge: '💰 AliCode' },
|
|
297
|
-
{ id: '9router/alicode/qwen3-coder-plus', name: 'Qwen3 Coder Plus (AliCode)', descVi: 'Coder Plus', descEn: 'Coder Plus', badge: '💰 AliCode' },
|
|
132
|
+
{ id: '9router/smart-route', name: 'Smart Proxy (Auto Route)', descVi: 'Tự động luân chuyển FREE models — không tốn xu', descEn: 'Auto-routing across FREE providers — zero cost', badgeVi: '🌟 Khuyên dùng', badgeEn: '🌟 Recommended' }
|
|
298
133
|
],
|
|
299
134
|
},
|
|
300
135
|
};
|
|
@@ -924,30 +759,17 @@
|
|
|
924
759
|
pHtml += `<h3 style="margin: 0 0 12px; font-size: 15px; font-weight: 700; color: var(--text-primary);">${providerIcon} ${isVi ? 'AI Provider' : 'AI Provider'} — ${providerName}</h3>`;
|
|
925
760
|
|
|
926
761
|
if (provider.isProxy) {
|
|
927
|
-
// 9Router: simple message
|
|
928
|
-
pHtml += `<p style="font-size: 13px; color: var(--text-secondary); margin: 0 0
|
|
762
|
+
// 9Router: simple message (no API key needed - managed via dashboard)
|
|
763
|
+
pHtml += `<p style="font-size: 13px; color: var(--text-secondary); margin: 0 0 8px;">
|
|
929
764
|
${isVi
|
|
930
765
|
? 'Sau khi Docker khởi động xong, mở <a href="http://localhost:20128/dashboard" target="_blank" style="color: var(--accent);">localhost:20128/dashboard</a> để đăng nhập OAuth và kết nối các Provider.'
|
|
931
766
|
: 'After Docker starts, open <a href="http://localhost:20128/dashboard" target="_blank" style="color: var(--accent);">localhost:20128/dashboard</a> to OAuth login and connect Providers.'}
|
|
932
767
|
</p>`;
|
|
933
|
-
pHtml += `<
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
<span class="toggle-slider"></span>
|
|
939
|
-
</label>
|
|
940
|
-
</div>
|
|
941
|
-
<p style="font-size: 11px; color: var(--text-muted); margin: 6px 0 0;">
|
|
942
|
-
${isVi ? 'Khuyên dùng khi chạy trên VPS/mạng chung — tự tạo API Key để bảo vệ proxy.' : 'Recommended for VPS/shared networks — auto-generates API Key to protect your proxy.'}
|
|
943
|
-
</p>
|
|
944
|
-
<div id="9router-key-display" style="display: none; margin-top: 10px;">
|
|
945
|
-
<div style="display: flex; gap: 8px; align-items: center;">
|
|
946
|
-
<input type="text" class="form-input" id="key-9router-apikey" readonly style="font-family: monospace; font-size: 12px; background: rgba(0,0,0,0.2); flex: 1; padding: 8px 12px;" value="">
|
|
947
|
-
<button type="button" onclick="navigator.clipboard.writeText(document.getElementById('key-9router-apikey').value);this.textContent='✅';setTimeout(()=>this.textContent='📋',1500)" style="padding: 6px 10px; border-radius: 8px; border: 1px solid rgba(139,92,246,0.3); background: rgba(139,92,246,0.1); cursor: pointer; font-size: 13px;">📋</button>
|
|
948
|
-
</div>
|
|
949
|
-
</div>
|
|
950
|
-
</div>`;
|
|
768
|
+
pHtml += `<p style="font-size: 12px; color: var(--text-muted); margin: 0;">
|
|
769
|
+
${isVi
|
|
770
|
+
? '💡 Bot và 9Router cùng Docker network — không cần API Key. Nếu muốn bảo mật proxy (VPS), tạo API Key trên Dashboard sau khi Docker chạy.'
|
|
771
|
+
: '💡 Bot and 9Router share Docker network — no API Key needed. To secure proxy (VPS), create API Key on Dashboard after Docker starts.'}
|
|
772
|
+
</p>`;
|
|
951
773
|
} else if (provider.isLocal) {
|
|
952
774
|
// Ollama
|
|
953
775
|
pHtml += `<p style="font-size: 13px; color: var(--text-secondary); margin: 0;">
|
|
@@ -956,7 +778,7 @@
|
|
|
956
778
|
} else {
|
|
957
779
|
// Direct API provider: show key input
|
|
958
780
|
pHtml += `<div class="form-group" style="margin: 0;">
|
|
959
|
-
<label class="form-group__label" for="key-api-key">🔑 ${provider.envLabel}
|
|
781
|
+
<label class="form-group__label" for="key-api-key">🔑 ${provider.envLabel} <span style="color: var(--danger, #ef4444);">*</span></label>
|
|
960
782
|
<input type="text" class="form-input" id="key-api-key" placeholder="${provider.envKey}=..." style="font-family: monospace; font-size: 13px;" oninput="window.__validateKeys()">
|
|
961
783
|
<p class="form-group__hint">${isVi ? 'Lấy từ' : 'Get from'} <a href="${provider.envLink}" target="_blank">${provider.envLink.replace('https://', '')}</a></p>
|
|
962
784
|
</div>`;
|
|
@@ -978,13 +800,13 @@
|
|
|
978
800
|
|
|
979
801
|
if (state.channel === 'telegram') {
|
|
980
802
|
cHtml += `<div class="form-group" style="margin: 0;">
|
|
981
|
-
<label class="form-group__label" for="key-bot-token">🤖 Telegram Bot Token
|
|
803
|
+
<label class="form-group__label" for="key-bot-token">🤖 Telegram Bot Token <span style="color: var(--danger, #ef4444);">*</span></label>
|
|
982
804
|
<input type="text" class="form-input" id="key-bot-token" placeholder="VD: 1234567890:ABCdefGHIjklMNOpqrsTUVwxyz" style="font-family: monospace; font-size: 13px;" oninput="window.__validateKeys()">
|
|
983
805
|
<p class="form-group__hint">${isVi ? 'Lấy từ <a href="https://t.me/BotFather" target="_blank">@BotFather</a> trên Telegram' : 'Get from <a href="https://t.me/BotFather" target="_blank">@BotFather</a> on Telegram'}</p>
|
|
984
806
|
</div>`;
|
|
985
807
|
} else if (state.channel === 'zalo-bot') {
|
|
986
808
|
cHtml += `<div class="form-group" style="margin: 0;">
|
|
987
|
-
<label class="form-group__label" for="key-bot-token">🔑 Zalo Bot Token
|
|
809
|
+
<label class="form-group__label" for="key-bot-token">🔑 Zalo Bot Token <span style="color: var(--danger, #ef4444);">*</span></label>
|
|
988
810
|
<input type="text" class="form-input" id="key-bot-token" placeholder="Zalo Bot Token" style="font-family: monospace; font-size: 13px;" oninput="window.__validateKeys()">
|
|
989
811
|
<p class="form-group__hint">${isVi ? 'Lấy từ <a href="https://developers.zalo.me" target="_blank">Zalo Bot Platform</a>' : 'Get from <a href="https://developers.zalo.me" target="_blank">Zalo Bot Platform</a>'}</p>
|
|
990
812
|
</div>`;
|
|
@@ -1025,22 +847,7 @@
|
|
|
1025
847
|
}
|
|
1026
848
|
}
|
|
1027
849
|
window.__validateKeys = function() { updateNavButtons(); };
|
|
1028
|
-
|
|
1029
|
-
const display = document.getElementById('9router-key-display');
|
|
1030
|
-
const keyInput = document.getElementById('key-9router-apikey');
|
|
1031
|
-
if (!display || !keyInput) return;
|
|
1032
|
-
if (checked) {
|
|
1033
|
-
// Auto-generate a random 32-char hex key
|
|
1034
|
-
const key = (typeof crypto !== 'undefined' && crypto.randomUUID)
|
|
1035
|
-
? crypto.randomUUID().replace(/-/g, '')
|
|
1036
|
-
: Array.from({length: 32}, () => Math.floor(Math.random() * 16).toString(16)).join('');
|
|
1037
|
-
keyInput.value = 'oc9r-' + key;
|
|
1038
|
-
display.style.display = 'block';
|
|
1039
|
-
} else {
|
|
1040
|
-
keyInput.value = '';
|
|
1041
|
-
display.style.display = 'none';
|
|
1042
|
-
}
|
|
1043
|
-
};
|
|
850
|
+
// 9Router API keys are managed via its dashboard — no client-side generation needed
|
|
1044
851
|
|
|
1045
852
|
// ========== Build .env content from key inputs ==========
|
|
1046
853
|
function populateEnvContent() {
|
|
@@ -1057,11 +864,6 @@
|
|
|
1057
864
|
|
|
1058
865
|
if (provider.isProxy) {
|
|
1059
866
|
lines.push('# Không cần AI API key — 9Router xử lý qua dashboard');
|
|
1060
|
-
const routerApiKey = document.getElementById('key-9router-apikey')?.value?.trim() || '';
|
|
1061
|
-
if (routerApiKey) {
|
|
1062
|
-
lines.push(`\n# 9Router API Key (bảo mật proxy)`);
|
|
1063
|
-
lines.push(`ROUTER_API_KEY=${routerApiKey}`);
|
|
1064
|
-
}
|
|
1065
867
|
} else if (provider.isLocal) {
|
|
1066
868
|
lines.push('OLLAMA_HOST=http://host.docker.internal:11434');
|
|
1067
869
|
} else {
|
|
@@ -1227,36 +1029,38 @@ Write-Host "Chrome se tu dong bat Debug Mode moi khi ban dang nhap Windows (dela
|
|
|
1227
1029
|
};
|
|
1228
1030
|
|
|
1229
1031
|
// 9Router: add proxy endpoint config under models.providers
|
|
1230
|
-
//
|
|
1231
|
-
const routerKeyForConfig = document.getElementById('key-9router-apikey')?.value?.trim() || '';
|
|
1032
|
+
// Bot and 9Router share Docker network — no API key needed
|
|
1232
1033
|
if (is9Router) {
|
|
1233
1034
|
clawConfig.models = {
|
|
1234
1035
|
mode: 'merge',
|
|
1235
1036
|
providers: {
|
|
1236
1037
|
'9router': {
|
|
1237
1038
|
baseUrl: 'http://9router:20128/v1',
|
|
1238
|
-
apiKey:
|
|
1039
|
+
apiKey: 'sk-no-key',
|
|
1239
1040
|
api: 'openai-completions',
|
|
1240
1041
|
models: [
|
|
1241
|
-
|
|
1242
|
-
|
|
1243
|
-
{ id: 'cc/claude-opus-4-6', name: 'Claude Opus 4.6', contextWindow: 200000, maxTokens: 8192 },
|
|
1244
|
-
{ id: 'cc/claude-sonnet-4-6', name: 'Claude Sonnet 4.6', contextWindow: 200000, maxTokens: 8192 },
|
|
1245
|
-
{ id: 'cx/gpt-5.4', name: 'GPT 5.4 (Codex)', contextWindow: 128000, maxTokens: 8192 },
|
|
1246
|
-
{ id: 'cx/gpt-5.3-codex', name: 'GPT 5.3 Codex', contextWindow: 128000, maxTokens: 8192 },
|
|
1247
|
-
{ id: 'gh/gpt-5.4', name: 'GPT 5.4 (Copilot)', contextWindow: 128000, maxTokens: 8192 },
|
|
1248
|
-
{ id: 'gh/claude-opus-4.6', name: 'Claude Opus 4.6 (Copilot)', contextWindow: 200000, maxTokens: 8192 },
|
|
1249
|
-
{ id: 'gc/gemini-3-flash-preview', name: 'Gemini 3 Flash (FREE)', contextWindow: 1000000, maxTokens: 8192 },
|
|
1250
|
-
// OAuth FREE
|
|
1251
|
-
{ id: 'if/qwen3-coder-plus', name: 'Qwen3 Coder Plus (iFlow FREE)', contextWindow: 128000, maxTokens: 8192 },
|
|
1042
|
+
// Free Tier Providers
|
|
1043
|
+
{ id: 'if/qwen3-coder-plus', name: 'Qwen3 Coder+ (iFlow FREE)', contextWindow: 128000, maxTokens: 8192 },
|
|
1252
1044
|
{ id: 'if/kimi-k2', name: 'Kimi K2 (iFlow FREE)', contextWindow: 128000, maxTokens: 8192 },
|
|
1045
|
+
{ id: 'if/kimi-k2-thinking', name: 'Kimi K2 Thinking (iFlow FREE)', contextWindow: 128000, maxTokens: 8192 },
|
|
1253
1046
|
{ id: 'if/glm-4.7', name: 'GLM 4.7 (iFlow FREE)', contextWindow: 128000, maxTokens: 8192 },
|
|
1047
|
+
{ id: 'if/minimax-m2', name: 'MiniMax M2 (iFlow FREE)', contextWindow: 1000000, maxTokens: 8192 },
|
|
1254
1048
|
{ id: 'if/deepseek-r1', name: 'DeepSeek R1 (iFlow FREE)', contextWindow: 128000, maxTokens: 8192 },
|
|
1255
|
-
{ id: 'qw/qwen3-coder-plus', name: 'Qwen3 Coder
|
|
1049
|
+
{ id: 'qw/qwen3-coder-plus', name: 'Qwen3 Coder+ (Qwen FREE)', contextWindow: 128000, maxTokens: 8192 },
|
|
1050
|
+
{ id: 'qw/qwen3-coder-flash', name: 'Qwen3 Coder Flash (Qwen FREE)', contextWindow: 128000, maxTokens: 8192 },
|
|
1256
1051
|
{ id: 'kr/claude-sonnet-4.5', name: 'Claude Sonnet 4.5 (Kiro FREE)', contextWindow: 200000, maxTokens: 8192 },
|
|
1257
|
-
|
|
1052
|
+
{ id: 'kr/claude-haiku-4.5', name: 'Claude Haiku 4.5 (Kiro FREE)', contextWindow: 200000, maxTokens: 8192 },
|
|
1053
|
+
// Ollama Cloud
|
|
1054
|
+
{ id: 'ollama/qwen3.5', name: 'Qwen 3.5 (Ollama Cloud)', contextWindow: 128000, maxTokens: 8192 },
|
|
1055
|
+
{ id: 'ollama/kimi-k2.5', name: 'Kimi K2.5 (Ollama Cloud)', contextWindow: 128000, maxTokens: 8192 },
|
|
1056
|
+
{ id: 'ollama/glm-5', name: 'GLM 5 (Ollama Cloud)', contextWindow: 128000, maxTokens: 8192 },
|
|
1057
|
+
{ id: 'ollama/glm-4.7-flash', name: 'GLM 4.7 Flash (Ollama Cloud)', contextWindow: 128000, maxTokens: 8192 },
|
|
1058
|
+
{ id: 'ollama/minimax-m2.5', name: 'MiniMax M2.5 (Ollama Cloud)', contextWindow: 128000, maxTokens: 8192 },
|
|
1059
|
+
{ id: 'ollama/gpt-oss:120b', name: 'GPT-OSS 120B (Ollama Cloud)', contextWindow: 128000, maxTokens: 8192 },
|
|
1060
|
+
// API Key Providers
|
|
1258
1061
|
{ id: 'glm/glm-4.7', name: 'GLM 4.7 ($0.6/1M)', contextWindow: 128000, maxTokens: 8192 },
|
|
1259
1062
|
{ id: 'minimax/MiniMax-M2.1', name: 'MiniMax M2.1 ($0.20/1M)', contextWindow: 1000000, maxTokens: 8192 },
|
|
1063
|
+
{ id: 'kimi/kimi-latest', name: 'Kimi Latest ($0.90/1M)', contextWindow: 128000, maxTokens: 8192 },
|
|
1260
1064
|
{ id: 'deepseek/deepseek-chat', name: 'DeepSeek V3.2 Chat', contextWindow: 128000, maxTokens: 8192 },
|
|
1261
1065
|
],
|
|
1262
1066
|
},
|
|
@@ -1377,6 +1181,11 @@ ${finalCmd}`;
|
|
|
1377
1181
|
// extra_hosts always needed for browser (socat → host Chrome)
|
|
1378
1182
|
const extraHostsBlock = ` extra_hosts:\n - "host.docker.internal:host-gateway"`;
|
|
1379
1183
|
|
|
1184
|
+
// ─── Dynamic Smart Route Sync Script ────────────────────────────────────────
|
|
1185
|
+
// Background loop inside 9Router container every 30s.
|
|
1186
|
+
// Queries /api/providers → filters connected+enabled → updates smart-route combo.
|
|
1187
|
+
const syncScript = `#!/bin/sh\nROUTER=http://localhost:20128\nINTERVAL=30\necho "[sync-combo] Waiting for 9Router..."\nwhile ! wget -qO- $ROUTER/api/version >/dev/null 2>&1; do sleep 2; done\necho "[sync-combo] 9Router ready. Syncing every \${INTERVAL}s..."\nwhile true; do\n PJ=$(wget -qO- $ROUTER/api/providers 2>/dev/null || echo '{}')\n CJ=$(node -e "\nconst PM={codex:['cx/gpt-5.4','cx/gpt-5.3-codex','cx/gpt-5.3-codex-high','cx/gpt-5.2-codex','cx/gpt-5.2','cx/gpt-5.1-codex-max','cx/gpt-5.1-codex','cx/gpt-5.1','cx/gpt-5-codex'],'claude-code':['cc/claude-opus-4-6','cc/claude-sonnet-4-6','cc/claude-opus-4-5-20251101','cc/claude-sonnet-4-5-20250929','cc/claude-haiku-4-5-20251001'],github:['gh/gpt-5.4','gh/gpt-5.3-codex','gh/gpt-5.2-codex','gh/gpt-5.2','gh/gpt-5.1-codex-max','gh/gpt-5.1-codex','gh/gpt-5.1','gh/gpt-5','gh/gpt-4.1','gh/gpt-4o','gh/claude-opus-4.6','gh/claude-sonnet-4.6','gh/claude-sonnet-4.5','gh/claude-opus-4.5','gh/claude-haiku-4.5','gh/gemini-3-pro-preview','gh/gemini-3-flash-preview','gh/gemini-2.5-pro'],cursor:['cu/default','cu/claude-4.6-opus-max','cu/claude-4.5-opus-high-thinking','cu/claude-4.5-sonnet-thinking','cu/claude-4.5-sonnet','cu/gpt-5.3-codex','cu/gpt-5.2-codex','cu/gemini-3-flash-preview'],kilo:['kc/anthropic/claude-sonnet-4-20250514','kc/anthropic/claude-opus-4-20250514','kc/google/gemini-2.5-pro','kc/google/gemini-2.5-flash','kc/openai/gpt-4.1','kc/deepseek/deepseek-chat'],cline:['cl/anthropic/claude-sonnet-4.6','cl/anthropic/claude-opus-4.6','cl/openai/gpt-5.3-codex','cl/openai/gpt-5.4','cl/google/gemini-3.1-pro-preview'],'gemini-cli':['gc/gemini-3-flash-preview','gc/gemini-3-pro-preview'],iflow:['if/qwen3-coder-plus','if/kimi-k2','if/kimi-k2-thinking','if/glm-4.7','if/deepseek-r1','if/deepseek-v3.2','if/deepseek-v3','if/qwen3-max','if/qwen3-235b','if/iflow-rome-30ba3b'],qwen:['qw/qwen3-coder-plus','qw/qwen3-coder-flash','qw/vision-model','qw/coder-model'],kiro:['kr/claude-sonnet-4.5','kr/claude-haiku-4.5','kr/deepseek-3.2','kr/deepseek-3.1','kr/qwen3-coder-next'],ollama:['ollama/qwen3.5','ollama/kimi-k2.5','ollama/glm-5','ollama/glm-4.7-flash','ollama/minimax-m2.5','ollama/gpt-oss:120b'],'kimi-coding':['kmc/kimi-k2.5','kmc/kimi-k2.5-thinking','kmc/kimi-latest'],glm:['glm/glm-5.1','glm/glm-5','glm/glm-4.7'],'glm-cn':['glm/glm-5.1','glm/glm-5','glm/glm-4.7'],minimax:['minimax/MiniMax-M2.7','minimax/MiniMax-M2.5','minimax/MiniMax-M2.1'],kimi:['kimi/kimi-k2.5','kimi/kimi-k2.5-thinking','kimi/kimi-latest'],deepseek:['deepseek/deepseek-chat','deepseek/deepseek-reasoner'],xai:['xai/grok-4','xai/grok-4-fast-reasoning','xai/grok-code-fast-1'],mistral:['mistral/mistral-large-latest','mistral/codestral-latest'],groq:['groq/llama-3.3-70b-versatile','groq/openai/gpt-oss-120b'],cerebras:['cerebras/gpt-oss-120b'],alicode:['alicode/qwen3.5-plus','alicode/qwen3-coder-plus'],openai:['openai/gpt-4o','openai/gpt-4.1'],anthropic:['anthropic/claude-sonnet-4','anthropic/claude-haiku-3.5'],gemini:['gemini/gemini-2.5-flash','gemini/gemini-2.5-pro']};\ntry{const d=$PJ;const a=(d.connections||[]).filter(c=>c.isActive).map(c=>c.provider);if(!a.length)process.exit(1);const m=a.flatMap(p=>PM[p]||[]);if(!m.length)process.exit(1);console.log(JSON.stringify({id:'smart-route',name:'smart-route',alias:'smart-route',models:m}))}catch(e){process.exit(1)}\n " 2>/dev/null)\n if [ -n "$CJ" ]; then\n node -e "\nconst fs=require('fs'),p='/root/.9router/db.json';let d={};try{d=JSON.parse(fs.readFileSync(p,'utf8'))}catch(e){}const c=$CJ;if(!d.combos)d.combos=[];const i=d.combos.findIndex(x=>x.id==='smart-route');if(i>=0){if(JSON.stringify(d.combos[i].models)!==JSON.stringify(c.models)){d.combos[i]=c;fs.writeFileSync(p,JSON.stringify(d,null,2));console.log('[sync-combo] Updated: '+c.models.length+' models')}}else{d.combos.push(c);fs.writeFileSync(p,JSON.stringify(d,null,2));console.log('[sync-combo] Created: '+c.models.length+' models')}\n " 2>/dev/null\n fi\n sleep $INTERVAL\ndone`;
|
|
1188
|
+
|
|
1380
1189
|
let compose;
|
|
1381
1190
|
if (is9Router) {
|
|
1382
1191
|
compose = `services:
|
|
@@ -1399,13 +1208,11 @@ ${extraHostsBlock}
|
|
|
1399
1208
|
container_name: 9router
|
|
1400
1209
|
restart: always
|
|
1401
1210
|
entrypoint: >
|
|
1402
|
-
/bin/sh -c "npm install -g 9router &&
|
|
1211
|
+
/bin/sh -c "npm install -g 9router && (echo '${syncScript}' > /tmp/sync.sh && sh /tmp/sync.sh &) && 9router"
|
|
1403
1212
|
environment:
|
|
1404
1213
|
- PORT=20128
|
|
1405
1214
|
- HOSTNAME=0.0.0.0
|
|
1406
|
-
- CI=true
|
|
1407
|
-
env_file:
|
|
1408
|
-
- .env
|
|
1215
|
+
- CI=true
|
|
1409
1216
|
volumes:
|
|
1410
1217
|
- 9router-data:/root/.9router
|
|
1411
1218
|
ports:
|
|
@@ -1453,13 +1260,11 @@ docker logs -f openclaw-bot${approveNote}`);
|
|
|
1453
1260
|
|
|
1454
1261
|
|
|
1455
1262
|
// 6. Generate auth-profiles.json (root + agent level)
|
|
1456
|
-
//
|
|
1457
|
-
// For 9Router: if user set API key → use it (enables Bearer auth); otherwise 'sk-no-key' (open access)
|
|
1263
|
+
// Bot and 9Router share Docker network — always use 'sk-no-key'
|
|
1458
1264
|
const authProviderName = is9Router ? '9router' : state.config.provider;
|
|
1459
1265
|
const authProfileId = is9Router ? '9router-proxy' : `${authProviderName}:default`;
|
|
1460
|
-
const router9ApiKey = document.getElementById('key-9router-apikey')?.value?.trim() || '';
|
|
1461
1266
|
const authKeyValue = is9Router
|
|
1462
|
-
?
|
|
1267
|
+
? 'sk-no-key'
|
|
1463
1268
|
: `<your_${(provider.envKey || 'API_KEY').toLowerCase()}>`;
|
|
1464
1269
|
|
|
1465
1270
|
const authProfilesJson = {
|
|
@@ -1967,8 +1772,12 @@ Write-Host " 🦞 OpenClaw Auto Setup" -ForegroundColor Cyan
|
|
|
1967
1772
|
Write-Host " Project: $projectDir" -ForegroundColor White
|
|
1968
1773
|
Write-Host ""
|
|
1969
1774
|
|
|
1775
|
+
try {
|
|
1970
1776
|
# [1/4] Create directories
|
|
1971
1777
|
Write-Host "[1/4] ${isVi ? 'Tạo thư mục...' : 'Creating directories...'}" -ForegroundColor Yellow
|
|
1778
|
+
|
|
1779
|
+
# Ensure root directory exists first
|
|
1780
|
+
New-Item -ItemType Directory -Force -Path "$projectDir" | Out-Null
|
|
1972
1781
|
`;
|
|
1973
1782
|
|
|
1974
1783
|
// Collect unique directories
|
|
@@ -2029,6 +1838,11 @@ Write-Host " 🎉 ${isVi ? 'Setup hoàn tất!' : 'Setup complete!'}" -Foregrou
|
|
|
2029
1838
|
}
|
|
2030
1839
|
|
|
2031
1840
|
ps += `Write-Host ""
|
|
1841
|
+
} catch {
|
|
1842
|
+
Write-Host ""
|
|
1843
|
+
Write-Host " ❌ LỖI / ERROR: $($_.Exception.Message)" -ForegroundColor Red
|
|
1844
|
+
Write-Host ""
|
|
1845
|
+
}
|
|
2032
1846
|
Read-Host "${isVi ? 'Nhấn Enter để thoát' : 'Press Enter to exit'}"
|
|
2033
1847
|
`;
|
|
2034
1848
|
|
|
@@ -2036,6 +1850,7 @@ Read-Host "${isVi ? 'Nhấn Enter để thoát' : 'Press Enter to exit'}"
|
|
|
2036
1850
|
const bat = `<# : batch wrapper
|
|
2037
1851
|
@echo off & chcp 65001>nul
|
|
2038
1852
|
powershell -ExecutionPolicy Bypass -NoProfile -File "%~f0" %*
|
|
1853
|
+
if %errorlevel% neq 0 pause
|
|
2039
1854
|
exit /b
|
|
2040
1855
|
#>
|
|
2041
1856
|
${ps}`;
|