create-openclaw-bot 5.6.8 → 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.
@@ -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 SMART_ROUTE_PROVIDER_MODELS = {
4
- 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'],
5
- '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'],
6
- 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'],
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
- function build9RouterComposeEntrypointScript(syncScriptBase64) {
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 docker9RouterEntrypointScript = build9RouterComposeEntrypointScript(syncScriptBase64);
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 Khoi dong lai bot ======' : 'echo ====== OpenClaw Restart Bot ======');
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 Khoi dong lai bot qua PM2 ======"' : 'echo "====== OpenClaw Restart Bot via PM2 ======"');
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 Khoi dong lai bot ======"' : 'echo "====== OpenClaw Restart Bot ======"');
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..."');