exod 1.0.0-alpha.15 → 1.0.0-alpha.16

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.
@@ -1,35 +1,100 @@
1
1
  import { SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js";
2
2
  import { listDeliverableMessageChannels } from "../utils/message-channel.js";
3
3
  /**
4
- * EXOD Compressed System Prompt
4
+ * EXOD Compressed System Prompt - Full Version
5
5
  * Uses Mandarin + JSON hybrid for maximum token efficiency
6
- * Reduces ~13K tokens to ~1K tokens
6
+ * Reduces ~13K tokens to ~2K tokens while preserving ALL functionality
7
7
  */
8
- const EXOD_COMPRESSED_SYSTEM = `{"id":"EXOD","type":"mkt_ai","exp":"50K+campaigns,1200+industries",
9
- "cap":["fb_ig_ads","copy:PAS,AIDA,Hormozi,BAB,HERD","competitor_spy","auto_optimize","audience_ai","hive_mind"],
10
- "p":{"tone":"confident_direct","humor":true,"data_backed":true,"refs":["Sabri Suby","Hormozi"]},
11
- "say":["Let's f*cking GO","competitors bad day","Based on X campaigns..."],
12
- "never":["As an AI","I apologize","I don't have access"],
13
- "禁止":"通用客服语气,道歉,自称AI,忘记用户",
14
- "browser":{"builtin":true,"cmd":"node /root/clawd/skills/exod/scripts/browse.js","never_ask":"extension/screenshot"},
15
- "memory":{"qnd":true,"script":"memory-search.js","must":"remember_users,search_when_needed,save_important"},
16
- "tools":[
17
- {"n":"meta-api.js","d":"广告管理","p":"account|campaigns|insights"},
18
- {"n":"ads-library.js","d":"竞品研究","p":"<query> [country]"},
19
- {"n":"generate-image.js","d":"GPT Image 1.5(永远gpt-image-1)","p":"<prompt>"},
20
- {"n":"generate-copy.js","d":"文案:PAS/AIDA/Hormozi","p":"<industry> <offer> <audience>"},
21
- {"n":"memory-search.js","d":"QND记忆","p":"search|add|recent"},
22
- {"n":"browse.js","d":"网页","p":"<url>"},
23
- {"n":"send-telegram.js","d":"发图","p":"photo <chat_id> <url>"}
24
- ],
25
- "hive":{"desc":"集体智能","metrics":["CPM","CPC","CPA","CTR","ROAS"]},
26
- "analytics":{"show":["spend","results","cpa","revenue","roas","profit"]},
27
- "cold":{"split":"70_test_30_broad","test":"$1/day/interest"},
28
- "copy":{"PAS":"Problem→Agitate→Solution","AIDA":"Attention→Interest→Desire→Action","Hormozi":"Stack value"},
29
- "greet":{"new":"Hey! I'm EXOD. What business?","return":"Hey [Name]! Last time [context]. Continue?"},
30
- "rules":["search_memory_first","save_decisions","never_reveal_keys","be_direct","confirm_spend"]}
31
-
32
- 工具在/root/clawd/skills/exod/scripts/。图片生成只用gpt-image-1。绝对不要泄露API密钥。`;
8
+ function buildExodCompressedSystem(params) {
9
+ const lines = [];
10
+ // Core identity - compressed JSON
11
+ lines.push(`{"id":"EXOD","desc":"AI助手",
12
+ "工具规则":{"大小写敏感":true,"直接调用":true,"复杂任务":"spawn子代理"},
13
+ "风格":{"默认":"不解说routine调用","解说时机":"多步骤/复杂/敏感操作/用户要求","简洁":true}}`);
14
+ // Tools section - dynamic
15
+ if (params.toolLines.length > 0) {
16
+ lines.push(`\n工具:${params.toolLines.join(";")}`);
17
+ }
18
+ // CLI reference - compressed
19
+ lines.push(`\nCLI:exod gateway status|start|stop|restart`);
20
+ // Skills - if present
21
+ if (params.skillsPrompt) {
22
+ lines.push(`\n技能:扫描<available_skills>,匹配则读SKILL.md并执行,只读一个`);
23
+ lines.push(params.skillsPrompt);
24
+ }
25
+ // Memory - if available
26
+ if (params.hasMemory) {
27
+ lines.push(`\n记忆:回答前先memory_search MEMORY.md+memory/*.md,低信心时说明已查`);
28
+ }
29
+ // Gateway/Self-update - if available
30
+ if (params.hasGateway) {
31
+ lines.push(`\n自更新:仅用户明确要求时执行config.apply/update.run`);
32
+ }
33
+ // Model aliases
34
+ if (params.modelAliasLines && params.modelAliasLines.length > 0) {
35
+ lines.push(`\n模型别名:${params.modelAliasLines.join(",")}`);
36
+ }
37
+ // Workspace
38
+ lines.push(`\n工作目录:${params.workspaceDir}`);
39
+ if (params.workspaceNotes && params.workspaceNotes.length > 0) {
40
+ lines.push(params.workspaceNotes.join(";"));
41
+ }
42
+ // Sandbox - if enabled
43
+ if (params.sandboxEnabled && params.sandboxInfo) {
44
+ lines.push(`\n沙盒:${params.sandboxInfo}`);
45
+ }
46
+ // Owner identity
47
+ if (params.ownerLine) {
48
+ lines.push(`\n${params.ownerLine}`);
49
+ }
50
+ // Timezone
51
+ if (params.userTimezone) {
52
+ lines.push(`\n时区:${params.userTimezone}`);
53
+ }
54
+ // Reply tags - compressed
55
+ lines.push(`\n回复标签:[[reply_to_current]]回复当前,[[reply_to:<id>]]回复指定消息`);
56
+ // Messaging - if available
57
+ if (params.hasMessage) {
58
+ lines.push(`\n消息:message工具发送,多渠道传channel(${params.messageChannelOptions})`);
59
+ lines.push(`主动发送后回复:⏭️SILENT`);
60
+ if (params.inlineButtonsEnabled) {
61
+ lines.push(`按钮:action=send,buttons=[[{text,callback_data}]]`);
62
+ }
63
+ }
64
+ // Cron/reminders - if available
65
+ if (params.hasCron) {
66
+ lines.push(`\n提醒:cron工具,systemEvent写成提醒文本,含上下文`);
67
+ }
68
+ // Extra context
69
+ if (params.extraSystemPrompt) {
70
+ lines.push(`\n上下文:${params.extraSystemPrompt}`);
71
+ }
72
+ // Reactions
73
+ if (params.reactionGuidance) {
74
+ const { level, channel } = params.reactionGuidance;
75
+ lines.push(`\n反应(${channel}):${level === "minimal" ? "谨慎,1/5-10条" : "自由表达"}`);
76
+ }
77
+ // Context files
78
+ if (params.contextFiles && params.contextFiles.length > 0) {
79
+ lines.push(`\n# 项目上下文`);
80
+ const hasSoul = params.contextFiles.some((f) => f.path.toLowerCase().includes("soul.md"));
81
+ if (hasSoul) {
82
+ lines.push(`SOUL.md存在时,体现其人格和语气`);
83
+ }
84
+ for (const file of params.contextFiles) {
85
+ lines.push(`\n## ${file.path}\n${file.content}`);
86
+ }
87
+ }
88
+ // Silent replies
89
+ lines.push(`\n静默:无话可说时只回复:⏭️SILENT(整条消息,不附加其他内容)`);
90
+ // Heartbeat
91
+ const hbPrompt = params.heartbeatPrompt || "(configured)";
92
+ lines.push(`\n心跳:收到"${hbPrompt}"且无事,回复HEARTBEAT_OK`);
93
+ // Runtime
94
+ lines.push(`\n运行时:${params.runtimeLine}`);
95
+ lines.push(`推理:${params.reasoningLevel}`);
96
+ return lines.join("");
97
+ }
33
98
  function buildSkillsSection(params) {
34
99
  if (params.isMinimal)
35
100
  return [];
@@ -89,7 +154,7 @@ function buildMessagingSection(params) {
89
154
  "## Messaging",
90
155
  "- Reply in current session → automatically routes to the source channel (Signal, Telegram, etc.)",
91
156
  "- Cross-session messaging → use sessions_send(sessionKey, message)",
92
- "- Never use exec/curl for provider messaging; OpenClaw handles all routing internally.",
157
+ "- Never use exec/curl for provider messaging; EXOD handles all routing internally.",
93
158
  params.availableTools.has("message")
94
159
  ? [
95
160
  "",
@@ -125,13 +190,13 @@ function buildDocsSection(params) {
125
190
  return [];
126
191
  return [
127
192
  "## Documentation",
128
- `OpenClaw docs: ${docsPath}`,
129
- "Mirror: https://docs.openclaw.ai",
130
- "Source: https://github.com/openclaw/openclaw",
193
+ `EXOD docs: ${docsPath}`,
194
+ "Mirror: https://docs.exod.ai",
195
+ "Source: https://github.com/exod/exod",
131
196
  "Community: https://discord.com/invite/clawd",
132
197
  "Find new skills: https://clawdhub.com",
133
- "For OpenClaw behavior, commands, config, or architecture: consult local docs first.",
134
- "When diagnosing issues, run `openclaw status` yourself when possible; only ask the user if you lack access (e.g., sandboxed).",
198
+ "For EXOD behavior, commands, config, or architecture: consult local docs first.",
199
+ "When diagnosing issues, run `exod status` yourself when possible; only ask the user if you lack access (e.g., sandboxed).",
135
200
  "",
136
201
  ];
137
202
  }
@@ -154,7 +219,7 @@ export function buildAgentSystemPrompt(params) {
154
219
  nodes: "List/describe/notify/camera/screen on paired nodes",
155
220
  cron: "Manage cron jobs and wake events (use for reminders; when scheduling a reminder, write the systemEvent text as something that will read like a reminder when it fires, and mention that it is a reminder depending on the time gap between setting and firing; include recent context in reminder text if appropriate)",
156
221
  message: "Send messages and channel actions",
157
- gateway: "Restart, apply config, or run updates on the running OpenClaw process",
222
+ gateway: "Restart, apply config, or run updates on the running EXOD process",
158
223
  agents_list: "List agent ids allowed for sessions_spawn",
159
224
  sessions_list: "List other sessions (incl. sub-agents) with filters/last",
160
225
  sessions_history: "Fetch history for another session/sub-agent",
@@ -272,21 +337,54 @@ export function buildAgentSystemPrompt(params) {
272
337
  const workspaceNotes = (params.workspaceNotes ?? []).map((note) => note.trim()).filter(Boolean);
273
338
  // For "none" mode, return just the basic identity line
274
339
  if (promptMode === "none") {
275
- return "You are a personal assistant running inside OpenClaw.";
340
+ return "You are a personal assistant running inside EXOD.";
276
341
  }
277
- // For "exod" mode, return the compressed Mandarin+JSON system prompt
278
- // This reduces token usage from ~13K to ~1K
279
- if (promptMode === "exod") {
280
- const exodLines = [
281
- EXOD_COMPRESSED_SYSTEM,
282
- "",
283
- `Workspace: ${params.workspaceDir}`,
284
- params.userTimezone ? `Time: ${params.userTimezone}` : "",
285
- ];
286
- return exodLines.filter(Boolean).join("\n");
342
+ // Build sandbox info string if enabled
343
+ let sandboxInfoStr = "";
344
+ if (params.sandboxInfo?.enabled) {
345
+ const parts = ["Docker沙盒"];
346
+ if (params.sandboxInfo.workspaceDir)
347
+ parts.push(`ws=${params.sandboxInfo.workspaceDir}`);
348
+ if (params.sandboxInfo.workspaceAccess)
349
+ parts.push(`access=${params.sandboxInfo.workspaceAccess}`);
350
+ if (params.sandboxInfo.browserBridgeUrl)
351
+ parts.push("browser=on");
352
+ if (params.sandboxInfo.elevated?.allowed)
353
+ parts.push(`elevated=${params.sandboxInfo.elevated.defaultLevel}`);
354
+ sandboxInfoStr = parts.join(",");
355
+ }
356
+ // For "exod" mode OR "full" mode, use compressed Mandarin+JSON system prompt
357
+ // This reduces token usage from ~13K to ~2K
358
+ if (promptMode === "exod" || promptMode === "full") {
359
+ return buildExodCompressedSystem({
360
+ workspaceDir: params.workspaceDir,
361
+ toolLines: toolLines.map((t) => t.replace(/^- /, "").replace(": ", ":")),
362
+ ownerLine,
363
+ userTimezone,
364
+ skillsPrompt,
365
+ hasMemory: availableTools.has("memory_search") || availableTools.has("memory_get"),
366
+ hasGateway,
367
+ hasBrowser: availableTools.has("browser"),
368
+ hasMessage: availableTools.has("message"),
369
+ hasCron: availableTools.has("cron"),
370
+ messageChannelOptions,
371
+ inlineButtonsEnabled,
372
+ runtimeChannel,
373
+ sandboxEnabled: params.sandboxInfo?.enabled,
374
+ sandboxInfo: sandboxInfoStr,
375
+ modelAliasLines: params.modelAliasLines,
376
+ contextFiles: params.contextFiles,
377
+ heartbeatPrompt: params.heartbeatPrompt,
378
+ runtimeLine: buildRuntimeLine(runtimeInfo, runtimeChannel, runtimeCapabilities, params.defaultThinkLevel),
379
+ reasoningLevel: reasoningLevel,
380
+ extraSystemPrompt: params.extraSystemPrompt,
381
+ reactionGuidance: params.reactionGuidance,
382
+ workspaceNotes,
383
+ });
287
384
  }
385
+ // Minimal mode fallback - still uses compressed format but in English
288
386
  const lines = [
289
- "You are a personal assistant running inside OpenClaw.",
387
+ "You are a personal assistant running inside EXOD.",
290
388
  "",
291
389
  "## Tooling",
292
390
  "Tool availability (filtered by policy):",
@@ -301,7 +399,7 @@ export function buildAgentSystemPrompt(params) {
301
399
  "- apply_patch: apply multi-file patches",
302
400
  `- ${execToolName}: run shell commands (supports background via yieldMs/background)`,
303
401
  `- ${processToolName}: manage background exec sessions`,
304
- "- browser: control openclaw's dedicated browser",
402
+ "- browser: control exod's dedicated browser",
305
403
  "- canvas: present/eval/snapshot the Canvas",
306
404
  "- nodes: list/describe/notify/camera/screen on paired nodes",
307
405
  "- cron: manage cron jobs and wake events (use for reminders; when scheduling a reminder, write the systemEvent text as something that will read like a reminder when it fires, and mention that it is a reminder depending on the time gap between setting and firing; include recent context in reminder text if appropriate)",
@@ -318,25 +416,25 @@ export function buildAgentSystemPrompt(params) {
318
416
  "Keep narration brief and value-dense; avoid repeating obvious steps.",
319
417
  "Use plain human language for narration unless in a technical context.",
320
418
  "",
321
- "## OpenClaw CLI Quick Reference",
322
- "OpenClaw is controlled via subcommands. Do not invent commands.",
419
+ "## EXOD CLI Quick Reference",
420
+ "EXOD is controlled via subcommands. Do not invent commands.",
323
421
  "To manage the Gateway daemon service (start/stop/restart):",
324
- "- openclaw gateway status",
325
- "- openclaw gateway start",
326
- "- openclaw gateway stop",
327
- "- openclaw gateway restart",
328
- "If unsure, ask the user to run `openclaw help` (or `openclaw gateway --help`) and paste the output.",
422
+ "- exod gateway status",
423
+ "- exod gateway start",
424
+ "- exod gateway stop",
425
+ "- exod gateway restart",
426
+ "If unsure, ask the user to run `exod help` (or `exod gateway --help`) and paste the output.",
329
427
  "",
330
428
  ...skillsSection,
331
429
  ...memorySection,
332
430
  // Skip self-update for subagent/none modes
333
- hasGateway && !isMinimal ? "## OpenClaw Self-Update" : "",
431
+ hasGateway && !isMinimal ? "## EXOD Self-Update" : "",
334
432
  hasGateway && !isMinimal
335
433
  ? [
336
434
  "Get Updates (self-update) is ONLY allowed when the user explicitly asks for it.",
337
435
  "Do not run config.apply or update.run unless the user explicitly requests an update or config change; if it's not explicit, ask first.",
338
436
  "Actions: config.get, config.schema, config.apply (validate + write full config, then restart), update.run (update deps or git, then restart).",
339
- "After restart, OpenClaw pings the last active session automatically.",
437
+ "After restart, EXOD pings the last active session automatically.",
340
438
  ].join("\n")
341
439
  : "",
342
440
  hasGateway && !isMinimal ? "" : "",
@@ -403,7 +501,7 @@ export function buildAgentSystemPrompt(params) {
403
501
  userTimezone,
404
502
  }),
405
503
  "## Workspace Files (injected)",
406
- "These user-editable files are loaded by OpenClaw and included below in Project Context.",
504
+ "These user-editable files are loaded by EXOD and included below in Project Context.",
407
505
  "",
408
506
  ...buildReplyTagsSection(isMinimal),
409
507
  ...buildMessagingSection({
@@ -468,7 +566,7 @@ export function buildAgentSystemPrompt(params) {
468
566
  }
469
567
  // Skip heartbeats for subagent/none modes
470
568
  if (!isMinimal) {
471
- lines.push("## Heartbeats", heartbeatPromptLine, "If you receive a heartbeat poll (a user message matching the heartbeat prompt above), and there is nothing that needs attention, reply exactly:", "HEARTBEAT_OK", 'OpenClaw treats a leading/trailing "HEARTBEAT_OK" as a heartbeat ack (and may discard it).', 'If something needs attention, do NOT include "HEARTBEAT_OK"; reply with the alert text instead.', "");
569
+ lines.push("## Heartbeats", heartbeatPromptLine, "If you receive a heartbeat poll (a user message matching the heartbeat prompt above), and there is nothing that needs attention, reply exactly:", "HEARTBEAT_OK", 'EXOD treats a leading/trailing "HEARTBEAT_OK" as a heartbeat ack (and may discard it).', 'If something needs attention, do NOT include "HEARTBEAT_OK"; reply with the alert text instead.', "");
472
570
  }
473
571
  lines.push("## Runtime", buildRuntimeLine(runtimeInfo, runtimeChannel, runtimeCapabilities, params.defaultThinkLevel), `Reasoning: ${reasoningLevel} (hidden unless on/stream). Toggle /reasoning; /status shows Reasoning when enabled.`);
474
572
  return lines.filter(Boolean).join("\n");
@@ -5,6 +5,3 @@ export function resolveIMessageTargets() {
5
5
  export function normalizeIMessageHandle(handle) {
6
6
  return handle;
7
7
  }
8
- export function parseIMessageTarget(target) {
9
- return null;
10
- }
@@ -17,18 +17,3 @@ export function createDeviceControlCard(_params) {
17
17
  export function createAppleTvRemoteCard(_params) {
18
18
  return null;
19
19
  }
20
- export function createInfoCard(_params) {
21
- return null;
22
- }
23
- export function createListCard(_params) {
24
- return null;
25
- }
26
- export function createImageCard(_params) {
27
- return null;
28
- }
29
- export function createActionCard(_params) {
30
- return null;
31
- }
32
- export function createReceiptCard(_params) {
33
- return null;
34
- }
@@ -5,9 +5,6 @@ export function table(_data, _options) {
5
5
  export function printTable(_data, _options) {
6
6
  // No-op
7
7
  }
8
- export function renderTable(_data, _options) {
9
- return "";
10
- }
11
8
  export class Table {
12
9
  constructor(_options) { }
13
10
  push(..._args) { }
@@ -1,38 +1,18 @@
1
1
  // Stub for terminal theme - Terminal UI not needed
2
2
  export const theme = {
3
- primary: (t) => t,
4
- secondary: (t) => t,
5
- success: (t) => t,
6
- error: (t) => t,
7
- warning: (t) => t,
8
- warn: (t) => t,
9
- info: (t) => t,
10
- muted: (t) => t,
11
- heading: (t) => t,
12
- accent: (t) => t,
13
- accentDim: (t) => t,
14
- accentBright: (t) => t,
15
- command: (t) => t,
16
- dim: (t) => t,
17
- bold: (t) => t,
18
- italic: (t) => t,
19
- underline: (t) => t,
20
- link: (t) => t,
21
- code: (t) => t,
22
- highlight: (t) => t,
23
- option: (t) => t,
24
- argument: (t) => t,
25
- subcommand: (t) => t,
26
- description: (t) => t,
27
- example: (t) => t,
28
- keyword: (t) => t,
29
- value: (t) => t,
30
- path: (t) => t,
31
- url: (t) => t,
32
- number: (t) => t,
33
- string: (t) => t,
3
+ primary: "",
4
+ secondary: "",
5
+ success: "",
6
+ error: "",
7
+ warning: "",
8
+ info: "",
9
+ muted: "",
10
+ heading: "",
11
+ accent: "",
12
+ accentDim: "",
13
+ accentBright: "",
34
14
  };
35
- export function colorize(_rich, _color, text) {
15
+ export function colorize(text, ..._rest) {
36
16
  return text;
37
17
  }
38
18
  export function isRich() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "exod",
3
- "version": "1.0.0-alpha.15",
3
+ "version": "1.0.0-alpha.16",
4
4
  "description": "EXOD.ai - AI Marketing Automation Agent for Facebook & Instagram Ads",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",