create-openclaw-bot 5.6.7 → 5.6.10
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/README.md +18 -19
- package/README.vi.md +18 -19
- package/dist/cli.js +214 -101
- package/dist/setup/data/channels.js +11 -1
- package/dist/setup/shared/common-gen.js +86 -0
- package/dist/setup/shared/docker-gen.js +73 -30
- package/dist/setup/shared/install-gen.js +23 -3
- package/dist/setup.js +217 -121
- package/package.json +1 -1
|
@@ -3,6 +3,39 @@
|
|
|
3
3
|
const OPENCLAW_NPM_SPEC = 'openclaw@2026.4.14';
|
|
4
4
|
const OPENCLAW_RUNTIME_PACKAGES = 'grammy @grammyjs/runner @grammyjs/transformer-throttler @buape/carbon @larksuiteoapi/node-sdk @slack/web-api';
|
|
5
5
|
const NINE_ROUTER_NPM_SPEC = '9router@latest';
|
|
6
|
+
const NINE_ROUTER_PORT = 20128;
|
|
7
|
+
const NINE_ROUTER_PROXY_API_KEY = 'sk-no-key';
|
|
8
|
+
const NINE_ROUTER_API_BASE_URL = `http://localhost:${NINE_ROUTER_PORT}`;
|
|
9
|
+
const NINE_ROUTER_DOCKER_API_BASE_URL = `http://9router:${NINE_ROUTER_PORT}`;
|
|
10
|
+
const SUPPORTED_CODEX_MODELS = ['cx/gpt-5.4', 'cx/gpt-5.3-codex', 'cx/gpt-5.2', 'cx/gpt-5.4-mini'];
|
|
11
|
+
const SMART_ROUTE_PROVIDER_MODELS = {
|
|
12
|
+
codex: SUPPORTED_CODEX_MODELS,
|
|
13
|
+
'claude-code': ['cc/claude-opus-4-7', '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'],
|
|
14
|
+
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-codex-mini', 'gh/gpt-5.1', 'gh/gpt-5-codex', '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', 'gh/grok-code-fast-1'],
|
|
15
|
+
cursor: ['cu/default', 'cu/claude-4.6-opus-max', 'cu/claude-4.6-sonnet-medium-thinking', 'cu/claude-4.5-opus-high-thinking', 'cu/claude-4.5-opus-high', 'cu/claude-4.5-sonnet-thinking', 'cu/claude-4.5-sonnet', 'cu/claude-4.5-haiku', 'cu/claude-4.5-opus', 'cu/gpt-5.3-codex', 'cu/gpt-5.2-codex', 'cu/gpt-5.2', 'cu/kimi-k2.5', 'cu/gemini-3-flash-preview'],
|
|
16
|
+
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', 'kc/deepseek/deepseek-reasoner'],
|
|
17
|
+
cline: ['cl/anthropic/claude-opus-4.7', 'cl/anthropic/claude-sonnet-4.6', 'cl/anthropic/claude-opus-4.6', 'cl/openai/gpt-5.4', 'cl/openai/gpt-5.3-codex', 'cl/google/gemini-3.1-pro-preview', 'cl/google/gemini-3.1-flash-lite-preview', 'cl/kwaipilot/kat-coder-pro'],
|
|
18
|
+
'gemini-cli': ['gc/gemini-3-flash-preview', 'gc/gemini-3-pro-preview'],
|
|
19
|
+
kiro: ['kr/claude-sonnet-4.5', 'kr/claude-haiku-4.5', 'kr/deepseek-3.2', 'kr/deepseek-3.1', 'kr/qwen3-coder-next', 'kr/glm-5', 'kr/MiniMax-M2.5'],
|
|
20
|
+
'kimi-coding': ['kmc/kimi-k2.5', 'kmc/kimi-k2.5-thinking', 'kmc/kimi-latest'],
|
|
21
|
+
openai: ['openai/gpt-5.4', 'openai/gpt-5.4-mini', 'openai/gpt-5.2', 'openai/gpt-5.1', 'openai/gpt-5', 'openai/gpt-4o', 'openai/gpt-4.1', 'openai/o3', 'openai/o4-mini'],
|
|
22
|
+
anthropic: ['anthropic/claude-sonnet-4-20250514', 'anthropic/claude-opus-4-20250514', 'anthropic/claude-3-5-sonnet-20241022'],
|
|
23
|
+
gemini: ['gemini/gemini-3.1-pro-preview', 'gemini/gemini-3-flash-preview', 'gemini/gemini-2.5-pro', 'gemini/gemini-2.5-flash', 'gemini/gemini-2.5-flash-lite'],
|
|
24
|
+
deepseek: ['deepseek/deepseek-chat', 'deepseek/deepseek-reasoner'],
|
|
25
|
+
xai: ['xai/grok-4', 'xai/grok-4-fast-reasoning', 'xai/grok-code-fast-1', 'xai/grok-3'],
|
|
26
|
+
mistral: ['mistral/mistral-large-latest', 'mistral/codestral-latest', 'mistral/mistral-medium-latest'],
|
|
27
|
+
iflow: ['if/qwen3-coder-plus', 'if/qwen3-max', 'if/qwen3-vl-plus', 'if/qwen3-max-preview', 'if/qwen3-235b', 'if/qwen3-32b', 'if/kimi-k2', 'if/deepseek-v3.2', 'if/deepseek-v3.1', 'if/deepseek-v3', 'if/deepseek-r1', 'if/glm-4.7', 'if/iflow-rome-30ba3b'],
|
|
28
|
+
qwen: ['qw/qwen3-coder-plus', 'qw/qwen3-coder-flash', 'qw/vision-model', 'qw/coder-model'],
|
|
29
|
+
alicode: ['alicode/qwen3.5-plus', 'alicode/kimi-k2.5', 'alicode/glm-5', 'alicode/qwen3-coder-next', 'alicode/qwen3-coder-plus', 'alicode/glm-4.7'],
|
|
30
|
+
groq: ['groq/llama-3.3-70b-versatile', 'groq/openai/gpt-oss-120b', 'groq/qwen/qwen3-32b'],
|
|
31
|
+
cerebras: ['cerebras/gpt-oss-120b', 'cerebras/zai-glm-4.7', 'cerebras/qwen-3-32b'],
|
|
32
|
+
glm: ['glm/glm-5.1', 'glm/glm-5', 'glm/glm-4.7'],
|
|
33
|
+
'glm-cn': ['glm-cn/glm-5.1', 'glm-cn/glm-5', 'glm-cn/glm-4.7', 'glm-cn/glm-4.6'],
|
|
34
|
+
minimax: ['minimax/MiniMax-M2.7', 'minimax/MiniMax-M2.5', 'minimax/MiniMax-M2.1'],
|
|
35
|
+
kimi: ['kimi/kimi-k2.5', 'kimi/kimi-k2.5-thinking', 'kimi/kimi-latest'],
|
|
36
|
+
ollama: ['ollama/qwen3.5', 'ollama/kimi-k2.5', 'ollama/glm-5', 'ollama/minimax-m2.5', 'ollama/glm-4.7-flash', 'ollama/gpt-oss:120b'],
|
|
37
|
+
};
|
|
38
|
+
const SMART_ROUTE_PROVIDER_ORDER = ['openai', 'anthropic', 'claude-code', 'codex', 'cursor', 'github', 'cline', 'kimi', 'minimax', 'deepseek', 'glm', 'alicode', 'xai', 'mistral', 'kilo', 'kiro', 'iflow', 'qwen', 'gemini-cli', 'gemini', 'ollama'];
|
|
6
39
|
const TELEGRAM_RELAY_PLUGIN_SPEC = 'openclaw-telegram-multibot-relay';
|
|
7
40
|
const TELEGRAM_RELAY_PLUGIN_ID = 'telegram-multibot-relay';
|
|
8
41
|
const TELEGRAM_SETUP_GUIDE_FILENAME = 'TELEGRAM-GROUP-SETUP.md';
|
|
@@ -209,10 +242,60 @@ If setup reported a plugin install error, run this after the bot is running:
|
|
|
209
242
|
return JSON.stringify(buildAuthProfilesJson(options), null, 2);
|
|
210
243
|
}
|
|
211
244
|
|
|
245
|
+
function get9RouterBaseUrl(deployMode = 'native') {
|
|
246
|
+
return deployMode === 'docker' ? `${NINE_ROUTER_DOCKER_API_BASE_URL}/v1` : `${NINE_ROUTER_API_BASE_URL}/v1`;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function build9RouterProviderConfig(baseUrl = `${NINE_ROUTER_API_BASE_URL}/v1`) {
|
|
250
|
+
return {
|
|
251
|
+
baseUrl,
|
|
252
|
+
apiKey: NINE_ROUTER_PROXY_API_KEY,
|
|
253
|
+
api: 'openai-completions',
|
|
254
|
+
models: [
|
|
255
|
+
{
|
|
256
|
+
id: 'smart-route',
|
|
257
|
+
name: 'Smart Proxy (Auto Route)',
|
|
258
|
+
contextWindow: 200000,
|
|
259
|
+
maxTokens: 8192,
|
|
260
|
+
},
|
|
261
|
+
...SUPPORTED_CODEX_MODELS.map((id) => ({
|
|
262
|
+
id,
|
|
263
|
+
name: `Codex ${id.slice(3).replace(/-/g, ' ').replace(/\b\w/g, (char) => char.toUpperCase())}`,
|
|
264
|
+
contextWindow: 200000,
|
|
265
|
+
maxTokens: 8192,
|
|
266
|
+
})),
|
|
267
|
+
],
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
function buildGatewayConfig(port = 18791, deployMode = 'native', allowedOrigins = []) {
|
|
272
|
+
const normalizedPort = Number(port) || 18791;
|
|
273
|
+
const cfg = {
|
|
274
|
+
port: normalizedPort,
|
|
275
|
+
mode: 'local',
|
|
276
|
+
controlUi: { allowedOrigins },
|
|
277
|
+
auth: { mode: 'token', token: crypto.randomUUID().replace(/-/g, '') },
|
|
278
|
+
};
|
|
279
|
+
if (deployMode === 'docker') {
|
|
280
|
+
cfg.bind = 'custom';
|
|
281
|
+
cfg.customBindHost = '0.0.0.0';
|
|
282
|
+
} else {
|
|
283
|
+
cfg.bind = 'loopback';
|
|
284
|
+
}
|
|
285
|
+
return cfg;
|
|
286
|
+
}
|
|
287
|
+
|
|
212
288
|
root.__openclawCommon = {
|
|
213
289
|
OPENCLAW_NPM_SPEC,
|
|
214
290
|
OPENCLAW_RUNTIME_PACKAGES,
|
|
215
291
|
NINE_ROUTER_NPM_SPEC,
|
|
292
|
+
NINE_ROUTER_PORT,
|
|
293
|
+
NINE_ROUTER_PROXY_API_KEY,
|
|
294
|
+
NINE_ROUTER_API_BASE_URL,
|
|
295
|
+
NINE_ROUTER_DOCKER_API_BASE_URL,
|
|
296
|
+
SUPPORTED_CODEX_MODELS,
|
|
297
|
+
SMART_ROUTE_PROVIDER_MODELS,
|
|
298
|
+
SMART_ROUTE_PROVIDER_ORDER,
|
|
216
299
|
TELEGRAM_RELAY_PLUGIN_SPEC,
|
|
217
300
|
TELEGRAM_RELAY_PLUGIN_ID,
|
|
218
301
|
TELEGRAM_SETUP_GUIDE_FILENAME,
|
|
@@ -221,6 +304,9 @@ If setup reported a plugin install error, run this after the bot is running:
|
|
|
221
304
|
buildTelegramPostInstallChecklist,
|
|
222
305
|
buildAuthProfilesJson,
|
|
223
306
|
buildAuthProfilesString,
|
|
307
|
+
get9RouterBaseUrl,
|
|
308
|
+
build9RouterProviderConfig,
|
|
309
|
+
buildGatewayConfig,
|
|
224
310
|
};
|
|
225
311
|
|
|
226
312
|
})(typeof globalThis !== 'undefined' ? globalThis : {});
|
|
@@ -1,33 +1,9 @@
|
|
|
1
1
|
// @ts-nocheck
|
|
2
2
|
(function (root) {
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
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'],
|
|
8
|
-
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'],
|
|
9
|
-
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'],
|
|
10
|
-
'gemini-cli': ['gc/gemini-3-flash-preview', 'gc/gemini-3-pro-preview'],
|
|
11
|
-
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'],
|
|
12
|
-
qwen: ['qw/qwen3-coder-plus', 'qw/qwen3-coder-flash', 'qw/vision-model', 'qw/coder-model'],
|
|
13
|
-
kiro: ['kr/claude-sonnet-4.5', 'kr/claude-haiku-4.5', 'kr/deepseek-3.2', 'kr/deepseek-3.1', 'kr/qwen3-coder-next'],
|
|
14
|
-
ollama: ['ollama/gemma4:e2b', 'ollama/gemma4:e4b', 'ollama/gemma4:26b', 'ollama/gemma4:31b', 'ollama/qwen3.5', 'ollama/kimi-k2.5', 'ollama/glm-5', 'ollama/glm-4.7-flash', 'ollama/minimax-m2.5', 'ollama/gpt-oss:120b'],
|
|
15
|
-
'kimi-coding': ['kmc/kimi-k2.5', 'kmc/kimi-k2.5-thinking', 'kmc/kimi-latest'],
|
|
16
|
-
glm: ['glm/glm-5.1', 'glm/glm-5', 'glm/glm-4.7'],
|
|
17
|
-
'glm-cn': ['glm/glm-5.1', 'glm/glm-5', 'glm/glm-4.7'],
|
|
18
|
-
minimax: ['minimax/MiniMax-M2.7', 'minimax/MiniMax-M2.5', 'minimax/MiniMax-M2.1'],
|
|
19
|
-
kimi: ['kimi/kimi-k2.5', 'kimi/kimi-k2.5-thinking', 'kimi/kimi-latest'],
|
|
20
|
-
deepseek: ['deepseek/deepseek-chat', 'deepseek/deepseek-reasoner'],
|
|
21
|
-
xai: ['xai/grok-4', 'xai/grok-4-fast-reasoning', 'xai/grok-code-fast-1'],
|
|
22
|
-
mistral: ['mistral/mistral-large-latest', 'mistral/codestral-latest'],
|
|
23
|
-
groq: ['groq/llama-3.3-70b-versatile', 'groq/openai/gpt-oss-120b'],
|
|
24
|
-
cerebras: ['cerebras/gpt-oss-120b'],
|
|
25
|
-
alicode: ['alicode/qwen3.5-plus', 'alicode/qwen3-coder-plus'],
|
|
26
|
-
openai: ['openai/gpt-4o', 'openai/gpt-4.1'],
|
|
27
|
-
anthropic: ['anthropic/claude-sonnet-4', 'anthropic/claude-haiku-3.5'],
|
|
28
|
-
gemini: ['gemini/gemini-2.5-flash', 'gemini/gemini-2.5-pro'],
|
|
29
|
-
};
|
|
30
|
-
const SMART_ROUTE_PROVIDER_ORDER = ['openai', 'anthropic', 'claude-code', 'codex', 'cursor', 'github', 'cline', 'kimi', 'minimax', 'deepseek', 'glm', 'alicode', 'xai', 'mistral', 'kilo', 'kiro', 'iflow', 'qwen', 'gemini-cli', 'ollama'];
|
|
3
|
+
const common = (typeof globalThis !== 'undefined' && globalThis.__openclawCommon) || {};
|
|
4
|
+
const SUPPORTED_CODEX_MODELS = common.SUPPORTED_CODEX_MODELS || ['cx/gpt-5.4', 'cx/gpt-5.3-codex', 'cx/gpt-5.2', 'cx/gpt-5.4-mini'];
|
|
5
|
+
const SMART_ROUTE_PROVIDER_MODELS = common.SMART_ROUTE_PROVIDER_MODELS || { codex: SUPPORTED_CODEX_MODELS };
|
|
6
|
+
const SMART_ROUTE_PROVIDER_ORDER = common.SMART_ROUTE_PROVIDER_ORDER || ['codex'];
|
|
31
7
|
|
|
32
8
|
function encodeBase64Utf8(value) {
|
|
33
9
|
if (typeof Buffer !== 'undefined') {
|
|
@@ -87,11 +63,75 @@ setTimeout(sync, 5000);
|
|
|
87
63
|
setInterval(sync, INTERVAL);`;
|
|
88
64
|
}
|
|
89
65
|
|
|
90
|
-
|
|
66
|
+
function build9RouterPatchScript() {
|
|
67
|
+
return `const fs=require('fs');const path=require('path');const cp=require('child_process');
|
|
68
|
+
const MODELS=${JSON.stringify(SUPPORTED_CODEX_MODELS.map((model) => model.replace('cx/', '')))};
|
|
69
|
+
const MODEL_NAMES={"gpt-5.4":"GPT 5.4","gpt-5.4-mini":"GPT 5.4 Mini","gpt-5.3-codex":"GPT 5.3 Codex","gpt-5.2":"GPT 5.2"};
|
|
70
|
+
const SELF_TEST_BLOCK=[
|
|
71
|
+
'codex: {',
|
|
72
|
+
' url: "https://chatgpt.com/backend-api/codex/responses",',
|
|
73
|
+
' method: "POST",',
|
|
74
|
+
' authHeader: "Authorization",',
|
|
75
|
+
' authPrefix: "Bearer ",',
|
|
76
|
+
' extraHeaders: { "Content-Type": "application/json", "originator": "codex-cli", "User-Agent": "codex-cli/1.0.18 (macOS; arm64)" },',
|
|
77
|
+
' body: JSON.stringify({',
|
|
78
|
+
' model: "gpt-5.2",',
|
|
79
|
+
' instructions: "You are a coding assistant.",',
|
|
80
|
+
' input: [{ role: "user", content: [{ type: "input_text", text: "Reply with exactly: ok" }] }],',
|
|
81
|
+
' stream: true,',
|
|
82
|
+
' store: false,',
|
|
83
|
+
' }),',
|
|
84
|
+
' acceptStatuses: [200, 400],',
|
|
85
|
+
' refreshable: true,',
|
|
86
|
+
' },'
|
|
87
|
+
].join('\\n');
|
|
88
|
+
const roots=new Set();
|
|
89
|
+
function add(p){if(p)roots.add(p);}
|
|
90
|
+
try{const npmRoot=cp.execSync('npm root -g',{stdio:['ignore','pipe','ignore'],encoding:'utf8'}).trim();if(npmRoot)add(path.join(npmRoot,'9router'));}catch{}
|
|
91
|
+
add(path.join(process.env.APPDATA||'','npm','node_modules','9router'));
|
|
92
|
+
add('/usr/local/lib/node_modules/9router');
|
|
93
|
+
add('/usr/lib/node_modules/9router');
|
|
94
|
+
add(path.join(process.cwd(),'node_modules','9router'));
|
|
95
|
+
function patchFile(filePath, transform){if(!fs.existsSync(filePath))return false;const before=fs.readFileSync(filePath,'utf8');const after=transform(before);if(!after||after===before)return false;fs.writeFileSync(filePath,after);return true;}
|
|
96
|
+
function patchText(text,replacers){let next=text;for(const replacer of replacers){next=replacer(next);}return next===text?null:next;}
|
|
97
|
+
function patchProviderModels(root){return patchFile(path.join(root,'open-sse','config','providerModels.js'),(text)=>text.replace(/cx:\\s*\\[[\\s\\S]*?\\],/,()=>{const lines=MODELS.map((id)=>' { id: "'+id+'", name: "'+(MODEL_NAMES[id]||id)+'" },');return 'cx: [ // OpenAI Codex\\n'+lines.join('\\n')+'\\n ],';}));}
|
|
98
|
+
function patchCodexLikeFile(filePath){return patchFile(filePath,(text)=>{if(text.includes('max_output_tokens'))return text;return patchText(text,[
|
|
99
|
+
(value)=>value.replace(/delete (\\w+)\\.max_tokens,delete \\1\\.user/g,'delete $1.max_tokens,delete $1.max_output_tokens,delete $1.user'),
|
|
100
|
+
(value)=>value.replace(/delete (\\w+)\\.max_tokens;(\\s*)delete \\1\\.user/g,'delete $1.max_tokens;$2delete $1.max_output_tokens;$2delete $1.user'),
|
|
101
|
+
(value)=>value.replace(' delete body.max_tokens;\\n',' delete body.max_tokens;\\n delete body.max_output_tokens;\\n')
|
|
102
|
+
]);});}
|
|
103
|
+
function patchCodexExecutor(root){let touched=0;touched+=patchCodexLikeFile(path.join(root,'open-sse','executors','codex.js'))?1:0;const chunksDir=path.join(root,'app','.next','server','chunks');if(fs.existsSync(chunksDir)){for(const entry of fs.readdirSync(chunksDir)){if(!entry.endsWith('.js'))continue;touched+=patchCodexLikeFile(path.join(chunksDir,entry))?1:0;}}return touched;}
|
|
104
|
+
function patchResponsesNullGuard(root){let touched=0;const chunksDir=path.join(root,'app','.next','server','chunks');if(!fs.existsSync(chunksDir))return touched;for(const entry of fs.readdirSync(chunksDir)){if(!entry.endsWith('.js'))continue;touched+=patchFile(path.join(chunksDir,entry),(text)=>patchText(text,[
|
|
105
|
+
(value)=>value.replace('let b=a.content.find(a=>"output_text"===a.type);','let b=a.content.find(a=>a&&"output_text"===a.type);'),
|
|
106
|
+
(value)=>value.replace('let c=a.content.find(a=>"string"==typeof a.text);','let c=a.content.find(a=>a&&"string"==typeof a.text);'),
|
|
107
|
+
(value)=>value.replace('let b=a.filter(a=>a?.type==="message");','let b=a.filter(a=>a&&a?.type==="message");'),
|
|
108
|
+
(value)=>value.replace('for(let a of j){let b=a.type||(a.role?"message":null);','for(let a of j){let b=a&&(a.type||(a.role?"message":null));'),
|
|
109
|
+
(value)=>value.replace('for(let a of b.messages||[]){if("system"===a.role){','for(let a of b.messages||[])if(a){if("system"===a.role){'),
|
|
110
|
+
(value)=>value.replace('let b=Array.isArray(a.content)?a.content.map(a=>"input_text"===a.type||"output_text"===a.type?{type:"text",text:a.text}:"input_image"===a.type?{type:"image_url",image_url:{url:a.image_url||a.file_id||"",detail:a.detail||"auto"}}:a):a.content;','let b=Array.isArray(a.content)?a.content.map(a=>a&&("input_text"===a.type||"output_text"===a.type)?{type:"text",text:a.text}:a&&"input_image"===a.type?{type:"image_url",image_url:{url:a.image_url||a.file_id||"",detail:a.detail||"auto"}}:a).filter(Boolean):a.content;'),
|
|
111
|
+
(value)=>value.replace('c="string"==typeof a.content?[{type:b,text:a.content}]:Array.isArray(a.content)?a.content.map(a=>{if("text"===a.type)return{type:b,text:a.text};if("image_url"===a.type)return{type:"input_image",image_url:"string"==typeof a.image_url?a.image_url:a.image_url?.url,detail:a.image_url?.detail||"auto"};if("input_image"===a.type)return a;let c=a.text||a.content||JSON.stringify(a);return{type:b,text:"string"==typeof c?c:JSON.stringify(c)}}):[];','c="string"==typeof a.content?[{type:b,text:a.content}]:Array.isArray(a.content)?a.content.map(a=>{if(!a)return null;if("text"===a.type)return{type:b,text:a.text};if("image_url"===a.type)return{type:"input_image",image_url:"string"==typeof a.image_url?a.image_url:a.image_url?.url,detail:a.image_url?.detail||"auto"};if("input_image"===a.type)return a;let c=a.text||a.content||JSON.stringify(a);return{type:b,text:"string"==typeof c?c:JSON.stringify(c)}}).filter(Boolean):[];'),
|
|
112
|
+
(value)=>value.replace('b.tools&&Array.isArray(b.tools)&&(e.tools=b.tools.map(a=>{if(a.function)return a;let b=a.name;return b&&"string"==typeof b&&""!==b.trim()?{type:"function",function:{name:b,description:String(a.description||""),parameters:i(a.parameters),strict:a.strict}}:null}).filter(Boolean))','b.tools&&Array.isArray(b.tools)&&(e.tools=b.tools.map(a=>{if(!a)return null;if(a.function)return a;let b=a.name;return b&&"string"==typeof b&&""!==b.trim()?{type:"function",function:{name:b,description:String(a.description||""),parameters:i(a.parameters),strict:a.strict}}:null}).filter(Boolean))'),
|
|
113
|
+
(value)=>value.replace('b.tools&&Array.isArray(b.tools)&&(e.tools=b.tools.map(a=>"function"===a.type?{type:"function",name:a.function.name,description:String(a.function.description||""),parameters:i(a.function.parameters),strict:a.function.strict}:a)),','b.tools&&Array.isArray(b.tools)&&(e.tools=b.tools.map(a=>a&&"function"===a.type?{type:"function",name:a.function.name,description:String(a.function.description||""),parameters:i(a.function.parameters),strict:a.function.strict}:a).filter(Boolean)),'),
|
|
114
|
+
(value)=>value.replace('filter(a=>"function_call"===a.type)','filter(a=>a&&"function_call"===a.type)'),
|
|
115
|
+
(value)=>value.replace(/filter\\(a=>"text"===a\\.type\\)/g,'filter(a=>a&&"text"===a.type)'),
|
|
116
|
+
(value)=>value.replace(/find\\(a=>"message_stop"===a\\.type\\)/g,'find(a=>a&&"message_stop"===a.type)'),
|
|
117
|
+
(value)=>value.replace(/find\\(a=>"content_block_delta"===a\\.type\\)/g,'find(a=>a&&"content_block_delta"===a.type)'),
|
|
118
|
+
(value)=>value.replace(/find\\(a=>"message_delta"===a\\.type\\)/g,'find(a=>a&&"message_delta"===a.type)'),
|
|
119
|
+
(value)=>value.replace(/find\\(a=>"message_start"===a\\.type\\)/g,'find(a=>a&&"message_start"===a.type)'),
|
|
120
|
+
(value)=>value.replace(/for\\(let e of a\\.content\\)(?!if\\(e\\))/g,'for(let e of a.content)if(e)')
|
|
121
|
+
] ))?1:0;}return touched;}
|
|
122
|
+
function patchSelfTest(root){return patchFile(path.join(root,'src','app','api','providers','[id]','test','testUtils.js'),(text)=>{if(text.includes('model: "gpt-5.2"')&&text.includes('store: false')&&text.includes('acceptStatuses: [200, 400]'))return text;return text.replace(/codex:\\s*\\{[\\s\\S]*?refreshable:\\s*true,\\s*\\},/,SELF_TEST_BLOCK);});}
|
|
123
|
+
let touched=0;
|
|
124
|
+
for(const root of roots){if(!root||!fs.existsSync(root))continue;touched+=patchProviderModels(root)?1:0;touched+=patchCodexExecutor(root)?1:0;touched+=patchResponsesNullGuard(root)?1:0;touched+=patchSelfTest(root)?1:0;}
|
|
125
|
+
if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}else{console.log('[patch-9router] No compatible 9router source files found to patch.');}`;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
function build9RouterComposeEntrypointScript(syncScriptBase64, patchScriptBase64) {
|
|
91
129
|
const nineRouterSpec = (typeof globalThis !== 'undefined' && globalThis.__openclawCommon && globalThis.__openclawCommon.NINE_ROUTER_NPM_SPEC) || '9router@latest';
|
|
92
130
|
return [
|
|
93
131
|
`npm install -g ${nineRouterSpec}`,
|
|
132
|
+
`node -e "require('fs').writeFileSync('/tmp/patch-9router.js',Buffer.from('${patchScriptBase64}','base64').toString())"`,
|
|
94
133
|
`node -e "require('fs').writeFileSync('/tmp/sync.js',Buffer.from('${syncScriptBase64}','base64').toString())"`,
|
|
134
|
+
'node /tmp/patch-9router.js || true',
|
|
95
135
|
'node /tmp/sync.js > /tmp/sync.log 2>&1 &',
|
|
96
136
|
'exec 9router -n -l -H 0.0.0.0 -p 20128 --skip-update'
|
|
97
137
|
].join('\n');
|
|
@@ -179,7 +219,9 @@ CMD ["/bin/sh", "/usr/local/bin/openclaw-entrypoint.sh"]`;
|
|
|
179
219
|
|
|
180
220
|
const syncScript = build9RouterSmartRouteSyncScript('/root/.9router/db.json');
|
|
181
221
|
const syncScriptBase64 = encodeBase64Utf8(syncScript);
|
|
182
|
-
const
|
|
222
|
+
const patchScript = build9RouterPatchScript();
|
|
223
|
+
const patchScriptBase64 = encodeBase64Utf8(patchScript);
|
|
224
|
+
const docker9RouterEntrypointScript = build9RouterComposeEntrypointScript(syncScriptBase64, patchScriptBase64);
|
|
183
225
|
const extraHostsBlock = ` extra_hosts:\n - "host.docker.internal:host-gateway"`;
|
|
184
226
|
|
|
185
227
|
const appEnvironmentBlock = ' environment:\n - OPENCLAW_HOME=/root/project/.openclaw\n - OPENCLAW_STATE_DIR=/root/project/.openclaw\n';
|
|
@@ -388,6 +430,7 @@ ${appEnvironmentBlock}${plainSingleExtraHosts ? `${extraHostsBlock}\n` : ''}
|
|
|
388
430
|
encodeBase64Utf8,
|
|
389
431
|
indentBlock,
|
|
390
432
|
build9RouterSmartRouteSyncScript,
|
|
433
|
+
build9RouterPatchScript,
|
|
391
434
|
build9RouterComposeEntrypointScript,
|
|
392
435
|
buildGatewayPatchCmd,
|
|
393
436
|
buildDockerArtifacts,
|
|
@@ -160,7 +160,7 @@ fi
|
|
|
160
160
|
L.push('set "PATH=%APPDATA%\\npm;%PATH%"');
|
|
161
161
|
L.push('powershell -NoProfile -Command "Set-ExecutionPolicy -Scope CurrentUser -ExecutionPolicy RemoteSigned -Force" >nul 2>&1');
|
|
162
162
|
L.push('echo.');
|
|
163
|
-
L.push(isVi ? 'echo ====== OpenClaw
|
|
163
|
+
L.push(isVi ? 'echo ====== OpenClaw - Khoi dong lai bot ======' : 'echo ====== OpenClaw - Restart Bot ======');
|
|
164
164
|
L.push('echo.');
|
|
165
165
|
L.push(isVi ? 'echo [1] Dung process openclaw cu (neu co)...' : 'echo [1] Stopping existing openclaw process (if any)...');
|
|
166
166
|
L.push('call openclaw gateway stop >nul 2>&1');
|
|
@@ -174,11 +174,20 @@ fi
|
|
|
174
174
|
L.push("echo $env:DATA_DIR = '%DATA_DIR%' > \"%TEMP%\\oc-start9r.ps1\"");
|
|
175
175
|
L.push("echo $b = Join-Path $env:APPDATA 'npm\\9router.cmd' >> \"%TEMP%\\oc-start9r.ps1\"");
|
|
176
176
|
L.push("echo if ^(-not ^(Test-Path $b^)^) { $b = Join-Path $env:APPDATA 'npm\\9router' } >> \"%TEMP%\\oc-start9r.ps1\"");
|
|
177
|
+
L.push(`echo $patch = Join-Path '${projectDir}' '.openclaw\\patch-9router.js' >> "%TEMP%\\oc-start9r.ps1"`);
|
|
178
|
+
L.push("echo if ^(Test-Path $patch^) { ^& node $patch ^| Out-Null } >> \"%TEMP%\\oc-start9r.ps1\"");
|
|
177
179
|
L.push(`echo Start-Process 'cmd.exe' -WindowStyle Hidden -WorkingDirectory '${projectDir}' -ArgumentList ^('/c "' + $b + '" -n -H 0.0.0.0 -p 20128 --skip-update'^) >> "%TEMP%\\oc-start9r.ps1"`);
|
|
178
180
|
L.push('powershell -NoProfile -ExecutionPolicy Bypass -File "%TEMP%\\oc-start9r.ps1"');
|
|
179
181
|
L.push('del "%TEMP%\\oc-start9r.ps1" >nul 2>&1');
|
|
180
182
|
L.push('timeout /t 5 /nobreak >nul');
|
|
181
183
|
L.push(isVi ? 'echo [OK] 9Router da khoi dong.' : 'echo [OK] 9Router started.');
|
|
184
|
+
L.push('');
|
|
185
|
+
L.push(isVi ? 'echo [2b] Khoi dong sync smart-route...' : 'echo [2b] Starting smart-route sync...');
|
|
186
|
+
L.push(`echo $env:DATA_DIR = '%DATA_DIR%' > "%TEMP%\\oc-syncsmart.ps1"`);
|
|
187
|
+
L.push(`echo $sync = Join-Path '${projectDir}' '.openclaw\\9router-smart-route-sync.js' >> "%TEMP%\\oc-syncsmart.ps1"`);
|
|
188
|
+
L.push(`echo if ^(Test-Path $sync^) { Start-Process 'node' -WindowStyle Hidden -ArgumentList $sync } >> "%TEMP%\\oc-syncsmart.ps1"`);
|
|
189
|
+
L.push('powershell -NoProfile -ExecutionPolicy Bypass -File "%TEMP%\\oc-syncsmart.ps1"');
|
|
190
|
+
L.push('del "%TEMP%\\oc-syncsmart.ps1" >nul 2>&1');
|
|
182
191
|
}
|
|
183
192
|
L.push('');
|
|
184
193
|
L.push(isVi ? 'echo [3] Khoi dong OpenClaw Gateway...' : 'echo [3] Starting OpenClaw Gateway...');
|
|
@@ -245,7 +254,7 @@ fi
|
|
|
245
254
|
L.push(' exit 1');
|
|
246
255
|
L.push('fi');
|
|
247
256
|
L.push('');
|
|
248
|
-
L.push(isVi ? 'echo "====== OpenClaw
|
|
257
|
+
L.push(isVi ? 'echo "====== OpenClaw - Khoi dong lai bot qua PM2 ======"' : 'echo "====== OpenClaw - Restart Bot via PM2 ======"');
|
|
249
258
|
L.push('echo ""');
|
|
250
259
|
if (is9Router) {
|
|
251
260
|
L.push(isVi ? 'echo "[1] Khoi dong lai 9Router qua PM2..."' : 'echo "[1] Restarting 9Router via PM2..."');
|
|
@@ -256,6 +265,9 @@ fi
|
|
|
256
265
|
L.push(' exit 1');
|
|
257
266
|
L.push('fi');
|
|
258
267
|
L.push('pm2 delete "$APP_NAME-9router" "$APP_NAME-9router-sync" >/dev/null 2>&1 || true');
|
|
268
|
+
L.push('if [ -f "$PROJECT_DIR/.openclaw/patch-9router.js" ]; then');
|
|
269
|
+
L.push(' "$NODE_BIN" "$PROJECT_DIR/.openclaw/patch-9router.js" >/dev/null 2>&1 || true');
|
|
270
|
+
L.push('fi');
|
|
259
271
|
L.push('PORT=20128 HOSTNAME=0.0.0.0 DATA_DIR="$DATA_DIR" pm2 start "$NINE_ROUTER_BIN" --name "$APP_NAME-9router" --interpreter "$NODE_BIN" -- -n -H 0.0.0.0 -p 20128 --skip-update');
|
|
260
272
|
L.push('if [ -f "$PROJECT_DIR/.openclaw/9router-smart-route-sync.js" ]; then');
|
|
261
273
|
L.push(' pm2 start "$NODE_BIN" --name "$APP_NAME-9router-sync" -- "$PROJECT_DIR/.openclaw/9router-smart-route-sync.js"');
|
|
@@ -291,7 +303,7 @@ fi
|
|
|
291
303
|
L.push('export DATA_DIR="$PWD/.9router"');
|
|
292
304
|
L.push('if [ -f ".env" ]; then set -a; . ./.env; set +a; fi');
|
|
293
305
|
L.push('');
|
|
294
|
-
L.push(isVi ? 'echo "====== OpenClaw
|
|
306
|
+
L.push(isVi ? 'echo "====== OpenClaw - Khoi dong lai bot ======"' : 'echo "====== OpenClaw - Restart Bot ======"');
|
|
295
307
|
L.push('');
|
|
296
308
|
L.push(isVi ? 'echo "[1] Dung openclaw gateway cu (neu co)..."' : 'echo "[1] Stopping existing openclaw gateway (if any)..."');
|
|
297
309
|
L.push('openclaw gateway stop 2>/dev/null || true');
|
|
@@ -306,9 +318,17 @@ fi
|
|
|
306
318
|
L.push(isVi ? ' echo "ERROR: Khong tim thay 9router! Chay: npm install -g 9router"' : ' echo "ERROR: 9router not found! Run: npm install -g 9router"');
|
|
307
319
|
L.push(' exit 1');
|
|
308
320
|
L.push('fi');
|
|
321
|
+
L.push('if [ -f "$PROJECT_DIR/.openclaw/patch-9router.js" ]; then');
|
|
322
|
+
L.push(' node "$PROJECT_DIR/.openclaw/patch-9router.js" >/dev/null 2>&1 || true');
|
|
323
|
+
L.push('fi');
|
|
309
324
|
L.push(`nohup env PORT=20128 HOSTNAME=0.0.0.0 DATA_DIR="$DATA_DIR" "$NINE_ROUTER_BIN" -n -H 0.0.0.0 -p 20128 --skip-update > "${logFile9r}" 2>&1 &`);
|
|
310
325
|
L.push('sleep 3');
|
|
311
326
|
L.push(isVi ? `echo "[OK] 9Router da khoi dong. Log: ${logFile9r}"` : `echo "[OK] 9Router started. Log: ${logFile9r}"`);
|
|
327
|
+
L.push('');
|
|
328
|
+
L.push(isVi ? 'echo "[2b] Khoi dong sync smart-route..."' : 'echo "[2b] Starting smart-route sync..."');
|
|
329
|
+
L.push('if [ -f "$PROJECT_DIR/.openclaw/9router-smart-route-sync.js" ]; then');
|
|
330
|
+
L.push(' nohup env DATA_DIR="$DATA_DIR" node "$PROJECT_DIR/.openclaw/9router-smart-route-sync.js" > /tmp/9router-sync.log 2>&1 &');
|
|
331
|
+
L.push('fi');
|
|
312
332
|
}
|
|
313
333
|
L.push('');
|
|
314
334
|
L.push(isVi ? 'echo "[3] Khoi dong OpenClaw Gateway..."' : 'echo "[3] Starting OpenClaw Gateway..."');
|