evolcore 0.0.35 → 0.0.36
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 +31 -0
- package/README.md +6 -0
- package/bin/install-codex-managed-hooks.mjs +20 -3
- package/dist/agents/baseagent-availability.js +1 -1
- package/dist/agents/baseagent.js +88 -0
- package/dist/agents/claude-runner.js +59 -12
- package/dist/agents/codex/app-server-client.js +18 -1
- package/dist/agents/codex-runner.js +262 -21
- package/dist/agents/ecagent-runner.js +47 -11
- package/dist/agents/gemini-runner.js +36 -12
- package/dist/aun/aid/client.js +4 -3
- package/dist/aun/aid/control-aid.js +270 -8
- package/dist/aun/aid/identity.js +6 -3
- package/dist/aun/aid/ownership-operation.js +58 -0
- package/dist/aun/aid/store.js +1 -0
- package/dist/aun/group/fs-download.js +67 -2
- package/dist/aun/group/history.js +20 -5
- package/dist/aun/group/operations.js +8 -2
- package/dist/aun/menu/client.js +39 -2
- package/dist/aun/menu/transport.js +1 -1
- package/dist/aun/msg/history.js +43 -4
- package/dist/aun/msg/managed-operation.js +30 -53
- package/dist/aun/msg/p2p.js +51 -15
- package/dist/aun/outbox.js +4 -0
- package/dist/channels/aun.js +260 -73
- package/dist/channels/daemon.js +6 -4
- package/dist/channels/feishu.js +3 -0
- package/dist/cli/agent-command.js +161 -223
- package/dist/cli/agent-create.js +190 -223
- package/dist/cli/agent.js +3 -1
- package/dist/cli/aid-bind-command.js +53 -0
- package/dist/cli/aun-commands.js +384 -91
- package/dist/cli/bench.js +1 -1
- package/dist/cli/cli-argv.js +74 -0
- package/dist/cli/daemon-commands.js +105 -74
- package/dist/cli/diag.js +1 -1
- package/dist/cli/fs-command.js +18 -19
- package/dist/cli/getmeta-command.js +159 -6
- package/dist/cli/index.js +6 -12
- package/dist/cli/init-channel.js +8 -55
- package/dist/cli/init.js +125 -218
- package/dist/cli/queue-command.js +11 -8
- package/dist/cli/restart-monitor.js +134 -48
- package/dist/cli/session-command.js +1 -1
- package/dist/cli/stats.js +7 -5
- package/dist/cli/thread-command.js +103 -30
- package/dist/cli/trigger-command.js +1 -1
- package/dist/cli/watch-msg-diag.js +1 -0
- package/dist/config/access-policy.js +2 -2
- package/dist/config/boot-log.js +14 -11
- package/dist/config/config-field-policy.js +9 -1
- package/dist/config/config-manager.js +176 -90
- package/dist/config/config-operation-service.js +7 -14
- package/dist/config/contact-book-store.js +142 -26
- package/dist/config/contact-book.js +4 -2
- package/dist/config/lifecycle.js +1 -1
- package/dist/config/owner-config.js +96 -0
- package/dist/config/peer-role-resolver.js +12 -18
- package/dist/config/providers-config.js +382 -0
- package/dist/config/providers-import.js +74 -0
- package/dist/config/providers-management.js +328 -0
- package/dist/config/providers.js +22 -0
- package/dist/config/resolved-config-op.js +17 -14
- package/dist/config/snapshot.js +28 -16
- package/dist/config-store.js +18 -14
- package/dist/core/agent-ipc-registration.js +21 -63
- package/dist/core/agent-runtime.js +16 -5
- package/dist/core/auth/agent-delegation.js +199 -25
- package/dist/core/auth/auth-gateway.js +44 -2
- package/dist/core/auth/authorization-denial.js +1 -1
- package/dist/core/auth/debug-context.js +2 -1
- package/dist/core/auth/delegation-authorization.js +2 -2
- package/dist/core/auth/delegation-diagnostics.js +4 -1
- package/dist/core/auth/operation-authorizer.js +10 -1
- package/dist/core/auth/operation-catalog.js +19 -1
- package/dist/core/bootstrap-service.js +43 -20
- package/dist/core/channel-loader.js +0 -1
- package/dist/core/channel-runtime.js +30 -4
- package/dist/core/command/agent-control.js +196 -37
- package/dist/core/command/cli-intent-parser.js +60 -4
- package/dist/core/command/command-handler.js +212 -60
- package/dist/core/command/connect-menu.js +1 -0
- package/dist/core/command/diag-service.js +5 -4
- package/dist/core/command/file-search.js +368 -0
- package/dist/core/command/menu-catalog.js +2 -1
- package/dist/core/command/menu-handler.js +292 -107
- package/dist/core/command/menu-protocol.js +23 -0
- package/dist/core/command/role-menu.js +7 -19
- package/dist/core/command/skill-slash.js +130 -25
- package/dist/core/command/slash-handler.js +101 -53
- package/dist/core/command/topic-slash.js +16 -5
- package/dist/core/daemon-bootstrap.js +7 -1
- package/dist/core/daemon-control.js +19 -1
- package/dist/core/daemon-lifecycle.js +2 -1
- package/dist/core/event-catalog.js +2 -0
- package/dist/core/evolagent-registry.js +13 -2
- package/dist/core/evolagent.js +3 -6
- package/dist/core/handoff/ipc-registration.js +2 -2
- package/dist/core/handoff/runtime.js +40 -6
- package/dist/core/handoff/store.js +1 -0
- package/dist/core/inference/text-inference.js +95 -6
- package/dist/core/ipc-registration.js +43 -24
- package/dist/core/memory/consolidation-context.js +4 -1
- package/dist/core/memory/consolidation.js +25 -14
- package/dist/core/message/aun-ipc-sender.js +296 -88
- package/dist/core/message/aun-request-registry.js +226 -0
- package/dist/core/message/create-status.js +33 -4
- package/dist/core/message/message-bridge.js +62 -13
- package/dist/core/message/message-log.js +0 -1
- package/dist/core/message/message-queue.js +4 -1
- package/dist/core/message/message-utils.js +8 -1
- package/dist/core/message/peer-mode.js +17 -9
- package/dist/core/message/response-engine.js +266 -124
- package/dist/core/message/retry-scheduler.js +11 -8
- package/dist/core/model/catalog-service.js +60 -18
- package/dist/core/model/model-catalog.js +112 -9
- package/dist/core/model/model-fallback.js +94 -26
- package/dist/core/ownership/owner-resolver.js +687 -0
- package/dist/core/permission/approval-gateway.js +196 -62
- package/dist/core/permission/ec-command-parser.js +138 -25
- package/dist/core/permission/filesystem-approval-scope.js +141 -0
- package/dist/core/permission/protected-paths.js +14 -1
- package/dist/core/permission/sandbox-runtime.js +171 -18
- package/dist/core/permission/tool-policy.js +13 -2
- package/dist/core/role/runtime-policy.js +3 -4
- package/dist/core/session/session-idle-monitor.js +10 -8
- package/dist/core/session/session-manager.js +72 -45
- package/dist/core/session/session-mapper.js +18 -7
- package/dist/core/session/session-renew.js +5 -4
- package/dist/core/session/session-title.js +2 -1
- package/dist/core/session/session-turn-coordinator.js +4 -2
- package/dist/core/skill/index-generator.js +2 -16
- package/dist/core/task/task-recovery-service.js +15 -2
- package/dist/core/thread/command-parser.js +28 -13
- package/dist/core/thread/index.js +1 -0
- package/dist/core/thread/ipc-operation.js +11 -8
- package/dist/core/thread/thread-operation.js +79 -44
- package/dist/core/thread/thread-route.js +54 -6
- package/dist/core/thread/thread-service.js +236 -45
- package/dist/core/thread/topic-id.js +248 -0
- package/dist/eck/kit-renderer.js +1 -1
- package/dist/eck/message-renderer.js +12 -2
- package/dist/index.js +50 -27
- package/dist/ipc.js +59 -6
- package/dist/paths.js +1 -0
- package/dist/product.js +1 -0
- package/dist/response-system/engines/v1/proactive-flow.js +10 -3
- package/dist/stats/db.js +8 -0
- package/dist/stats/writer.js +26 -4
- package/dist/trigger/authorization.js +48 -3
- package/dist/trigger/feedback.js +28 -10
- package/dist/trigger/ipc-service.js +86 -10
- package/dist/trigger/local-files.js +55 -23
- package/dist/trigger/scheduler.js +57 -11
- package/dist/trigger/system-definitions.js +1 -0
- package/dist/trigger/validation.js +44 -15
- package/dist/utils/aid-bind.js +17 -297
- package/dist/utils/avatar-upload.js +16 -4
- package/dist/utils/cross-platform.js +109 -34
- package/dist/utils/ecweb-supervisor.js +1 -1
- package/dist/utils/ecweb-utils.js +8 -1
- package/dist/utils/error-utils.js +44 -6
- package/dist/utils/instance-registry.js +12 -2
- package/dist/utils/npm-ops.js +102 -27
- package/dist/utils/package-version-info.js +72 -27
- package/dist/utils/restart-safety.js +50 -0
- package/dist/utils/upgrade-jobs.js +304 -0
- package/dist/utils/windows-autostart.js +17 -10
- package/kits/docs/INDEX.md +5 -0
- package/kits/docs/aun/ABILITY_CALLING.md +239 -0
- package/kits/docs/evolcore/INDEX.md +14 -3
- package/kits/docs/evolcore/agent-create.md +55 -141
- package/kits/docs/evolcore/agent.md +38 -16
- package/kits/docs/evolcore/aid.md +34 -0
- package/kits/docs/evolcore/config.md +20 -1
- package/kits/docs/evolcore/event.md +2 -2
- package/kits/docs/evolcore/fs.md +18 -2
- package/kits/docs/evolcore/group-collaboration.md +13 -246
- package/kits/docs/evolcore/group.md +2 -1
- package/kits/docs/evolcore/memory-consolidation-batches.md +1 -1
- package/kits/docs/evolcore/menu-protocol.md +65 -1
- package/kits/docs/evolcore/msg.md +64 -2
- package/kits/docs/evolcore/skill.md +86 -0
- package/kits/docs/evolcore/stats.md +6 -0
- package/kits/docs/evolcore/task.md +2 -0
- package/kits/docs/evolcore/thread-chain.md +145 -51
- package/kits/docs/evolcore/trigger.md +48 -3
- package/kits/eck_manifest.json +21 -0
- package/kits/eck_message_manifest.json +4 -4
- package/kits/migrations/migrate-role-config-v5.mjs +20 -7
- package/kits/rules/01-overview.md +2 -1
- package/kits/rules/03-identity.md +3 -1
- package/kits/rules/04-relation.md +1 -1
- package/kits/rules/07-memory-and-thread.md +1 -1
- package/kits/schemas/_meta.json +16 -1
- package/kits/schemas/agent-config.schema.13.json +44 -2
- package/kits/schemas/contact-book.schema.3.json +5 -0
- package/kits/schemas/daemon.schema.6.json +3 -1
- package/kits/schemas/daemon.schema.8.json +329 -0
- package/kits/schemas/defaults.schema.5.json +39 -3
- package/kits/schemas/providers.schema.1.json +76 -0
- package/kits/schemas/relation-config.schema.9.json +5 -1
- package/kits/skills/.switches.json +28 -0
- package/kits/skills/aid-ability/SKILL.md +214 -0
- package/kits/skills/ec-agent-create/SKILL.md +162 -0
- package/kits/skills/ec-group/SKILL.md +2 -1
- package/kits/skills/ec-group-collaboration/SKILL.md +228 -0
- package/kits/skills/ec-identity/SKILL.md +143 -0
- package/kits/skills/ec-skill/scripts/cli.mjs +36 -3
- package/kits/skills/ec-skill/scripts/skill.mjs +202 -15
- package/kits/skills/ec-trigger/SKILL.md +167 -0
- package/kits/skills/ec-trigger/references/examples.md +153 -0
- package/kits/skills/thread-ops/SKILL.md +108 -420
- package/kits/templates/message-fragments/thread-context.md +1 -2
- package/kits/templates/message-fragments/trigger-thread-check.md +1 -1
- package/kits/templates/roles/member.json +1 -1
- package/kits/templates/roles/visitor.json +1 -0
- package/kits/templates/system-fragments/bootstrap.md +1 -0
- package/kits/templates/system-fragments/channel.md +2 -1
- package/kits/templates/system-fragments/commands.md +5 -4
- package/kits/templates/system-fragments/identity.md +2 -0
- package/kits/templates/system-fragments/session.md +1 -1
- package/kits/templates/system-fragments/venue.md +1 -1
- package/package.json +4 -3
|
@@ -41,6 +41,15 @@ function agentSkillsDir() {
|
|
|
41
41
|
|
|
42
42
|
const SWITCHES_FILE = '.switches.json';
|
|
43
43
|
|
|
44
|
+
/**
|
|
45
|
+
* 写操作后的索引刷新提示。技能目录监控默认关闭(daemon.json `skills.watch=false`),
|
|
46
|
+
* 不刷新的话注入给模型的技能索引仍是旧列表。
|
|
47
|
+
*/
|
|
48
|
+
function refreshHint() {
|
|
49
|
+
const aid = process.env.EVOLCORE_SELF_AID || '<aid>';
|
|
50
|
+
return `注入给模型的技能索引不会自动更新,请执行: ec skill refresh ${aid}`;
|
|
51
|
+
}
|
|
52
|
+
|
|
44
53
|
// ── 权限门禁 ──────────────────────────────────────────────────────────
|
|
45
54
|
//
|
|
46
55
|
// 三级技能目录的写权限不对等,判据也不同:
|
|
@@ -267,23 +276,108 @@ export function resolveAll() {
|
|
|
267
276
|
|
|
268
277
|
// ── 子命令 ────────────────────────────────────────────────────────────
|
|
269
278
|
|
|
270
|
-
export function cmdList({ json = false } = {}) {
|
|
279
|
+
export function cmdList({ json = false, all = false, filter = [], page = 1, limit = 20, paginateJson = false, commandStyle = process.env.SKILL_COMMAND_STYLE || 'cli' } = {}) {
|
|
271
280
|
const skills = resolveAll();
|
|
272
|
-
|
|
281
|
+
// --filter 可多次出现,每次值内逗号分隔。
|
|
282
|
+
// 组内(逗号分隔)→ OR;多个 --filter 之间 → AND。
|
|
283
|
+
// 匹配范围:技能名 + description,大小写不敏感。
|
|
284
|
+
const rawGroups = Array.isArray(filter) ? filter : (filter ? [filter] : []);
|
|
285
|
+
const filterGroups = rawGroups
|
|
286
|
+
.map(g => String(g).split(',').map(s => s.trim()).filter(Boolean))
|
|
287
|
+
.filter(g => g.length > 0);
|
|
288
|
+
|
|
289
|
+
const descOf = s => {
|
|
290
|
+
const fm = readFrontmatter(s.dir) || {};
|
|
291
|
+
return typeof fm.description === 'string' ? fm.description : '';
|
|
292
|
+
};
|
|
293
|
+
|
|
294
|
+
let shown = all ? skills : skills.filter(s => s.enabled);
|
|
295
|
+
if (filterGroups.length > 0) {
|
|
296
|
+
shown = shown.filter(s => {
|
|
297
|
+
const hay = `${s.name}\n${descOf(s)}`.toLowerCase();
|
|
298
|
+
return filterGroups.every(group => group.some(kw => hay.includes(kw.toLowerCase())));
|
|
299
|
+
});
|
|
300
|
+
}
|
|
273
301
|
|
|
274
|
-
|
|
302
|
+
const cmdPrefix = commandStyle === 'slash' ? '/skill list' : 'ec skill list';
|
|
303
|
+
const filterArgs = filterGroups.map(g => `--filter '${g.join(',')}'`);
|
|
304
|
+
|
|
305
|
+
// 分页:limit > 0 且总数超 limit 才分页
|
|
306
|
+
const total = shown.length;
|
|
307
|
+
const effectiveLimit = limit > 0 ? limit : 20;
|
|
308
|
+
const hasPaging = total > effectiveLimit;
|
|
309
|
+
const totalPages = hasPaging ? Math.ceil(total / effectiveLimit) : 1;
|
|
310
|
+
const requestedPage = page < 1 ? 1 : page;
|
|
311
|
+
const currentPage = Math.min(requestedPage, totalPages);
|
|
312
|
+
const paged = hasPaging
|
|
313
|
+
? shown.slice((currentPage - 1) * effectiveLimit, currentPage * effectiveLimit)
|
|
314
|
+
: shown;
|
|
315
|
+
|
|
316
|
+
// JSON 默认返回全部匹配项(供脚本消费);显式给了 --page/--limit 才分页
|
|
317
|
+
if (json) return paginateJson ? paged : shown;
|
|
318
|
+
|
|
319
|
+
const enabledCount = skills.filter(s => s.enabled).length;
|
|
320
|
+
const fmtGroup = g => g.length === 1 ? `"${g[0]}"` : `(${g.map(k => `"${k}"`).join(' | ')})`;
|
|
321
|
+
|
|
322
|
+
if (shown.length === 0) {
|
|
323
|
+
if (filterGroups.length > 0) {
|
|
324
|
+
const tip = all ? '' : `;搜全部技能: ${[cmdPrefix, '--all', ...filterArgs].join(' ')}`;
|
|
325
|
+
return `(没有匹配 ${filterGroups.map(fmtGroup).join(' AND ')} 的技能${tip})`;
|
|
326
|
+
}
|
|
327
|
+
return all ? '(没有任何技能)' : `(没有启用的技能,共 ${skills.length} 个;查看全部: ${cmdPrefix} --all)`;
|
|
328
|
+
}
|
|
275
329
|
|
|
330
|
+
const filterNote = filterGroups.length > 0 ? `,过滤: ${filterGroups.map(fmtGroup).join(' AND ')}` : '';
|
|
331
|
+
const allNote = all ? '' : '(仅列启用;加 --all 查看全部)';
|
|
332
|
+
const pageNote = hasPaging ? `,第 ${currentPage}/${totalPages} 页` : '';
|
|
276
333
|
const lines = [];
|
|
277
|
-
lines.push(`${skills.length}
|
|
278
|
-
|
|
279
|
-
const
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
334
|
+
lines.push(`${skills.length} 个技能,${enabledCount} 个启用${allNote}${filterNote}${pageNote}`);
|
|
335
|
+
|
|
336
|
+
const groups = [
|
|
337
|
+
{ label: '内置技能', items: paged.filter(s => s.source === 'builtin') },
|
|
338
|
+
{ label: '本机技能', items: paged.filter(s => s.source === 'local') },
|
|
339
|
+
];
|
|
340
|
+
|
|
341
|
+
const nameW = Math.max(20, ...paged.map(s => s.name.length + 2));
|
|
342
|
+
|
|
343
|
+
for (const { label, items } of groups) {
|
|
344
|
+
if (items.length === 0) continue;
|
|
345
|
+
lines.push('');
|
|
346
|
+
lines.push(`── ${label} (${items.length}) ──`);
|
|
347
|
+
for (const s of items) {
|
|
348
|
+
const state = s.enabled ? '开' : '关';
|
|
349
|
+
const lock = s.locked ? ' [locked]' : '';
|
|
350
|
+
const fm = readFrontmatter(s.dir) || {};
|
|
351
|
+
const rawDesc = typeof fm.description === 'string' ? fm.description : '';
|
|
352
|
+
const desc = rawDesc.length > 30
|
|
353
|
+
? rawDesc.slice(0, 30).replace(/[,。、,.\s]+$/, '') + '…'
|
|
354
|
+
: rawDesc;
|
|
355
|
+
lines.push(` ${s.name.padEnd(nameW)}${(state + lock).padEnd(10)}${desc}`);
|
|
356
|
+
}
|
|
284
357
|
}
|
|
285
|
-
|
|
286
|
-
|
|
358
|
+
|
|
359
|
+
// 页脚:有翻页就给翻页命令 + 缩小范围的方法(与是否带 --all 无关)
|
|
360
|
+
if (hasPaging) {
|
|
361
|
+
const scope = all ? ['--all'] : [];
|
|
362
|
+
const limitArg = effectiveLimit !== 20 ? [`--limit ${effectiveLimit}`] : [];
|
|
363
|
+
const pageCmd = p => [cmdPrefix, ...scope, ...filterArgs, ...limitArg, `--page ${p}`].join(' ');
|
|
364
|
+
|
|
365
|
+
lines.push('');
|
|
366
|
+
lines.push(`── 第 ${currentPage}/${totalPages} 页(每页 ${effectiveLimit} 条,共 ${total} 条)──`);
|
|
367
|
+
if (requestedPage > totalPages) {
|
|
368
|
+
lines.push(`(请求的第 ${requestedPage} 页超出范围,已显示最后一页)`);
|
|
369
|
+
}
|
|
370
|
+
if (currentPage < totalPages) lines.push(`下一页: ${pageCmd(currentPage + 1)}`);
|
|
371
|
+
if (currentPage > 1) lines.push(`上一页: ${pageCmd(currentPage - 1)}`);
|
|
372
|
+
if (filterGroups.length === 0) {
|
|
373
|
+
lines.push(`缩小范围: ${[cmdPrefix, ...scope, "--filter '<关键词>'"].join(' ')}(匹配名称和描述,逗号分隔为或)`);
|
|
374
|
+
lines.push(` 例: ${[cmdPrefix, ...scope, "--filter '飞书,lark'"].join(' ')}`);
|
|
375
|
+
} else {
|
|
376
|
+
lines.push(`继续缩小: 再加一个 --filter(多个 --filter 之间为且)`);
|
|
377
|
+
lines.push(` 例: ${[cmdPrefix, ...scope, ...filterArgs, "--filter '<关键词>'"].join(' ')}`);
|
|
378
|
+
}
|
|
379
|
+
}
|
|
380
|
+
|
|
287
381
|
return lines.join('\n');
|
|
288
382
|
}
|
|
289
383
|
|
|
@@ -406,6 +500,7 @@ export function cmdCreate(name, { desc = '', force = false, enable = false, json
|
|
|
406
500
|
' 2. 正文写清步骤;需要时把大块资料放 references/',
|
|
407
501
|
' 3. 需要脚本就放 scripts/,脚本内用 import.meta.dirname 自定位,不要依赖 cwd',
|
|
408
502
|
enable ? ` 4. 如需停用: ec skill disable ${name}` : ` 4. 完成后启用: ec skill enable ${name}`,
|
|
503
|
+
...(enable ? ['', refreshHint()] : []),
|
|
409
504
|
].join('\n');
|
|
410
505
|
}
|
|
411
506
|
|
|
@@ -472,7 +567,7 @@ export function cmdInstall(src, { force = false, enable = false, json = false }
|
|
|
472
567
|
`✅ 已安装技能 ${name} → ${target}`,
|
|
473
568
|
` 状态: ${enable ? '已启用' : '已禁用(开关缺省即禁用)'}`,
|
|
474
569
|
'',
|
|
475
|
-
|
|
570
|
+
refreshHint(),
|
|
476
571
|
enable
|
|
477
572
|
? `如需停用: ec skill disable ${name}`
|
|
478
573
|
: `确认要启用吗?启用: ec skill enable ${name}(本机级全机启用加 --level local)`,
|
|
@@ -512,7 +607,7 @@ export function cmdRemove(name, { json = false } = {}) {
|
|
|
512
607
|
|
|
513
608
|
const result = { name, removed: true };
|
|
514
609
|
if (json) return result;
|
|
515
|
-
return `✅ 已删除本机技能 ${name}
|
|
610
|
+
return [`✅ 已删除本机技能 ${name}`, refreshHint()].join('\n');
|
|
516
611
|
}
|
|
517
612
|
|
|
518
613
|
export function cmdEnableDisable(name, enabled, { level = 'agent', json = false } = {}) {
|
|
@@ -545,10 +640,102 @@ export function cmdEnableDisable(name, enabled, { level = 'agent', json = false
|
|
|
545
640
|
`✅ ${enabled ? '已启用' : '已禁用'} ${name}(${level} 级)`,
|
|
546
641
|
` 写入: ${file}`,
|
|
547
642
|
'',
|
|
548
|
-
|
|
643
|
+
refreshHint(),
|
|
549
644
|
].join('\n');
|
|
550
645
|
}
|
|
551
646
|
|
|
647
|
+
export function cmdPath(name, { json = false } = {}) {
|
|
648
|
+
if (!name) throw new Error('缺少技能名。用法:ec skill path <name>');
|
|
649
|
+
const all = resolveAll();
|
|
650
|
+
// 注意:resolveAll 按覆盖链只保留一个来源(本机覆盖内置),
|
|
651
|
+
// 需要两个来源都有的情况要分别扫描
|
|
652
|
+
const roots = skillRoots();
|
|
653
|
+
const builtinDir = path.join(roots.builtin, name);
|
|
654
|
+
const localDir = roots.local ? path.join(roots.local, name) : null;
|
|
655
|
+
const builtinExists = fs.existsSync(path.join(builtinDir, 'SKILL.md'));
|
|
656
|
+
const localExists = localDir ? fs.existsSync(path.join(localDir, 'SKILL.md')) : false;
|
|
657
|
+
|
|
658
|
+
if (!builtinExists && !localExists) {
|
|
659
|
+
throw new Error(`技能不存在: ${name}\n用 ec skill list --all --filter '${name}' 查找相近的技能`);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
const skill = all.find(s => s.name === name);
|
|
663
|
+
const rows = [];
|
|
664
|
+
if (builtinExists) {
|
|
665
|
+
const p = path.join(builtinDir, 'SKILL.md');
|
|
666
|
+
const mtime = fs.statSync(p).mtimeMs;
|
|
667
|
+
const enabled = skill ? skill.enabled : false;
|
|
668
|
+
rows.push({ source: 'builtin', enabled, path: p, mtime });
|
|
669
|
+
}
|
|
670
|
+
if (localExists) {
|
|
671
|
+
const p = path.join(localDir, 'SKILL.md');
|
|
672
|
+
const mtime = fs.statSync(p).mtimeMs;
|
|
673
|
+
const enabled = skill ? skill.enabled : false;
|
|
674
|
+
rows.push({ source: 'local', enabled, path: p, mtime });
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
// 建议路径:优先本机级(覆盖链顶端),再按 mtime 最新
|
|
678
|
+
const suggested = rows.find(r => r.source === 'local') ??
|
|
679
|
+
rows.reduce((a, b) => b.mtime > a.mtime ? b : a);
|
|
680
|
+
|
|
681
|
+
if (json) return { rows, suggested: suggested.path };
|
|
682
|
+
|
|
683
|
+
const lines = rows.map(r => {
|
|
684
|
+
const mtimeStr = new Date(r.mtime).toLocaleString('zh-CN');
|
|
685
|
+
const stateStr = r.enabled ? '开' : '关';
|
|
686
|
+
const marker = r.path === suggested.path && rows.length > 1 ? ' ← 建议' : '';
|
|
687
|
+
return `${r.source.padEnd(8)}${stateStr} ${r.path} (${mtimeStr})${marker}`;
|
|
688
|
+
});
|
|
689
|
+
if (rows.length === 1) lines.push(rows[0].path);
|
|
690
|
+
return lines.join('\n');
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
export function cmdLoad(name, { source = null, withFrontmatter = false, json = false } = {}) {
|
|
694
|
+
if (!name) throw new Error('缺少技能名。用法:ec skill load <name> [--source builtin|local] [--with-frontmatter]');
|
|
695
|
+
if (source && source !== 'builtin' && source !== 'local') {
|
|
696
|
+
throw new Error('--source 只能是 builtin 或 local');
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
const roots = skillRoots();
|
|
700
|
+
const all = resolveAll();
|
|
701
|
+
const skill = all.find(s => s.name === name);
|
|
702
|
+
|
|
703
|
+
// 确定技能目录:source 指定时用对应根目录,否则按覆盖链结果
|
|
704
|
+
let skillDir;
|
|
705
|
+
if (source === 'builtin') {
|
|
706
|
+
skillDir = path.join(roots.builtin, name);
|
|
707
|
+
} else if (source === 'local') {
|
|
708
|
+
if (!roots.local) throw new Error('无法定位本机级目录');
|
|
709
|
+
skillDir = path.join(roots.local, name);
|
|
710
|
+
} else {
|
|
711
|
+
if (!skill) throw new Error(`技能不存在: ${name}\n用 ec skill list --all --filter '${name}' 查找相近的技能`);
|
|
712
|
+
skillDir = skill.dir;
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
const skillMd = path.join(skillDir, 'SKILL.md');
|
|
716
|
+
if (!fs.existsSync(skillMd)) {
|
|
717
|
+
if (!source) throw new Error(`SKILL.md 不存在: ${skillMd}`);
|
|
718
|
+
const label = source === 'builtin' ? '内置级' : '本机级';
|
|
719
|
+
throw new Error(skill
|
|
720
|
+
? `${label}没有技能 ${name}(该技能来自 ${skill.source},去掉 --source 或改用 --source ${skill.source})`
|
|
721
|
+
: `${label}没有技能 ${name}\n用 ec skill list --all --filter '${name}' 查找相近的技能`);
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
if (!skill || !skill.enabled) {
|
|
725
|
+
throw new Error(`技能未启用: ${name}\n请先执行: ec skill enable ${name}`);
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
let content = fs.readFileSync(skillMd, 'utf-8');
|
|
729
|
+
if (!withFrontmatter) {
|
|
730
|
+
content = content.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n/, '');
|
|
731
|
+
}
|
|
732
|
+
const footer = `\n---\nskillDir: ${skillDir}\n`;
|
|
733
|
+
const output = content.trimStart() + footer;
|
|
734
|
+
|
|
735
|
+
if (json) return { name, skillDir, content: output };
|
|
736
|
+
return output;
|
|
737
|
+
}
|
|
738
|
+
|
|
552
739
|
export function cmdWhere({ json = false } = {}) {
|
|
553
740
|
const roots = skillRoots();
|
|
554
741
|
const info = {
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ec-trigger
|
|
3
|
+
description: >-
|
|
4
|
+
EC Trigger(定时/事件触发器)的使用决策指南。用户说"过会儿提醒我""每天/每周几点"
|
|
5
|
+
"每隔 N 分钟看一眼""盯着、巡检、自动跟进、到时通知""有事就说""定时任务/定时检查/cron/
|
|
6
|
+
闹钟/计划任务",或要取消、改期已有 trigger,排查 trigger 为什么没触发、没发送、发错地方时
|
|
7
|
+
使用。也用于设计事件驱动自动化(消息到达、任务失败、会话闲置后触发)。不适用于当前会话里
|
|
8
|
+
马上能做完的事(直接做),也不适用于跨话题收发消息本身(用 thread-ops)。
|
|
9
|
+
license: MIT
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
# EC Trigger 决策指南
|
|
13
|
+
|
|
14
|
+
**本 skill 只讲决策与行为语义**:什么场景该建 trigger、建哪一种、结果发给谁、建完怎么
|
|
15
|
+
复核、什么时候收尾。参数细节看 `ec trigger --help` 和 `$KITS_DOCS/evolcore/trigger.md`。
|
|
16
|
+
命令的可选参数很多,但建错 90% 是下面四件事里的一件:**执行类型 / 投递目标 / 边界 / NOOP**。
|
|
17
|
+
|
|
18
|
+
## 一、场景速查(先对号入座)
|
|
19
|
+
|
|
20
|
+
| 用户这么说 | 该怎么建 |
|
|
21
|
+
|---|---|
|
|
22
|
+
| "明天早上 9 点提醒我带合同" | 一次 `--at` 或单次 cron,**trigger-session**,投递到用户的会话 |
|
|
23
|
+
| "以后每天 9 点给我出昨日总结" | `--cron '0 9 * * *' --tz Asia/Shanghai`,**trigger-session**,投递用户会话 |
|
|
24
|
+
| "帮我把这个任务跟到底,对方回了我马上告诉我" | 跨话题委托时用 `msg send --check-every`,**不要自建 trigger**(见 thread-ops) |
|
|
25
|
+
| "每 30 分钟看一眼升级有没有新版本" | `--every 30m`,**trigger-session**,提示词写"无变化只输出 `[[NOOP]]`",加 `--max-runs` |
|
|
26
|
+
| "任务失败就自动继续 / 出错误告诉我" | `--event 'task:error'` 或 `--event 'message:received' --event-filter ...` |
|
|
27
|
+
| "帮我盯着这个会话,闲下来时看看有没有漏掉的事" | 这是会话 loop,`/loop 300`(事件 `session:idle`),**不是**普通 trigger |
|
|
28
|
+
| "这个 trigger 改成立刻跑一次试试" | `ec trigger run <id>`;只验证模板用 `--dry-run` |
|
|
29
|
+
| "不要了 / 停掉" | 不再需要就 `ec trigger delete <id>`;只是暂缓用 `disable` |
|
|
30
|
+
|
|
31
|
+
**先问自己一句**:这件事要一个**全新的模型上下文**去做(巡检、判断、生成摘要),还是
|
|
32
|
+
交给用户**当前那个会话**去做(在已有对话里追问、看上下文才能判断)?答案决定执行类型。
|
|
33
|
+
|
|
34
|
+
## 二、执行类型(选错最常见)
|
|
35
|
+
|
|
36
|
+
| 类型 | 谁在执行 | 用在哪 | 坑 |
|
|
37
|
+
|---|---|---|---|
|
|
38
|
+
| `trigger-session` | daemon 专属的 trigger 会话,**与用户对话隔离** | 周期巡检、生成摘要、独立判断。默认同 trigger 复用一条会话 | 只有它支持 `--baseagent`;`--trigger-thread per-run` 每次都开新会话 |
|
|
39
|
+
| `target-session` | 把提示词**当成一条消息**投进目标会话,由那个会话的 agent 处理 | 要在用户的对话里、带着上下文做的事;跨话题复查(`--check-every`) | 不支持 `feedback=silent`;目标会话被占用会等/冲突;也**不支持** `execution.thread` |
|
|
40
|
+
| `script` | 确定性脚本,不过模型 | 只看数、查文件、调 IPC、算东西——**不需要模型判断**时优先用,又快又便宜 | 走沙箱,脚本不能读受保护路径;宿主执行要求独立批准 |
|
|
41
|
+
|
|
42
|
+
**结论**:用户要"看到结果"→ 让结果落在**用户会话**(trigger-session + target feedback,
|
|
43
|
+
或 target-session)。用户要"有人替我去做判断"→ trigger-session。脚本能做的别用模型。
|
|
44
|
+
|
|
45
|
+
## 三、投递目标:结果落在哪
|
|
46
|
+
|
|
47
|
+
`feedback.strategy` 三个可用值:
|
|
48
|
+
|
|
49
|
+
- **`target`** — 送到 `--target-*` 指定的会话。**最常用**。
|
|
50
|
+
- **`origin`** — 送回创建它的那条会话。在某个话题里建、想回到该话题,用这个(比手写 target 稳)。
|
|
51
|
+
- **`silent`** — 不投递结果,只做副作用(只用于 `trigger-session` / `script`)。
|
|
52
|
+
|
|
53
|
+
单聊最省事的写法(AUN):
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
ec trigger create --cron '0 9 * * *' --tz Asia/Shanghai \
|
|
57
|
+
--exec trigger-session \
|
|
58
|
+
--prompt '生成昨日要点,直接输出结论' \
|
|
59
|
+
--target-channel aun --target-channel-id <用户AID> --target-chat-type private \
|
|
60
|
+
--target-session main --name daily-brief --enable
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
- `--target-channel aun` 是简写,保存时自动展开成 `aun#<自己AID>#main`。
|
|
64
|
+
- `--target-session main` = 用户的主会话;`thread --target-thread-id <threadId>` = 指定话题。
|
|
65
|
+
- **群聊**:`--target-channel-id` 填**群 AID**,`--target-chat-type group`。
|
|
66
|
+
- 其他渠道(飞书/微信等)要写完整 channelKey,不能写 `aun`。
|
|
67
|
+
- **目标会话不存在时会就地新建一个**,不会报错——建完一定要 `show --json` 看 `feedback.target`
|
|
68
|
+
是不是你以为的那条会话。
|
|
69
|
+
|
|
70
|
+
## 四、必须做的四件事
|
|
71
|
+
|
|
72
|
+
1. **边界**:短期跟进的周期 trigger 加 `--max-runs` 或 `--max-duration`。到上限自动 `disable`
|
|
73
|
+
(定义留着、可查),不会删。无限周期的巡检只留给用户明确要求"一直跑"的场景。
|
|
74
|
+
2. **NOOP**:周期任务有"没事可报"的情况,提示词里写死"无异常时**只输出** `[[NOOP]]`"。
|
|
75
|
+
**整段输出必须恰好是 `[[NOOP]]`**(前后不能有其它文字,结尾换行没关系),否则结果照样
|
|
76
|
+
投递,模型还会额外对着用户说一圈废话。
|
|
77
|
+
3. **复核**:建完立刻 `ec trigger show <id> --json` 看三样:`enabled`、`feedback.target`、
|
|
78
|
+
`schedule.nextFireAt`(cron 看得到下次触发时刻;与预期不符就是时区/表达式问题)。
|
|
79
|
+
改定义一律带 `--if-revision <show 返回的 revision>`,改完再看 revision 变了没有。
|
|
80
|
+
4. **收尾**:任务线结束 → `ec trigger delete <id>`。不要用 `disable/cancel` 留尸体——
|
|
81
|
+
定义和调度状态都会留在磁盘上,越积越多。删除后历史审计仍在(`ec trigger history`)。
|
|
82
|
+
|
|
83
|
+
## 五、反直觉的语义(文档没写透的)
|
|
84
|
+
|
|
85
|
+
- **cron 从"创建那一刻"起算下一次**:17:41 建 `0 */2 * * *`,下次是 19:00,不是 18:00。
|
|
86
|
+
- **一次性来源自动关**:`--once` / `--delay` / `--at` 跑完一轮自动 `disable`,定义保留。
|
|
87
|
+
- **错过的时间点合并**:默认 `missedPolicy=run_once`,daemon 停机期间错过的几次只补跑一次。
|
|
88
|
+
- **并发**:默认 `forbid`——同一会话正被另一个 run 占用时,**后到的直接被 skip**;
|
|
89
|
+
只有 `replace` 才会掐掉前一个。别以为"排队等"。queue 里塞着的多个 target-session
|
|
90
|
+
trigger 是**串行**的,每个都要等前面跑完。
|
|
91
|
+
- **投递失败只重发结果,不重跑任务**:`effects` 里才是真实投递记录;状态 `failed` 不代表
|
|
92
|
+
用户没收到。排查时看 `history` 里的 `effects`。
|
|
93
|
+
- **你被 trigger 唤醒时**:信封里的 `触发于:` 是排定时刻(firedAt),不是唤醒时刻;
|
|
94
|
+
proactive 模式下正文流式输出会被丢弃,**回复必须走 `ec ctl send`**;`[[NOOP]]` 仍适用,
|
|
95
|
+
只用它、别在它前后多说一句。
|
|
96
|
+
- **提示词里能用的变量**:`{{trigger.name}}`、`{{run.number}}`(第几次)、`{{run.elapsed}}`、
|
|
97
|
+
`{{date}}`、`{{time}}`,事件触发另有 `{{event.<字段>}}`。提示词正文走同一套渲染。
|
|
98
|
+
- **每次创建都是新 trigger**:重复建同一个提醒会得到多个 trigger,各自都会触发。先 `list` 查。
|
|
99
|
+
- **列表默认只显示 enabled**:排查"怎么没有"要 `ec trigger list --all`。
|
|
100
|
+
|
|
101
|
+
## 六、常用命令
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
ec trigger list [--all] [--json]
|
|
105
|
+
ec trigger show <id> [--json] # revision、nextFireAt、recentRuns、subscription
|
|
106
|
+
ec trigger history [<id>] [--limit 50] # created/updated/disabled/deleted + 每次 run 终态
|
|
107
|
+
ec trigger update <id> --cron '...' --if-revision <rev>
|
|
108
|
+
ec trigger enable|disable|delete <id>
|
|
109
|
+
ec trigger run <id> [--dry-run] # 手动跑一次;--dry-run 不执行真实副作用
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
**定位用 id(`trig_...`)不用名称**。只有 `once/delay/at/cron/every/event` 六种来源,互斥。
|
|
113
|
+
|
|
114
|
+
## 七、事件触发
|
|
115
|
+
|
|
116
|
+
`--event` 支持精确名、命名空间前缀(`task:*`)、全量(`*`),配 `--event-filter` 按字段过滤。
|
|
117
|
+
常用:`message:received`、`task:completed`、`task:error`、`session:idle`、`permission:requested`、
|
|
118
|
+
`runner:model-changed`。
|
|
119
|
+
|
|
120
|
+
- `trigger:*` 是**内部事件**,普通 trigger 订阅不了。
|
|
121
|
+
- 监听 `*` 必须配 filter,否则每次模型输出都会触发。
|
|
122
|
+
- 订阅前查 `$KITS_DOCS/evolcore/event.md` 的事件目录;文末"不存在或已移除的事件"表里的名字
|
|
123
|
+
一律不要用(写出来的 trigger 会永远不触发)。
|
|
124
|
+
- **脚本的 `files` 字段不会真的发文件**:要发文件在脚本正文或提示词里给出路径。
|
|
125
|
+
|
|
126
|
+
示例:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
ec trigger create --event 'task:error' \
|
|
130
|
+
--exec trigger-session \
|
|
131
|
+
--prompt '诊断这次失败,给出原因和下一步;无需处理只输出 [[NOOP]]' \
|
|
132
|
+
--target-channel aun --target-channel-id <用户AID> --target-chat-type private \
|
|
133
|
+
--target-session main --name task-error-watch --enable
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## 八、不要做
|
|
137
|
+
|
|
138
|
+
1. 不用 trigger 代替当前会话里立刻能做的事。
|
|
139
|
+
2. **默认**不给无上限的周期任务;用户明说长期跑,或任务本身长期有效(如每日简报)才可省略,
|
|
140
|
+
并在建之前说明"这条会一直跑到被删"。
|
|
141
|
+
3. 不在提示词里写主动发消息的命令(`ec msg send` / `ec ctl send`)——结果会被**再投递一次**,
|
|
142
|
+
用户收到两遍。让模型只产出正文。
|
|
143
|
+
4. 不用 `--agent` 去操作别的 agent 的 trigger(托管会话里很容易被拒)。
|
|
144
|
+
5. 不直接读 `trigger.json`、`scripts/*`、`data/`、`AIDs/` 这类受保护路径——沙箱按 H 类拦截,
|
|
145
|
+
脚本会直接启动失败。
|
|
146
|
+
6. 提示词超过 4096 字符用 `--prompt-file`,不要硬塞。
|
|
147
|
+
7. 群聊里不要用 `--mention` 去 @ 人做提醒——`ec group send` 和 trigger 提示词不共享参数;
|
|
148
|
+
要在群里点名,写进目标会话的提示词里,或让 target-session 在群里自己 @。
|
|
149
|
+
|
|
150
|
+
## 九、排查手册
|
|
151
|
+
|
|
152
|
+
| 现象 | 先查 | 常见原因 |
|
|
153
|
+
|---|---|---|
|
|
154
|
+
| 根本没触发 | `show --json` 的 `nextFireAt`、`recentRuns`;`list --all` | 被 disable、cron 表达式/时区错、一次性已跑完、上限已命中 |
|
|
155
|
+
| 触发了但没送到 | `history` 的 `effects` / `feedback` | target 路由写错、AUN 缺 chatType、渠道未配置 |
|
|
156
|
+
| 发到了错的会话 | `show --json` 的 `feedback.target` / `origin` | 在话题里建但用了 target、目标会话不存在被新建 |
|
|
157
|
+
| 用户收到一堆废话 | run 状态 `completed` 但内容很啰嗦 | `[[NOOP]]` 没独占整段输出 |
|
|
158
|
+
| 每次跑很久/堆任务 | `show --json` 的 `active`;`history` | 周期比执行时间短,queue 串行排队;concurrency 设为 forbid |
|
|
159
|
+
| 脚本报沙箱不可用 | 脚本路径/项目路径 | 受保护路径,或宿主未准备沙箱 |
|
|
160
|
+
| 手动跑有效、定时没效 | `history` 时间线 | 错过策略、daemon 停机、时区 |
|
|
161
|
+
|
|
162
|
+
## 参考资料
|
|
163
|
+
|
|
164
|
+
- `$KITS_DOCS/evolcore/trigger.md` — 完整参数与 Trigger V3.1 JSON 定义(建复杂 trigger 前读)
|
|
165
|
+
- `$KITS_DOCS/evolcore/event.md` — 事件目录与过滤语法
|
|
166
|
+
- `$KITS/skills/thread-ops/SKILL.md` — 跨话题复查(`--check-every`)的正确用法
|
|
167
|
+
- `$KITS/skills/ec-trigger/references/examples.md` — 可直接改用的 JSON 定义:每日简报、错误告警、闲置巡检、定时发文件
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Trigger 定义样例(Trigger V3.1)
|
|
2
|
+
|
|
3
|
+
复杂 trigger 用 JSON 导入,CLI flag 覆盖不了的字段(`origin` / `silent` feedback /
|
|
4
|
+
分支模板 / `event filter`)只能走这里:
|
|
5
|
+
|
|
6
|
+
```bash
|
|
7
|
+
ec trigger create --exec <script|trigger-session|target-session> --file ./trigger.json --enable
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
`--exec` 必须与 JSON 里的 `execution.type` 一致。`<aid>` 换成自己的 AID。
|
|
11
|
+
|
|
12
|
+
## 1. 每日简报(trigger-session → 用户会话)
|
|
13
|
+
|
|
14
|
+
```json
|
|
15
|
+
{
|
|
16
|
+
"$schema_version": 3.1,
|
|
17
|
+
"agentAid": "<aid>",
|
|
18
|
+
"enabled": true,
|
|
19
|
+
"name": "daily-brief",
|
|
20
|
+
"source": { "type": "cron", "expression": "0 9 * * *", "timezone": "Asia/Shanghai" },
|
|
21
|
+
"execution": {
|
|
22
|
+
"type": "trigger_session",
|
|
23
|
+
"prompt": "生成昨日要点:3-5 条,直接给结论,不要寒暄。",
|
|
24
|
+
"permissionMode": "readonly",
|
|
25
|
+
"onError": "retry",
|
|
26
|
+
"noopSentinel": "[[NOOP]]"
|
|
27
|
+
},
|
|
28
|
+
"feedback": {
|
|
29
|
+
"strategy": "target",
|
|
30
|
+
"target": { "channelKey": "aun", "channelId": "<用户AID>", "chatType": "private", "session": "main" }
|
|
31
|
+
},
|
|
32
|
+
"reliability": { "concurrency": "forbid", "missedPolicy": "run_once", "retry": { "maxAttempts": 1, "backoffMs": 30000 } }
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## 2. 错误告警(事件 → 原会话,链式恢复的简化版)
|
|
37
|
+
|
|
38
|
+
```json
|
|
39
|
+
{
|
|
40
|
+
"$schema_version": 3.1,
|
|
41
|
+
"agentAid": "<aid>",
|
|
42
|
+
"enabled": true,
|
|
43
|
+
"name": "task-error-watch",
|
|
44
|
+
"source": {
|
|
45
|
+
"type": "event",
|
|
46
|
+
"eventPattern": "task:error",
|
|
47
|
+
"filter": { "match": { "agentAid": "<aid>", "originTriggerId": { "$exists": false } } }
|
|
48
|
+
},
|
|
49
|
+
"execution": {
|
|
50
|
+
"type": "target_session",
|
|
51
|
+
"prompt": "本次任务失败。给出原因与下一步;无需告知用户时只输出 [[NOOP]]。",
|
|
52
|
+
"onError": "retry",
|
|
53
|
+
"noopSentinel": "[[NOOP]]"
|
|
54
|
+
},
|
|
55
|
+
"feedback": {
|
|
56
|
+
"strategy": "target",
|
|
57
|
+
"target": { "channelKey": "aun", "channelId": "<用户AID>", "chatType": "private", "session": "main" }
|
|
58
|
+
},
|
|
59
|
+
"reliability": { "concurrency": "forbid", "missedPolicy": "run_once", "retry": { "maxAttempts": 2, "backoffMs": 30000 } }
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
> `originTriggerId: {$exists: false}` 用来排除"自己触发的错误"造成的递归。
|
|
64
|
+
> 需要"失败后自动恢复原会话"时不要仿写,直接用系统自带的 `__task-recovery`。
|
|
65
|
+
|
|
66
|
+
## 3. 闲置巡检(session:idle → 原会话)
|
|
67
|
+
|
|
68
|
+
```json
|
|
69
|
+
{
|
|
70
|
+
"$schema_version": 3.1,
|
|
71
|
+
"agentAid": "<aid>",
|
|
72
|
+
"enabled": true,
|
|
73
|
+
"name": "idle-check",
|
|
74
|
+
"source": {
|
|
75
|
+
"type": "event",
|
|
76
|
+
"eventPattern": "session:idle",
|
|
77
|
+
"filter": { "match": { "chatType": { "$in": ["private", "group"] } } }
|
|
78
|
+
},
|
|
79
|
+
"execution": {
|
|
80
|
+
"type": "target_session",
|
|
81
|
+
"prompt": "本会话已闲置。检查有没有未完成却停滞的事项;有就在职责内推进或提醒一次,没有只输出 [[NOOP]]。",
|
|
82
|
+
"onError": "retry",
|
|
83
|
+
"noopSentinel": "[[NOOP]]"
|
|
84
|
+
},
|
|
85
|
+
"feedback": { "strategy": "event_session" },
|
|
86
|
+
"reliability": { "concurrency": "forbid", "missedPolicy": "run_once", "retry": { "maxAttempts": 2, "backoffMs": 30000 } }
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
- `session:idle` 只对**打开了会话 loop 的会话**发出:`/loop 300`(主会话)或
|
|
91
|
+
`/loop 300`(话题会话,配置存在该会话上)。秒数范围 30–86400,默认 300。
|
|
92
|
+
- `event_session` 会把事件里的 `sessionId` 解析回原会话,**不会**退化为普通消息投递;
|
|
93
|
+
找不到就失败关闭。
|
|
94
|
+
- 系统自带的 `__session-idle-check` 已经是这个形状,`/loop` 要求它处于 enabled。
|
|
95
|
+
|
|
96
|
+
## 4. 定时给群里发一份文件(script → 群)
|
|
97
|
+
|
|
98
|
+
脚本在 trigger 目录内,Windows 上非 owner 的脚本要走沙箱(独立批准),普通场景优先
|
|
99
|
+
trigger-session 生成正文后由目标会话自己发文件:
|
|
100
|
+
|
|
101
|
+
```json
|
|
102
|
+
{
|
|
103
|
+
"$schema_version": 3.1,
|
|
104
|
+
"agentAid": "<aid>",
|
|
105
|
+
"enabled": true,
|
|
106
|
+
"name": "weekly-report",
|
|
107
|
+
"source": { "type": "cron", "expression": "0 10 * * 1", "timezone": "Asia/Shanghai" },
|
|
108
|
+
"execution": {
|
|
109
|
+
"type": "trigger_session",
|
|
110
|
+
"prompt": "生成本周周报(Markdown),写到 <项目目录>/reports/weekly.md,然后把文件路径和一句话摘要输出。",
|
|
111
|
+
"permissionMode": "auto",
|
|
112
|
+
"onError": "retry",
|
|
113
|
+
"noopSentinel": "[[NOOP]]"
|
|
114
|
+
},
|
|
115
|
+
"feedback": {
|
|
116
|
+
"strategy": "target",
|
|
117
|
+
"target": { "channelKey": "aun", "channelId": "<群AID>", "chatType": "group", "session": "main" }
|
|
118
|
+
},
|
|
119
|
+
"limits": { "maxRuns": 12 },
|
|
120
|
+
"reliability": { "concurrency": "forbid", "missedPolicy": "run_once", "retry": { "maxAttempts": 1, "backoffMs": 30000 } }
|
|
121
|
+
}
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
- 脚本的 `files` 字段**不会**自动发文件,要发就把路径交给目标会话。
|
|
125
|
+
- `limits` 命中后自动 disable,不会删定义。
|
|
126
|
+
|
|
127
|
+
## 5. 静默 script(只做副作用,不打扰用户)
|
|
128
|
+
|
|
129
|
+
```json
|
|
130
|
+
{
|
|
131
|
+
"$schema_version": 3.1,
|
|
132
|
+
"agentAid": "<aid>",
|
|
133
|
+
"enabled": true,
|
|
134
|
+
"name": "clean-tmp",
|
|
135
|
+
"source": { "type": "cron", "expression": "30 3 * * *", "timezone": "Asia/Shanghai" },
|
|
136
|
+
"execution": {
|
|
137
|
+
"type": "script",
|
|
138
|
+
"script": { "path": "clean.cjs", "runtime": "node", "timeoutMs": 60000 },
|
|
139
|
+
"onError": "fail",
|
|
140
|
+
"noopSentinel": "[[NOOP]]"
|
|
141
|
+
},
|
|
142
|
+
"feedback": { "strategy": "silent" },
|
|
143
|
+
"reliability": { "concurrency": "forbid", "missedPolicy": "run_once", "retry": { "maxAttempts": 0, "backoffMs": 30000 } }
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## 6. 跨话题复查(只有懂这个形状才手写)
|
|
148
|
+
|
|
149
|
+
正常用 `ec msg send '...' --thread <T2> --check-every 5m` 生成,不要手写。要点:
|
|
150
|
+
|
|
151
|
+
- `labels.kind = "cross-thread-review"` 决定投递身份取**目标话题自身**的对端,而不是来源对端。
|
|
152
|
+
- 只支持 `target_session`,`feedback.target.session = "thread"` 且带 `threadId`。
|
|
153
|
+
- 结束复查一律 `ec trigger delete`,积压的复查 trigger 会持续唤醒目标话题。
|