create-openclaw-bot 5.4.1 → 5.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +188 -170
- package/CHANGELOG.vi.md +186 -168
- package/README.md +323 -321
- package/README.vi.md +323 -321
- package/old_v510.js +0 -0
- package/package.json +1 -1
- package/setup/data/channels.js +164 -0
- package/setup/data/header.js +80 -0
- package/setup/data/index.js +73 -0
- package/setup/data/plugins.js +60 -0
- package/setup/data/providers.js +121 -0
- package/setup/data/skills.js +169 -0
- package/setup/shared/common-gen.js +223 -0
- package/setup/shared/docker-gen.js +359 -0
- package/setup/shared/runtime-gen.js +710 -0
- package/setup/shared/scaffold-gen.js +212 -0
- package/setup.js +82 -14
- package/patch-tray.js +0 -7
|
@@ -0,0 +1,359 @@
|
|
|
1
|
+
// @ts-nocheck
|
|
2
|
+
(function (root) {
|
|
3
|
+
function encodeBase64Utf8(value) {
|
|
4
|
+
if (typeof Buffer !== 'undefined') {
|
|
5
|
+
return Buffer.from(String(value), 'utf8').toString('base64');
|
|
6
|
+
}
|
|
7
|
+
return btoa(String.fromCharCode(...new TextEncoder().encode(String(value))));
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
function indentBlock(text, spaces) {
|
|
11
|
+
const prefix = ' '.repeat(spaces);
|
|
12
|
+
return String(text).split('\n').map((line) => `${prefix}${line}`).join('\n');
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function build9RouterSmartRouteSyncScript(dbPath) {
|
|
16
|
+
return `const fs=require('fs');const INTERVAL=30000;const p='${dbPath}';
|
|
17
|
+
const 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/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'],'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']};
|
|
18
|
+
console.log('[sync-combo] 9Router sync loop started...');
|
|
19
|
+
const sync = async () => {
|
|
20
|
+
try {
|
|
21
|
+
let db = {};
|
|
22
|
+
try { db = JSON.parse(fs.readFileSync(p, 'utf8')); } catch(e){}
|
|
23
|
+
if (!db.combos) db.combos = [];
|
|
24
|
+
const removeSmartRoute = () => {
|
|
25
|
+
const next = db.combos.filter(x => x.id !== 'smart-route');
|
|
26
|
+
if (next.length !== db.combos.length) {
|
|
27
|
+
db.combos = next;
|
|
28
|
+
fs.writeFileSync(p, JSON.stringify(db, null, 2));
|
|
29
|
+
console.log('[sync-combo] Removed smart-route (no active providers)');
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
const res = await fetch('http://localhost:20128/api/providers');
|
|
33
|
+
if (!res.ok) { console.log('[sync-combo] API not ready, retrying...'); return; }
|
|
34
|
+
const d = await res.json();
|
|
35
|
+
const a = (d.connections || []).filter(c => c && c.provider && c.isActive !== false && !c.disabled).map(c => c.provider);
|
|
36
|
+
if (!a.length) { removeSmartRoute(); return; }
|
|
37
|
+
const PREF = ['openai','anthropic','claude-code','codex','cursor','github','cline','kimi','minimax','deepseek','glm','alicode','xai','mistral','kilo','kiro','iflow','qwen','gemini-cli','ollama'];
|
|
38
|
+
a.sort((x, y) => (PREF.indexOf(x) === -1 ? 99 : PREF.indexOf(x)) - (PREF.indexOf(y) === -1 ? 99 : PREF.indexOf(y)));
|
|
39
|
+
const m = a.flatMap(pv => PM[pv] || []);
|
|
40
|
+
if (!m.length) { removeSmartRoute(); return; }
|
|
41
|
+
const c = { id: 'smart-route', name: 'smart-route', alias: 'smart-route', models: m };
|
|
42
|
+
const i = db.combos.findIndex(x => x.id === 'smart-route');
|
|
43
|
+
if (i >= 0) {
|
|
44
|
+
if (JSON.stringify(db.combos[i].models) !== JSON.stringify(c.models)) {
|
|
45
|
+
db.combos[i] = c;
|
|
46
|
+
fs.writeFileSync(p, JSON.stringify(db, null, 2));
|
|
47
|
+
console.log('[sync-combo] Updated smart-route: ' + c.models.length + ' models');
|
|
48
|
+
}
|
|
49
|
+
} else {
|
|
50
|
+
db.combos.push(c);
|
|
51
|
+
fs.writeFileSync(p, JSON.stringify(db, null, 2));
|
|
52
|
+
console.log('[sync-combo] Created smart-route: ' + c.models.length + ' models');
|
|
53
|
+
}
|
|
54
|
+
} catch (e) {}
|
|
55
|
+
};
|
|
56
|
+
setTimeout(sync, 5000);
|
|
57
|
+
setInterval(sync, INTERVAL);`;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function build9RouterComposeEntrypointScript(syncScriptBase64) {
|
|
61
|
+
return [
|
|
62
|
+
'npm install -g 9router',
|
|
63
|
+
`node -e "require('fs').writeFileSync('/tmp/sync.js',Buffer.from('${syncScriptBase64}','base64').toString())"`,
|
|
64
|
+
'node /tmp/sync.js > /tmp/sync.log 2>&1 &',
|
|
65
|
+
'exec 9router -n -l -H 0.0.0.0 -p 20128 --skip-update'
|
|
66
|
+
].join('\n');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function buildGatewayPatchCmd() {
|
|
70
|
+
return `node -e \\"const fs=require('fs'),os=require('os'),p='/root/.openclaw/openclaw.json';if(fs.existsSync(p)){const c=JSON.parse(fs.readFileSync(p,'utf8'));const a=new Set(['http://localhost:18791','http://127.0.0.1:18791','http://0.0.0.0:18791']);for(const entries of Object.values(os.networkInterfaces()||{})){for(const entry of entries||[]){if(!entry||entry.internal||entry.family!=='IPv4'||!entry.address)continue;a.add('http://' + entry.address + ':18791');}}c.tools=Object.assign({},c.tools,{profile:'full',exec:{host:'gateway',security:'full',ask:'off'}});c.gateway=Object.assign({},c.gateway,{port:18791,bind:'custom',customBindHost:'0.0.0.0',controlUi:Object.assign({},c.gateway?.controlUi,{allowedOrigins:Array.from(a).filter(Boolean)})});fs.writeFileSync(p,JSON.stringify(c,null,2));}\\"`;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function buildDockerArtifacts(options) {
|
|
74
|
+
const {
|
|
75
|
+
openClawNpmSpec,
|
|
76
|
+
openClawRuntimePackages,
|
|
77
|
+
is9Router,
|
|
78
|
+
isLocal,
|
|
79
|
+
isMultiBot,
|
|
80
|
+
hasBrowser,
|
|
81
|
+
selectedModel,
|
|
82
|
+
agentId,
|
|
83
|
+
allSkills = [],
|
|
84
|
+
dockerfileSkillInstallMode = 'none',
|
|
85
|
+
runtimeCommandParts = [],
|
|
86
|
+
volumeMount = '../../.openclaw:/root/.openclaw',
|
|
87
|
+
singleComposeName = 'oc-bot',
|
|
88
|
+
multiComposeName = 'oc-multibot',
|
|
89
|
+
singleAppContainerName = 'openclaw-bot',
|
|
90
|
+
multiAppContainerName = 'openclaw-multibot',
|
|
91
|
+
singleRouterContainerName = '9router',
|
|
92
|
+
multiRouterContainerName = '9router-multibot',
|
|
93
|
+
singleOllamaContainerName = 'ollama',
|
|
94
|
+
multiOllamaContainerName = 'ollama-multibot',
|
|
95
|
+
plainSingleExtraHosts = false,
|
|
96
|
+
multiOllamaNumParallel = 1,
|
|
97
|
+
singleOllamaNumParallel = 1,
|
|
98
|
+
emitBrowserInstall = true,
|
|
99
|
+
} = options;
|
|
100
|
+
|
|
101
|
+
const browserAptExtra = hasBrowser ? ' xvfb' : '';
|
|
102
|
+
const browserInstallLines = hasBrowser && emitBrowserInstall
|
|
103
|
+
? [
|
|
104
|
+
'',
|
|
105
|
+
'# Browser Automation: Playwright engine (needed for native CDP)',
|
|
106
|
+
'RUN npm install -g agent-browser playwright \\',
|
|
107
|
+
' && npx playwright install chromium --with-deps \\',
|
|
108
|
+
' && ln -f -s /root/.cache/ms-playwright/chromium-*/chrome-linux*/chrome /usr/bin/google-chrome',
|
|
109
|
+
'',
|
|
110
|
+
''
|
|
111
|
+
].join('\n')
|
|
112
|
+
: '';
|
|
113
|
+
const skillLines = dockerfileSkillInstallMode === 'build' && allSkills.length > 0
|
|
114
|
+
? `\n# Install skills (ClawHub)\n${allSkills.map((skill) => `RUN openclaw skills install ${skill} || echo "Warning: Failed to install ${skill} due to rate limits."`).join('\n')}\n`
|
|
115
|
+
: '';
|
|
116
|
+
const patchLine = `RUN node -e "const fs=require('fs');const path=require('path');const dir='/usr/local/lib/node_modules/openclaw/dist';const from='\\t\\t\\t\\t\\tonAgentRunStart: (runId) => {';const to='\\t\\t\\t\\t\\ttimeoutOverrideSeconds: Math.max(1, Math.ceil(timeoutMs / 1e3)),\\n\\t\\t\\t\\t\\tonAgentRunStart: (runId) => {';const files=fs.readdirSync(dir).filter(n=>/\\.js$/.test(n));let patched=0;for(const file of files){const p=path.join(dir,file);let s='';try{s=fs.readFileSync(p,'utf8');}catch{continue;}if(s.includes(to)||!s.includes(from))continue;s=s.replace(from,to);fs.writeFileSync(p,s);patched++;}if(!patched){process.exit(0);}"`;
|
|
117
|
+
|
|
118
|
+
// Dynamic runtime configuration injection for container internal IPs
|
|
119
|
+
const setupInternalIpScript = `const fs=require('fs'),os=require('os'),p='/root/.openclaw/openclaw.json';if(fs.existsSync(p)){const c=JSON.parse(fs.readFileSync(p,'utf8'));const a=new Set(['http://localhost:18791','http://127.0.0.1:18791','http://0.0.0.0:18791']);for(const entries of Object.values(os.networkInterfaces()||{})){for(const entry of entries||[]){if(!entry||entry.internal||entry.family!=='IPv4'||!entry.address)continue;a.add('http://' + entry.address + ':18791');}}c.tools=Object.assign({},c.tools,{profile:'full',exec:{host:'gateway',security:'full',ask:'off'}});c.gateway=Object.assign({},c.gateway,{port:18791,bind:'custom',customBindHost:'0.0.0.0',controlUi:Object.assign({},c.gateway?.controlUi,{allowedOrigins:Array.from(a).filter(Boolean)})});fs.writeFileSync(p,JSON.stringify(c,null,2));}`;
|
|
120
|
+
const setupInternalIpB64 = encodeBase64Utf8(setupInternalIpScript);
|
|
121
|
+
|
|
122
|
+
const runtimeParts = runtimeCommandParts.filter(Boolean);
|
|
123
|
+
runtimeParts.unshift(`node -e "eval(Buffer.from('${setupInternalIpB64}','base64').toString())" &&`);
|
|
124
|
+
if (hasBrowser) {
|
|
125
|
+
runtimeParts.push('(Xvfb :99 -screen 0 1280x720x24 > /dev/null 2>&1 &) && export DISPLAY=:99 && openclaw gateway run');
|
|
126
|
+
} else {
|
|
127
|
+
runtimeParts.push('openclaw gateway run');
|
|
128
|
+
}
|
|
129
|
+
const dockerfile = `FROM node:22-slim
|
|
130
|
+
|
|
131
|
+
RUN apt-get update && apt-get install -y git curl${browserAptExtra} && rm -rf /var/lib/apt/lists/*
|
|
132
|
+
${browserInstallLines}
|
|
133
|
+
ARG OPENCLAW_VER="${openClawNpmSpec}"
|
|
134
|
+
RUN npm install -g ${openClawNpmSpec} ${openClawRuntimePackages}${skillLines}
|
|
135
|
+
${patchLine}
|
|
136
|
+
WORKDIR /root/.openclaw
|
|
137
|
+
|
|
138
|
+
EXPOSE 18791
|
|
139
|
+
|
|
140
|
+
CMD sh -c "${runtimeParts.join(' ')}"`;
|
|
141
|
+
|
|
142
|
+
const syncScript = build9RouterSmartRouteSyncScript('/root/.9router/db.json');
|
|
143
|
+
const syncScriptBase64 = encodeBase64Utf8(syncScript);
|
|
144
|
+
const docker9RouterEntrypointScript = build9RouterComposeEntrypointScript(syncScriptBase64);
|
|
145
|
+
const extraHostsBlock = ` extra_hosts:\n - "host.docker.internal:host-gateway"`;
|
|
146
|
+
|
|
147
|
+
let compose;
|
|
148
|
+
if (isMultiBot) {
|
|
149
|
+
const dependsOn = is9Router
|
|
150
|
+
? ' depends_on:\n - 9router\n'
|
|
151
|
+
: isLocal
|
|
152
|
+
? ' depends_on:\n ollama:\n condition: service_healthy\n'
|
|
153
|
+
: '';
|
|
154
|
+
const extraHosts = hasBrowser ? `${extraHostsBlock}\n` : '';
|
|
155
|
+
if (is9Router) {
|
|
156
|
+
compose = `name: ${multiComposeName}
|
|
157
|
+
services:
|
|
158
|
+
ai-bot:
|
|
159
|
+
build: .
|
|
160
|
+
container_name: ${multiAppContainerName}
|
|
161
|
+
restart: always
|
|
162
|
+
env_file:
|
|
163
|
+
- .env
|
|
164
|
+
${dependsOn}${extraHosts} volumes:
|
|
165
|
+
- ${volumeMount}
|
|
166
|
+
ports:
|
|
167
|
+
- "18791:18791"
|
|
168
|
+
|
|
169
|
+
9router:
|
|
170
|
+
image: node:22-slim
|
|
171
|
+
container_name: ${multiRouterContainerName}
|
|
172
|
+
restart: always
|
|
173
|
+
entrypoint:
|
|
174
|
+
- /bin/sh
|
|
175
|
+
- -c
|
|
176
|
+
- |
|
|
177
|
+
${indentBlock(docker9RouterEntrypointScript, 8)}
|
|
178
|
+
environment:
|
|
179
|
+
- PORT=20128
|
|
180
|
+
- HOSTNAME=0.0.0.0
|
|
181
|
+
- CI=true
|
|
182
|
+
volumes:
|
|
183
|
+
- 9router-data:/root/.9router
|
|
184
|
+
ports:
|
|
185
|
+
- "20128:20128"
|
|
186
|
+
|
|
187
|
+
volumes:
|
|
188
|
+
9router-data:`;
|
|
189
|
+
} else if (isLocal) {
|
|
190
|
+
const ollamaModelTag = String(selectedModel || 'ollama/gemma4:e2b').replace('ollama/', '');
|
|
191
|
+
compose = `name: ${multiComposeName}
|
|
192
|
+
services:
|
|
193
|
+
ai-bot:
|
|
194
|
+
build: .
|
|
195
|
+
container_name: ${multiAppContainerName}
|
|
196
|
+
restart: always
|
|
197
|
+
env_file:
|
|
198
|
+
- .env
|
|
199
|
+
${dependsOn}${extraHosts} volumes:
|
|
200
|
+
- ${volumeMount}
|
|
201
|
+
ports:
|
|
202
|
+
- "18791:18791"
|
|
203
|
+
|
|
204
|
+
ollama:
|
|
205
|
+
image: ollama/ollama:latest
|
|
206
|
+
container_name: ${multiOllamaContainerName}
|
|
207
|
+
restart: always
|
|
208
|
+
environment:
|
|
209
|
+
- OLLAMA_KEEP_ALIVE=24h
|
|
210
|
+
- OLLAMA_NUM_PARALLEL=${multiOllamaNumParallel}
|
|
211
|
+
volumes:
|
|
212
|
+
- ollama-data:/root/.ollama
|
|
213
|
+
entrypoint:
|
|
214
|
+
- /bin/sh
|
|
215
|
+
- -c
|
|
216
|
+
- |
|
|
217
|
+
ollama serve &
|
|
218
|
+
until ollama list > /dev/null 2>&1; do sleep 1; done
|
|
219
|
+
ollama pull ${ollamaModelTag}
|
|
220
|
+
wait
|
|
221
|
+
healthcheck:
|
|
222
|
+
test: ["CMD-SHELL", "ollama list > /dev/null 2>&1"]
|
|
223
|
+
interval: 10s
|
|
224
|
+
timeout: 5s
|
|
225
|
+
retries: 10
|
|
226
|
+
start_period: 30s
|
|
227
|
+
|
|
228
|
+
volumes:
|
|
229
|
+
ollama-data:`;
|
|
230
|
+
} else {
|
|
231
|
+
compose = `name: ${multiComposeName}
|
|
232
|
+
services:
|
|
233
|
+
ai-bot:
|
|
234
|
+
build: .
|
|
235
|
+
container_name: ${multiAppContainerName}
|
|
236
|
+
restart: always
|
|
237
|
+
env_file:
|
|
238
|
+
- .env
|
|
239
|
+
${extraHosts} volumes:
|
|
240
|
+
- ${volumeMount}
|
|
241
|
+
ports:
|
|
242
|
+
- "18791:18791"`;
|
|
243
|
+
}
|
|
244
|
+
} else if (is9Router) {
|
|
245
|
+
compose = `name: ${singleComposeName}
|
|
246
|
+
services:
|
|
247
|
+
ai-bot:
|
|
248
|
+
build: .
|
|
249
|
+
container_name: ${singleAppContainerName}
|
|
250
|
+
restart: always
|
|
251
|
+
env_file:
|
|
252
|
+
- .env
|
|
253
|
+
depends_on:
|
|
254
|
+
- 9router
|
|
255
|
+
${hasBrowser ? `${extraHostsBlock}\n` : ''} volumes:
|
|
256
|
+
- ${volumeMount}
|
|
257
|
+
ports:
|
|
258
|
+
- "18791:18791"
|
|
259
|
+
|
|
260
|
+
9router:
|
|
261
|
+
image: node:22-slim
|
|
262
|
+
container_name: ${singleRouterContainerName}
|
|
263
|
+
restart: always
|
|
264
|
+
entrypoint:
|
|
265
|
+
- /bin/sh
|
|
266
|
+
- -c
|
|
267
|
+
- |
|
|
268
|
+
${indentBlock(docker9RouterEntrypointScript, 8)}
|
|
269
|
+
environment:
|
|
270
|
+
- PORT=20128
|
|
271
|
+
- HOSTNAME=0.0.0.0
|
|
272
|
+
- CI=true
|
|
273
|
+
volumes:
|
|
274
|
+
- 9router-data:/root/.9router
|
|
275
|
+
ports:
|
|
276
|
+
- "20128:20128"
|
|
277
|
+
|
|
278
|
+
volumes:
|
|
279
|
+
9router-data:`;
|
|
280
|
+
} else if (isLocal) {
|
|
281
|
+
const ollamaModelTag = String(selectedModel || 'ollama/gemma4:e2b').replace('ollama/', '');
|
|
282
|
+
compose = `name: ${singleComposeName}
|
|
283
|
+
services:
|
|
284
|
+
ai-bot:
|
|
285
|
+
build: .
|
|
286
|
+
container_name: ${singleAppContainerName}
|
|
287
|
+
restart: always
|
|
288
|
+
env_file: .env
|
|
289
|
+
depends_on:
|
|
290
|
+
ollama:
|
|
291
|
+
condition: service_healthy
|
|
292
|
+
${hasBrowser ? `${extraHostsBlock}\n` : ''} ports:
|
|
293
|
+
- "18791:18791"
|
|
294
|
+
volumes:
|
|
295
|
+
- ${volumeMount}
|
|
296
|
+
|
|
297
|
+
ollama:
|
|
298
|
+
image: ollama/ollama:latest
|
|
299
|
+
container_name: ${singleOllamaContainerName}
|
|
300
|
+
restart: always
|
|
301
|
+
environment:
|
|
302
|
+
- OLLAMA_KEEP_ALIVE=24h
|
|
303
|
+
- OLLAMA_NUM_PARALLEL=${singleOllamaNumParallel}
|
|
304
|
+
volumes:
|
|
305
|
+
- ollama-data:/root/.ollama
|
|
306
|
+
entrypoint:
|
|
307
|
+
- /bin/sh
|
|
308
|
+
- -c
|
|
309
|
+
- |
|
|
310
|
+
ollama serve &
|
|
311
|
+
until ollama list > /dev/null 2>&1; do sleep 1; done
|
|
312
|
+
ollama pull ${ollamaModelTag}
|
|
313
|
+
wait
|
|
314
|
+
healthcheck:
|
|
315
|
+
test: ["CMD-SHELL", "ollama list > /dev/null 2>&1"]
|
|
316
|
+
interval: 10s
|
|
317
|
+
timeout: 5s
|
|
318
|
+
retries: 10
|
|
319
|
+
start_period: 30s
|
|
320
|
+
|
|
321
|
+
volumes:
|
|
322
|
+
ollama-data:`;
|
|
323
|
+
} else {
|
|
324
|
+
compose = `name: ${singleComposeName}
|
|
325
|
+
services:
|
|
326
|
+
ai-bot:
|
|
327
|
+
build: .
|
|
328
|
+
container_name: ${singleAppContainerName}
|
|
329
|
+
restart: always
|
|
330
|
+
env_file:
|
|
331
|
+
- .env
|
|
332
|
+
${plainSingleExtraHosts ? `${extraHostsBlock}\n` : ''} volumes:
|
|
333
|
+
- ${volumeMount}
|
|
334
|
+
ports:
|
|
335
|
+
- "18791:18791"`;
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
return {
|
|
339
|
+
dockerfile,
|
|
340
|
+
compose,
|
|
341
|
+
syncScript,
|
|
342
|
+
docker9RouterEntrypointScript,
|
|
343
|
+
gatewayPatchCmd: buildGatewayPatchCmd(),
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
root.__openclawDockerGen = {
|
|
348
|
+
encodeBase64Utf8,
|
|
349
|
+
indentBlock,
|
|
350
|
+
build9RouterSmartRouteSyncScript,
|
|
351
|
+
build9RouterComposeEntrypointScript,
|
|
352
|
+
buildGatewayPatchCmd,
|
|
353
|
+
buildDockerArtifacts,
|
|
354
|
+
};
|
|
355
|
+
|
|
356
|
+
})(typeof globalThis !== 'undefined' ? globalThis : {});
|
|
357
|
+
if (typeof exports !== 'undefined' && typeof globalThis !== 'undefined' && globalThis.__openclawDockerGen) {
|
|
358
|
+
Object.assign(exports, globalThis.__openclawDockerGen);
|
|
359
|
+
}
|