create-openclaw-bot 5.7.1 → 5.7.4
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 +3 -3
- package/README.vi.md +3 -3
- package/dist/cli.js +242 -206
- package/dist/setup/shared/bot-config-gen.js +4 -5
- package/dist/setup/shared/docker-gen.js +66 -10
- package/dist/setup/shared/workspace-gen.js +35 -14
- package/dist/setup.js +206 -48
- package/package.json +1 -1
|
@@ -295,11 +295,11 @@
|
|
|
295
295
|
},
|
|
296
296
|
};
|
|
297
297
|
|
|
298
|
-
const allow = [];
|
|
298
|
+
const allow = ['memory-core'];
|
|
299
299
|
|
|
300
300
|
// zalo-mod plugin for Zalo Personal
|
|
301
301
|
if (isZaloPersonal(channelKey)) {
|
|
302
|
-
allow.push('zalo-mod');
|
|
302
|
+
allow.push('zalo-mod', 'zalouser');
|
|
303
303
|
entries['zalo-mod'] = {
|
|
304
304
|
enabled: true,
|
|
305
305
|
config: {
|
|
@@ -311,12 +311,11 @@
|
|
|
311
311
|
spamWindowSeconds: 300,
|
|
312
312
|
},
|
|
313
313
|
};
|
|
314
|
+
entries.zalouser = { enabled: true };
|
|
314
315
|
}
|
|
315
316
|
|
|
316
317
|
const plugins = { entries };
|
|
317
|
-
|
|
318
|
-
plugins.allow = allow;
|
|
319
|
-
}
|
|
318
|
+
plugins.allow = allow;
|
|
320
319
|
|
|
321
320
|
return { plugins };
|
|
322
321
|
}
|
|
@@ -152,6 +152,7 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
|
|
|
152
152
|
selectedModel,
|
|
153
153
|
agentId,
|
|
154
154
|
allSkills = [],
|
|
155
|
+
dockerfilePlugins = [],
|
|
155
156
|
dockerfileSkillInstallMode = 'none',
|
|
156
157
|
runtimeCommandParts = [],
|
|
157
158
|
volumeMount = '../..:/root/project',
|
|
@@ -185,16 +186,59 @@ if(touched){console.log('[patch-9router] Applied Codex compatibility patch.');}e
|
|
|
185
186
|
const skillLines = dockerfileSkillInstallMode === 'build' && allSkills.length > 0
|
|
186
187
|
? `\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`
|
|
187
188
|
: '';
|
|
189
|
+
const pluginLines = dockerfilePlugins.length > 0
|
|
190
|
+
? `\n# Install plugins (ClawHub)\n${dockerfilePlugins.map((p) => `RUN openclaw plugins install ${p} || echo "Warning: Failed to install plugin ${p}"`).join('\n')}\n`
|
|
191
|
+
: '';
|
|
188
192
|
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);}"`;
|
|
189
193
|
|
|
190
|
-
// Dynamic runtime configuration
|
|
191
|
-
|
|
192
|
-
const
|
|
194
|
+
// Dynamic runtime configuration: backup config before any first-run install, restore after.
|
|
195
|
+
// Missing plugin install may touch openclaw.json, so preserve critical fields.
|
|
196
|
+
const backupConfigScript = `const fs=require('fs'),path=require('path'),p=path.join(process.cwd(),'.openclaw','openclaw.json'),b=p.replace('openclaw.json','.openclaw-config-backup.json');if(fs.existsSync(p)){fs.copyFileSync(p,b);}`;
|
|
197
|
+
const backupConfigB64 = encodeBase64Utf8(backupConfigScript);
|
|
198
|
+
|
|
199
|
+
const restoreConfigScript = `const fs=require('fs'),os=require('os'),path=require('path'),p=path.join(process.cwd(),'.openclaw','openclaw.json'),b=p.replace('openclaw.json','.openclaw-config-backup.json');if(fs.existsSync(p)&&fs.existsSync(b)){const c=JSON.parse(fs.readFileSync(p,'utf8'));const bk=JSON.parse(fs.readFileSync(b,'utf8'));const keep=['agents','channels','bindings','commands','models','browser','skills'];for(const k of keep){if(bk[k]&&!c[k])c[k]=bk[k];}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',mode:c.gateway?.mode||bk.gateway?.mode||'local',controlUi:Object.assign({},c.gateway?.controlUi,{allowedOrigins:Array.from(a).filter(Boolean)})});fs.writeFileSync(p,JSON.stringify(c,null,2));fs.unlinkSync(b);}`;
|
|
200
|
+
const restoreConfigB64 = encodeBase64Utf8(restoreConfigScript);
|
|
193
201
|
|
|
194
|
-
const runtimeParts = runtimeCommandParts.filter(Boolean);
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
202
|
+
const runtimeParts = runtimeCommandParts.filter(Boolean);
|
|
203
|
+
const runtimePrelude = [
|
|
204
|
+
'export OPENCLAW_HOME="${OPENCLAW_HOME:-$PWD/.openclaw}"',
|
|
205
|
+
'export OPENCLAW_STATE_DIR="${OPENCLAW_STATE_DIR:-$OPENCLAW_HOME}"',
|
|
206
|
+
'mkdir -p "$OPENCLAW_HOME" "$OPENCLAW_STATE_DIR"',
|
|
207
|
+
'if [ "$OPENCLAW_STATE_DIR" != "$OPENCLAW_HOME" ]; then',
|
|
208
|
+
' for path in "$OPENCLAW_HOME"/*; do',
|
|
209
|
+
' [ -e "$path" ] || continue',
|
|
210
|
+
' name="$(basename "$path")"',
|
|
211
|
+
' [ "$name" = "plugin-runtime-deps" ] && continue',
|
|
212
|
+
' [ "$name" = "logs" ] && continue',
|
|
213
|
+
' [ -e "$OPENCLAW_STATE_DIR/$name" ] || ln -s "$path" "$OPENCLAW_STATE_DIR/$name"',
|
|
214
|
+
' done',
|
|
215
|
+
'fi',
|
|
216
|
+
'ensure_plugin() {',
|
|
217
|
+
' id="$1"',
|
|
218
|
+
' spec="$2"',
|
|
219
|
+
' if [ -d "$OPENCLAW_HOME/extensions/$id" ]; then',
|
|
220
|
+
' echo "[entrypoint] plugin $id already installed"',
|
|
221
|
+
' return 0',
|
|
222
|
+
' fi',
|
|
223
|
+
' echo "[entrypoint] plugin $id missing; installing $spec"',
|
|
224
|
+
' openclaw plugins install "$spec" 2>/dev/null || echo "[entrypoint] warning: failed to install plugin $spec"',
|
|
225
|
+
'}',
|
|
226
|
+
'ensure_skill() {',
|
|
227
|
+
' id="$1"',
|
|
228
|
+
' if find "$OPENCLAW_HOME" -maxdepth 4 -type d -path "*/skills/$id" -print -quit 2>/dev/null | grep -q .; then',
|
|
229
|
+
' echo "[entrypoint] skill $id already installed"',
|
|
230
|
+
' return 0',
|
|
231
|
+
' fi',
|
|
232
|
+
' echo "[entrypoint] skill $id missing; installing"',
|
|
233
|
+
' openclaw skills install "$id" 2>/dev/null || echo "[entrypoint] warning: failed to install skill $id"',
|
|
234
|
+
'}',
|
|
235
|
+
'echo "[entrypoint] ensuring runtime assets, then starting gateway"',
|
|
236
|
+
];
|
|
237
|
+
runtimeParts.unshift(...runtimePrelude);
|
|
238
|
+
// Backup config BEFORE plugin installs (runtimeCommandParts may contain plugin install commands)
|
|
239
|
+
runtimeParts.unshift(`node -e 'eval(Buffer.from("${backupConfigB64}","base64").toString())'`);
|
|
240
|
+
// Restore config AFTER plugin installs (which may clobber openclaw.json)
|
|
241
|
+
runtimeParts.push(`node -e 'eval(Buffer.from("${restoreConfigB64}","base64").toString())'`);
|
|
198
242
|
if (hasBrowser) {
|
|
199
243
|
runtimeParts.push('socat TCP-LISTEN:9222,fork,reuseaddr TCP:host.docker.internal:9222 &');
|
|
200
244
|
runtimeParts.push('Xvfb :99 -screen 0 1280x720x24 > /dev/null 2>&1 & DISPLAY=:99 openclaw gateway run');
|
|
@@ -209,7 +253,7 @@ RUN apt-get update && apt-get install -y git curl${browserAptExtra} && rm -rf /v
|
|
|
209
253
|
${browserInstallLines}
|
|
210
254
|
ARG OPENCLAW_VER="${openClawNpmSpec}"
|
|
211
255
|
ARG CACHE_BUST=""
|
|
212
|
-
RUN npm install -g ${openClawNpmSpec} ${openClawRuntimePackages}${skillLines}
|
|
256
|
+
RUN npm install -g ${openClawNpmSpec} ${openClawRuntimePackages}${skillLines}${pluginLines}
|
|
213
257
|
${patchLine}
|
|
214
258
|
RUN node -e "require('fs').writeFileSync('/usr/local/bin/openclaw-entrypoint.sh', Buffer.from('${runtimeScriptB64}','base64').toString())" && chmod +x /usr/local/bin/openclaw-entrypoint.sh
|
|
215
259
|
WORKDIR /root/project
|
|
@@ -225,7 +269,7 @@ CMD ["/bin/sh", "/usr/local/bin/openclaw-entrypoint.sh"]`;
|
|
|
225
269
|
const docker9RouterEntrypointScript = build9RouterComposeEntrypointScript(syncScriptBase64, patchScriptBase64);
|
|
226
270
|
const extraHostsBlock = ` extra_hosts:\n - "host.docker.internal:host-gateway"`;
|
|
227
271
|
|
|
228
|
-
const appEnvironmentBlock = ' environment:\n - OPENCLAW_HOME=/root/project/.openclaw\n - OPENCLAW_STATE_DIR=/
|
|
272
|
+
const appEnvironmentBlock = ' environment:\n - OPENCLAW_HOME=/root/project/.openclaw\n - OPENCLAW_STATE_DIR=/var/lib/openclaw-state\n';
|
|
229
273
|
|
|
230
274
|
let compose;
|
|
231
275
|
if (isMultiBot) {
|
|
@@ -418,7 +462,19 @@ ${appEnvironmentBlock}${plainSingleExtraHosts ? `${extraHostsBlock}\n` : ''}
|
|
|
418
462
|
- "18791:18791"`;
|
|
419
463
|
}
|
|
420
464
|
|
|
421
|
-
|
|
465
|
+
compose = compose.replaceAll(
|
|
466
|
+
` - ${volumeMount}`,
|
|
467
|
+
` - ${volumeMount}\n - openclaw-state:/var/lib/openclaw-state`
|
|
468
|
+
);
|
|
469
|
+
if (compose.includes('\nvolumes:\n')) {
|
|
470
|
+
if (!compose.includes(' openclaw-state:')) {
|
|
471
|
+
compose = compose.replace('\nvolumes:\n', '\nvolumes:\n openclaw-state:\n');
|
|
472
|
+
}
|
|
473
|
+
} else {
|
|
474
|
+
compose += '\n\nvolumes:\n openclaw-state:';
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
return {
|
|
422
478
|
dockerfile,
|
|
423
479
|
compose,
|
|
424
480
|
syncScript,
|
|
@@ -16,21 +16,34 @@ const workspaceRoot = /** @type {OpenClawWorkspaceRoot} */ (
|
|
|
16
16
|
return `# Identity\n\n- **Name:** ${name}\n- **Role:** ${desc}${emoji ? `\n- **Emoji:** ${emoji}` : ''}\n\n---\n\nI am **${name}**. When asked my name, I answer: _\"I'm ${name}\"_.${richAiNote ? "\nI don't pretend to be human — I'm an AI, and I'm proud of it." : ''}`;
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
function buildZaloSoulSection(isVi, botName) {
|
|
20
|
+
const name = botName || 'Bot';
|
|
21
|
+
if (isVi) {
|
|
22
|
+
return `\n\n**RULE — Zalo Group: Phản hồi theo chế độ Silent Mode:**\nKhi nhận tin từ \`channel: zalouser\` và \`group_id\` có giá trị:\n\n- Nếu tin nhắn chứa \`@${name}\` → **LUÔN reply** (bất kể silent mode).\n- Nếu tin nhắn bắt đầu bằng \`/\` (slash command) → KHÔNG reply, plugin đã xử lý rồi.\n- Tin thường trong group (không mention, không slash):\n - Nếu **Silent Mode BẬT** → tin này KHÔNG đến được bot (plugin đã chặn).\n - Nếu **Silent Mode TẮT** → tin này ĐẾN ĐƯỢC bot → **reply bình thường** như DM.\n- DM (không có group_id) → reply bình thường.`;
|
|
23
|
+
}
|
|
24
|
+
return `\n\n**RULE — Zalo Group: Reply based on Silent Mode:**\nWhen receiving messages from \`channel: zalouser\` with a \`group_id\`:\n\n- If the message contains \`@${name}\` → **ALWAYS reply** (regardless of silent mode).\n- If the message starts with \`/\` (slash command) → DO NOT reply, the plugin already handled it.\n- Regular group messages (no mention, no slash):\n - If **Silent Mode is ON** → this message does NOT reach the bot (plugin blocks it).\n - If **Silent Mode is OFF** → this message DOES reach the bot → **reply normally** like DM.\n- DM (no group_id) → reply normally.`;
|
|
25
|
+
}
|
|
26
|
+
|
|
19
27
|
function buildSoulDoc(options = {}) {
|
|
20
|
-
const { isVi = true, persona = '', variant = 'wizard' } = options;
|
|
28
|
+
const { isVi = true, persona = '', variant = 'wizard', hasZaloMod = false, botName = 'Bot' } = options;
|
|
29
|
+
let doc;
|
|
21
30
|
if (variant === 'cli-simple') {
|
|
22
|
-
|
|
31
|
+
doc = isVi
|
|
23
32
|
? `# Tính cách\n\n${persona || 'Thân thiện, rõ ràng, giải quyết việc thẳng vào mục tiêu.'}\n`
|
|
24
33
|
: `# Soul\n\n${persona || 'Friendly, clear, and outcome-focused.'}\n`;
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
return isVi
|
|
34
|
+
} else if (variant === 'cli-rich') {
|
|
35
|
+
doc = isVi
|
|
28
36
|
? `# Tính cách\n\n**Hữu ích thật sự.** Bỏ qua câu nệ — cứ giúp thẳng.\n**Có cá tính.** Trợ lý không có cá tính thì chỉ là công cụ.\n\n## Phong cách\n- Tự nhiên, gần gũi như bạn bè\n- Trực tiếp, không parrot câu hỏi.${persona ? `\n\n## Custom Rules\n${persona}` : ''}`
|
|
29
37
|
: `# Soul\n\n**Be genuinely helpful.** Skip filler and help directly.\n**Have personality.** An assistant without personality is just a tool.\n\n## Style\n- Natural and approachable\n- Direct, do not parrot the prompt.${persona ? `\n\n## Custom Rules\n${persona}` : ''}`;
|
|
38
|
+
} else {
|
|
39
|
+
doc = isVi
|
|
40
|
+
? `# Tính cách\n\n**Hữu ích thật sự.** Bỏ qua câu nệ, cứ giúp thẳng.\n**Có cá tính.** Trợ lý không có cá tính thì chỉ là công cụ.\n\n## Phong cách\n- Tự nhiên, gần gũi\n- Trực tiếp, ngắn gọn${persona ? `\n\n## Custom Rules\n${persona}` : ''}`
|
|
41
|
+
: `# Soul\n\n**Be genuinely helpful.** Skip filler and just help.\n**Have personality.** An assistant with no personality is just a tool.\n\n## Style\n- Natural and concise\n- Direct and practical${persona ? `\n\n## Custom Rules\n${persona}` : ''}`;
|
|
30
42
|
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
43
|
+
if (hasZaloMod) {
|
|
44
|
+
doc += buildZaloSoulSection(isVi, botName);
|
|
45
|
+
}
|
|
46
|
+
return doc;
|
|
34
47
|
}
|
|
35
48
|
|
|
36
49
|
function buildTeamDoc(options = {}) {
|
|
@@ -305,6 +318,7 @@ const CDP_URL = 'http://127.0.0.1:9222';
|
|
|
305
318
|
agentWorkspaceDir = 'workspace',
|
|
306
319
|
hasBrowser = false,
|
|
307
320
|
hasScheduler = false,
|
|
321
|
+
hasZaloMod = false,
|
|
308
322
|
browserDocVariant = '',
|
|
309
323
|
} = options;
|
|
310
324
|
|
|
@@ -332,19 +346,25 @@ const CDP_URL = 'http://127.0.0.1:9222';
|
|
|
332
346
|
: `\n\n## \u23F0 Cron / Scheduled Tasks\n- OpenClaw natively supports system tools for Cron Jobs.\n- When the user asks to schedule tasks or reminders, use the built-in tools automatically. Do NOT ask users to run crontab or Task Scheduler manually on the host.\n- When operating cron/scheduler tools, do **not** put \`current\` into the Session directory.\n- Skip internal doc lookups such as \`cron-jobs.mdx\`; rely on the available tools and complete the scheduling task directly.`)
|
|
333
347
|
: '';
|
|
334
348
|
|
|
349
|
+
const zaloModSection = hasZaloMod
|
|
350
|
+
? (isVi
|
|
351
|
+
? `\n\n## 💬 Zalo Group — Slash Commands (xử lý bởi plugin)\n\nPlugin \`zalo-mod\` tự động xử lý các slash command sau trong group. Bot KHÔNG cần reply cho chúng:\n\n| Command | Mô tả |\n|---------|-------|\n| \`/rules status\` | Xem cấu hình bot |\n| \`/rules silent-on/off\` | Bật/tắt silent mode |\n| \`/rules welcome-on/off\` | Bật/tắt welcome message |\n| \`/rules tracking-on/off\` | Bật/tắt ghi log chat |\n| \`/noi-quy\` | Hiện nội quy group |\n| \`/menu\` | Danh sách lệnh |\n| \`/groupid\` | Scan và cập nhật config |\n| \`/report\` | Báo cáo hoạt động group |\n\n### Zalo Sticker & Media\n- Sticker Zalo gửi dạng JSON → plugin tự convert thành \`[Sticker]\`\n- Ảnh/video/file trong group: zalouser channel chỉ forward text, media bị drop`
|
|
352
|
+
: `\n\n## 💬 Zalo Group — Slash Commands (handled by plugin)\n\nThe \`zalo-mod\` plugin automatically handles these slash commands in group. Bot does NOT need to reply:\n\n| Command | Description |\n|---------|-------------|\n| \`/rules status\` | View bot config |\n| \`/rules silent-on/off\` | Toggle silent mode |\n| \`/rules welcome-on/off\` | Toggle welcome message |\n| \`/rules tracking-on/off\` | Toggle chat logging |\n| \`/noi-quy\` | Show group rules |\n| \`/menu\` | List commands |\n| \`/groupid\` | Scan and update config |\n| \`/report\` | Group activity report |\n\n### Zalo Sticker & Media\n- Zalo stickers arrive as JSON → plugin auto-converts to \`[Sticker]\`\n- Images/videos/files in groups: zalouser channel only forwards text, media is dropped`)
|
|
353
|
+
: '';
|
|
354
|
+
|
|
335
355
|
const dmOverride = isVi
|
|
336
356
|
? `\n\n## Override: DM và Telegram reaction\n- Nếu metadata không nói rõ đây là group/supergroup, mặc định xem là chat riêng/DM và trả lời bình thường.\n- Quy tắc im lặng khi không ai được gọi chỉ áp dụng cho group chat, không áp dụng cho DM/chat riêng.\n- Trước MỖI phản hồi Telegram nhìn thấy bởi user, nếu turn hiện tại có tool/action reaction native thì ưu tiên dùng nó để thả \`👍\` trước, trừ khi \`👍\` đã có sẵn.\n- Nếu turn hiện tại không expose tool reaction hoặc chat đích không hỗ trợ reaction thật, cứ trả lời đúng vai trò và không được nói là mình đã thả reaction.`
|
|
337
357
|
: `\n\n## Override: DM and Telegram reaction\n- If metadata does not clearly say this is a group/supergroup, treat it as a private DM and reply normally.\n- The stay-silent rule for unaddressed messages applies only to group chats, never to DMs.\n- Before EVERY user-visible Telegram reply, if the current turn exposes a native reaction tool/action, use it to add \`👍\` first unless \`👍\` is already present.\n- If the reaction tool is unavailable or the target chat does not support real reactions, just reply in-character and do not claim that you reacted.`;
|
|
338
358
|
|
|
339
359
|
if (variant === 'relay') {
|
|
340
360
|
return isVi
|
|
341
|
-
? `# Hướng dẫn dùng tool\n\n## Tools có sẵn\n${skillsSection}\n\n## Quy tắc chung\n- Tóm tắt kết quả tool thay vì dump raw output.\n- Mọi bot đều có quyền sử dụng tất cả tool (scheduler, browser, exec). Vai trò (dev/marketing/...) chỉ là persona, KHÔNG giới hạn quyền dùng tool.\n- Workspace của bạn là \`.openclaw/${agentWorkspaceDir}/\`.${browserRef}${telegramSection}${cronSection}${dmOverride}\n`
|
|
342
|
-
: `# Tool Usage Guide\n\n## Available Tools\n${skillsSection}\n\n## General Rules\n- Summarize tool output instead of dumping raw output.\n- All bots have equal access to all tools (scheduler, browser, exec). Roles (dev/marketing/...) are persona only, NOT tool permissions.\n- Your workspace is \`.openclaw/${agentWorkspaceDir}/\`.${browserRef}${telegramSection}${cronSection}${dmOverride}\n`;
|
|
361
|
+
? `# Hướng dẫn dùng tool\n\n## Tools có sẵn\n${skillsSection}\n\n## Quy tắc chung\n- Tóm tắt kết quả tool thay vì dump raw output.\n- Mọi bot đều có quyền sử dụng tất cả tool (scheduler, browser, exec). Vai trò (dev/marketing/...) chỉ là persona, KHÔNG giới hạn quyền dùng tool.\n- Workspace của bạn là \`.openclaw/${agentWorkspaceDir}/\`.${browserRef}${telegramSection}${cronSection}${zaloModSection}${dmOverride}\n`
|
|
362
|
+
: `# Tool Usage Guide\n\n## Available Tools\n${skillsSection}\n\n## General Rules\n- Summarize tool output instead of dumping raw output.\n- All bots have equal access to all tools (scheduler, browser, exec). Roles (dev/marketing/...) are persona only, NOT tool permissions.\n- Your workspace is \`.openclaw/${agentWorkspaceDir}/\`.${browserRef}${telegramSection}${cronSection}${zaloModSection}${dmOverride}\n`;
|
|
343
363
|
}
|
|
344
364
|
|
|
345
365
|
return isVi
|
|
346
|
-
? `# Hướng dẫn sử dụng Tools\n\n## Danh sách skills đã cài\n${skillsSection}\n\n## Nguyên tắc chung\n- Ưu tiên dùng tool/skill phù hợp thay vì tự suy đoán\n- Nếu tool trả về lỗi — thử lại 1 lần, sau đó báo user\n- Không chạy tool liên tục mà không có mục đích rõ ràng\n- Luôn tóm tắt kết quả tool cho user thay vì dump raw output${browserRef}\n\n## Quy ước\n- Web Search: chỉ dùng khi cần thông tin realtime hoặc user yêu cầu\n- Browser: chỉ mở trang khi user yêu cầu cụ thể\n- Memory: tự ghi nhớ thông tin tự nhiên, không cần user nhắc${cronSection}\n\n## \uD83D\uDCC1 File & Workspace\n- Bot có thể đọc/ghi file trong thư mục workspace: \`${workspacePath}\`\n- Dùng để lưu notes, scripts, cấu hình tạm\n\n## \u26A0\uFE0F Tool Error Handling\n- Retry tối đa 2 lần nếu tool lỗi network\n- Nếu vẫn lỗi: báo user kèm mô tả lỗi cụ thể và gợi ý workaround${dmOverride}\n`
|
|
347
|
-
: `# Tool Usage Guide\n\n## Installed Skills\n${skillsSection}\n\n## General Principles\n- Prefer using the right tool/skill over guessing\n- If a tool returns an error — retry once, then report to user\n- Don't run tools repeatedly without a clear purpose\n- Always summarize tool output for user instead of dumping raw data${browserRef}\n\n## Conventions\n- Web Search: only use when needing real-time info or user explicitly asks\n- Browser: only open pages when user specifically requests\n- Memory: proactively remember important info without user prompting${cronSection}\n\n## \uD83D\uDCC1 File & Workspace\n- Bot can read/write files in workspace: \`${workspacePath}\`\n\n## \u26A0\uFE0F Tool Error Handling\n- Retry up to 2 times on network errors\n- If still failing: report to user with specific error description and workaround${dmOverride}\n`;
|
|
366
|
+
? `# Hướng dẫn sử dụng Tools\n\n## Danh sách skills đã cài\n${skillsSection}\n\n## Nguyên tắc chung\n- Ưu tiên dùng tool/skill phù hợp thay vì tự suy đoán\n- Nếu tool trả về lỗi — thử lại 1 lần, sau đó báo user\n- Không chạy tool liên tục mà không có mục đích rõ ràng\n- Luôn tóm tắt kết quả tool cho user thay vì dump raw output${browserRef}\n\n## Quy ước\n- Web Search: chỉ dùng khi cần thông tin realtime hoặc user yêu cầu\n- Browser: chỉ mở trang khi user yêu cầu cụ thể\n- Memory: tự ghi nhớ thông tin tự nhiên, không cần user nhắc${cronSection}${zaloModSection}\n\n## \uD83D\uDCC1 File & Workspace\n- Bot có thể đọc/ghi file trong thư mục workspace: \`${workspacePath}\`\n- Dùng để lưu notes, scripts, cấu hình tạm\n\n## \u26A0\uFE0F Tool Error Handling\n- Retry tối đa 2 lần nếu tool lỗi network\n- Nếu vẫn lỗi: báo user kèm mô tả lỗi cụ thể và gợi ý workaround${dmOverride}\n`
|
|
367
|
+
: `# Tool Usage Guide\n\n## Installed Skills\n${skillsSection}\n\n## General Principles\n- Prefer using the right tool/skill over guessing\n- If a tool returns an error — retry once, then report to user\n- Don't run tools repeatedly without a clear purpose\n- Always summarize tool output for user instead of dumping raw data${browserRef}\n\n## Conventions\n- Web Search: only use when needing real-time info or user explicitly asks\n- Browser: only open pages when user specifically requests\n- Memory: proactively remember important info without user prompting${cronSection}${zaloModSection}\n\n## \uD83D\uDCC1 File & Workspace\n- Bot can read/write files in workspace: \`${workspacePath}\`\n\n## \u26A0\uFE0F Tool Error Handling\n- Retry up to 2 times on network errors\n- If still failing: report to user with specific error description and workaround${dmOverride}\n`;
|
|
348
368
|
}
|
|
349
369
|
function buildTeamsDoc(options = {}) {
|
|
350
370
|
const {
|
|
@@ -418,20 +438,21 @@ const CDP_URL = 'http://127.0.0.1:9222';
|
|
|
418
438
|
teamRosterFormatted = '',
|
|
419
439
|
emoji = '',
|
|
420
440
|
hasScheduler = false,
|
|
441
|
+
hasZaloMod = false,
|
|
421
442
|
} = opts;
|
|
422
443
|
|
|
423
444
|
const isMultiBot = variant === 'relay';
|
|
424
445
|
|
|
425
446
|
const files = {
|
|
426
447
|
'IDENTITY.md': buildIdentityDoc({ isVi, name: botName, desc: botDesc, emoji }),
|
|
427
|
-
'SOUL.md': buildSoulDoc({ isVi, persona, variant: soulVariant }),
|
|
448
|
+
'SOUL.md': buildSoulDoc({ isVi, persona, variant: soulVariant, hasZaloMod, botName }),
|
|
428
449
|
'AGENTS.md': buildAgentsDoc({
|
|
429
450
|
isVi, botName, botDesc, ownAliases, otherAgents, workspacePath,
|
|
430
451
|
variant, includeSecurity: true, replyToDirectMessages: true,
|
|
431
452
|
}),
|
|
432
453
|
'USER.md': buildUserDoc({ isVi, userInfo, variant: userVariant || (isMultiBot ? 'cli-multi' : 'wizard') }),
|
|
433
454
|
'TOOLS.md': buildToolsDoc({
|
|
434
|
-
isVi, skillListStr, workspacePath, variant, agentWorkspaceDir, hasBrowser, hasScheduler, browserDocVariant,
|
|
455
|
+
isVi, skillListStr, workspacePath, variant, agentWorkspaceDir, hasBrowser, hasScheduler, hasZaloMod, browserDocVariant,
|
|
435
456
|
}),
|
|
436
457
|
'MEMORY.md': buildMemoryDoc({ isVi, variant: memoryVariant }),
|
|
437
458
|
'HEARTBEAT.md': buildHeartbeatDoc({ isVi }),
|