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.
- package/dist/agents/system-prompt.js +156 -58
- package/dist/imessage/targets.js +0 -3
- package/dist/line/flex-templates.js +0 -15
- package/dist/terminal/table.js +0 -3
- package/dist/terminal/theme.js +12 -32
- package/package.json +1 -1
|
@@ -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 ~
|
|
6
|
+
* Reduces ~13K tokens to ~2K tokens while preserving ALL functionality
|
|
7
7
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
"
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
"
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
{
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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;
|
|
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
|
-
`
|
|
129
|
-
"Mirror: https://docs.
|
|
130
|
-
"Source: https://github.com/
|
|
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
|
|
134
|
-
"When diagnosing issues, run `
|
|
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
|
|
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
|
|
340
|
+
return "You are a personal assistant running inside EXOD.";
|
|
276
341
|
}
|
|
277
|
-
//
|
|
278
|
-
|
|
279
|
-
if (
|
|
280
|
-
const
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
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
|
|
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
|
|
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
|
-
"##
|
|
322
|
-
"
|
|
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
|
-
"-
|
|
325
|
-
"-
|
|
326
|
-
"-
|
|
327
|
-
"-
|
|
328
|
-
"If unsure, ask the user to run `
|
|
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 ? "##
|
|
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,
|
|
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
|
|
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", '
|
|
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");
|
package/dist/imessage/targets.js
CHANGED
|
@@ -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
|
-
}
|
package/dist/terminal/table.js
CHANGED
package/dist/terminal/theme.js
CHANGED
|
@@ -1,38 +1,18 @@
|
|
|
1
1
|
// Stub for terminal theme - Terminal UI not needed
|
|
2
2
|
export const theme = {
|
|
3
|
-
primary:
|
|
4
|
-
secondary:
|
|
5
|
-
success:
|
|
6
|
-
error:
|
|
7
|
-
warning:
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
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(
|
|
15
|
+
export function colorize(text, ..._rest) {
|
|
36
16
|
return text;
|
|
37
17
|
}
|
|
38
18
|
export function isRich() {
|