evolcore 0.0.26 → 0.0.28
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 +36 -0
- package/bin/codex-managed-acl.ps1 +43 -0
- package/dist/agents/baseagent-availability.js +68 -0
- package/dist/agents/baseagent.js +10 -5
- package/dist/agents/claude-runner.js +123 -22
- package/dist/agents/codex/app-server-client.js +70 -26
- package/dist/agents/codex/catalog.js +7 -1
- package/dist/agents/codex-runner.js +363 -421
- package/dist/agents/ecagent-runner.js +170 -25
- package/dist/agents/gemini-runner.js +6 -0
- package/dist/agents/runner-types.js +50 -2
- package/dist/aun/aid/agentmd.js +73 -31
- package/dist/aun/aid/client.js +1 -1
- package/dist/aun/aid/control-aid.js +180 -1
- package/dist/aun/aid/identity.js +3 -3
- package/dist/aun/group/history.js +303 -0
- package/dist/aun/group/identity.js +43 -0
- package/dist/aun/group/index.js +5 -0
- package/dist/aun/{msg/group.js → group/operations.js} +161 -38
- package/dist/aun/{menu-client.js → menu/client.js} +13 -7
- package/dist/aun/menu/index.js +2 -0
- package/dist/aun/menu/transport.js +49 -0
- package/dist/aun/msg/index.js +2 -1
- package/dist/aun/msg/managed-operation.js +84 -18
- package/dist/aun/msg/mention-schema.js +51 -0
- package/dist/aun/msg/p2p.js +13 -8
- package/dist/aun/msg/upload.js +43 -88
- package/dist/aun/outbox.js +29 -7
- package/dist/aun/rpc/client.js +1 -0
- package/dist/aun/storage/client.js +39 -50
- package/dist/channels/aun.js +544 -239
- package/dist/channels/daemon.js +10 -6
- package/dist/cli/agent-command.js +108 -6
- package/dist/cli/agent-create.js +515 -2
- package/dist/cli/agent.js +109 -8
- package/dist/cli/aun-commands.js +191 -42
- package/dist/cli/config.js +8 -5
- package/dist/cli/contact.js +2 -2
- package/dist/cli/ctl-command.js +2 -2
- package/dist/cli/daemon-commands.js +111 -162
- package/dist/cli/diag.js +3 -3
- package/dist/cli/fs-command.js +3 -3
- package/dist/cli/handoff-command.js +6 -6
- package/dist/cli/index.js +8 -2
- package/dist/cli/init.js +34 -1
- package/dist/cli/managed-command-guard.js +2 -1
- package/dist/cli/menu-client.js +13 -5
- package/dist/cli/model.js +3 -3
- package/dist/cli/queue-command.js +2 -2
- package/dist/cli/response.js +2 -2
- package/dist/cli/restart-monitor.js +81 -19
- package/dist/cli/task-command.js +59 -0
- package/dist/cli/task-context.js +97 -49
- package/dist/cli/trigger-command.js +20 -10
- package/dist/config/builtin-roles.js +10 -0
- package/dist/config/config-field-policy.js +11 -0
- package/dist/config/config-manager.js +32 -4
- package/dist/config/config-operation-service.js +20 -5
- package/dist/config/contact-book-store.js +1 -1
- package/dist/config/contact-book.js +1 -1
- package/dist/config/contact-operation-service.js +1 -1
- package/dist/config/peer-role-resolver.js +1 -1
- package/dist/config/resolved-config-op.js +3 -0
- package/dist/config-store.js +1 -1
- package/dist/core/agent-application-service.js +5 -0
- package/dist/core/audit/event-key.js +17 -2
- package/dist/core/audit/log-integrity.js +34 -8
- package/dist/core/auth/agent-delegation.js +48 -14
- package/dist/core/auth/auth-gateway.js +2 -0
- package/dist/core/auth/authorization-audit.js +34 -38
- package/dist/core/auth/operation-authorizer.js +67 -5
- package/dist/core/auth/operation-catalog.js +110 -0
- package/dist/core/auth/remote-access-store.js +115 -9
- package/dist/core/bootstrap-messages.js +66 -7
- package/dist/core/bootstrap-service.js +110 -19
- package/dist/core/command/agent-control.js +88 -7
- package/dist/core/command/agent-storage-menu.js +443 -0
- package/dist/core/command/cli-intent-parser.js +19 -0
- package/dist/core/command/command-handler.js +105 -40
- package/dist/core/command/data-root-resolver.js +273 -0
- package/dist/core/command/diag-service.js +292 -27
- package/dist/core/command/group-menu.js +7 -2
- package/dist/core/command/menu-catalog.js +34 -4
- package/dist/core/command/menu-handler.js +364 -96
- package/dist/core/command/menu-protocol.js +43 -6
- package/dist/core/command/role-menu.js +2 -2
- package/dist/core/command/slash-handler.js +61 -37
- package/dist/core/event-catalog.js +4 -0
- package/dist/core/evolagent-registry.js +28 -2
- package/dist/core/group/invite-service.js +924 -0
- package/dist/core/interaction-router.js +22 -8
- package/dist/core/message/im-renderer.js +94 -16
- package/dist/core/message/message-bridge.js +140 -13
- package/dist/core/message/message-log.js +5 -3
- package/dist/core/message/message-queue.js +73 -41
- package/dist/core/message/response-engine.js +729 -118
- package/dist/core/permission/approval-gateway.js +36 -3
- package/dist/core/permission/ec-command-parser.js +76 -36
- package/dist/core/permission/protected-paths.js +134 -16
- package/dist/core/permission/sandbox-runtime.js +72 -3
- package/dist/core/permission/tool-error-code.js +15 -0
- package/dist/core/permission/tool-policy.js +8 -8
- package/dist/core/relation/peer-identity.js +57 -6
- package/dist/core/relation/shared-data.js +106 -0
- package/dist/core/role/runtime-policy.js +64 -0
- package/dist/core/runtime-lock.js +10 -26
- package/dist/core/session/runner-task-history.js +170 -0
- package/dist/core/session/session-manager.js +38 -6
- package/dist/core/session/session-mapper.js +41 -0
- package/dist/core/session/session-turn-coordinator.js +37 -7
- package/dist/core/session/session-turns.js +48 -7
- package/dist/core/task/task-recovery-service.js +176 -0
- package/dist/core/task/task-resume-operation.js +32 -0
- package/dist/eck/group-rules-sync.js +5 -3
- package/dist/eck/kit-renderer.js +1 -0
- package/dist/index.js +322 -207
- package/dist/ipc.js +141 -15
- package/dist/paths.js +17 -4
- package/dist/product.js +3 -0
- package/dist/trigger/event-source.js +19 -0
- package/dist/trigger/feedback.js +233 -40
- package/dist/trigger/parser.js +55 -5
- package/dist/trigger/patch.js +9 -0
- package/dist/trigger/scheduler.js +30 -4
- package/dist/trigger/validation.js +20 -3
- package/dist/utils/atomic-write.js +98 -0
- package/dist/utils/cross-platform.js +87 -16
- package/dist/utils/ecweb-utils.js +1 -0
- package/dist/utils/error-utils.js +40 -2
- package/dist/utils/logger.js +23 -13
- package/dist/utils/npm-ops.js +119 -4
- package/dist/utils/package-version-info.js +244 -0
- package/dist/utils/tool-summary.js +59 -3
- package/dist/utils/welcome.js +174 -1
- package/dist/utils/windows-shell-trust.js +37 -0
- package/ecagent/dist/harness/agent-harness.js +3 -0
- package/ecagent/dist/harness/session/jsonl-storage.js +21 -2
- package/kits/docs/INDEX.md +0 -6
- package/kits/docs/channels/aun.md +23 -2
- package/kits/docs/channels/feishu.md +1 -1
- package/kits/docs/context-assembly.md +29 -17
- package/kits/docs/evolcore/INDEX.md +8 -3
- package/kits/docs/evolcore/agent-create.md +39 -7
- package/kits/docs/evolcore/agent.md +33 -1
- package/kits/docs/evolcore/aid.md +9 -1
- package/kits/docs/evolcore/config.md +40 -1
- package/kits/docs/evolcore/group-collaboration.md +1 -1
- package/kits/docs/evolcore/group.md +117 -2
- package/kits/docs/evolcore/menu-client.md +16 -0
- package/kits/docs/evolcore/msg.md +3 -0
- package/kits/docs/evolcore/storage.md +3 -0
- package/kits/docs/evolcore/task.md +14 -0
- package/kits/docs/evolcore/trigger.md +51 -3
- package/kits/docs/venues/group.md +5 -0
- package/kits/eck_manifest.json +27 -0
- package/kits/rules/01-overview.md +11 -7
- package/kits/rules/04-relation.md +2 -1
- package/kits/rules/05-venue.md +1 -1
- package/kits/rules/06-channel.md +6 -4
- package/kits/schemas/agent-config.schema.12.json +25 -1
- package/kits/schemas/daemon.schema.6.json +2 -2
- package/kits/schemas/defaults.schema.5.json +1 -1
- package/kits/schemas/relation-config.schema.1.json +1 -1
- package/kits/schemas/relation-config.schema.5.json +1 -1
- package/kits/schemas/role-config.schema.1.json +14 -0
- package/kits/templates/roles/member.json +5 -0
- package/kits/templates/roles/visitor.json +5 -0
- package/kits/templates/system-fragments/baseagent.md +1 -1
- package/kits/templates/system-fragments/bootstrap.md +26 -9
- package/kits/templates/system-fragments/channel.md +8 -44
- package/kits/templates/system-fragments/commands.md +10 -2
- package/kits/templates/system-fragments/group-unread-history.md +7 -0
- package/kits/templates/system-fragments/reply.md +56 -0
- package/package.json +7 -3
- package/dist/aun/group-identity.js +0 -9
- /package/dist/aun/{group-fs-download.js → group/fs-download.js} +0 -0
- /package/dist/aun/{msg/group-index.js → group/index-rpc.js} +0 -0
package/dist/utils/welcome.js
CHANGED
|
@@ -8,10 +8,154 @@
|
|
|
8
8
|
* - 所有 IM 渠道(Feishu/WeChat/DingTalk/QQBot/WeCom):首次交互时发送给交互用户(被动响应)
|
|
9
9
|
*/
|
|
10
10
|
import fs from 'fs';
|
|
11
|
-
import
|
|
11
|
+
import path from 'path';
|
|
12
|
+
import { createHash } from 'crypto';
|
|
13
|
+
import { parseDocument } from 'yaml';
|
|
14
|
+
import { agentWelcomePath, channelStatePath, resolveRoot } from '../paths.js';
|
|
15
|
+
import { isValidAid } from '../aun/aid/validation.js';
|
|
12
16
|
import { loadAgent, saveAgent } from '../config-store.js';
|
|
13
17
|
import { resolveAgentLifecycle, withLifecycleForWrite } from '../config/lifecycle.js';
|
|
18
|
+
import { renderTemplate } from '../eck/manifest-engine.js';
|
|
19
|
+
import { atomicWriteText } from './atomic-write.js';
|
|
14
20
|
import { logger } from './logger.js';
|
|
21
|
+
export const MAX_WELCOME_TEMPLATE_BYTES = 4 * 1024;
|
|
22
|
+
export const MAX_RENDERED_WELCOME_BYTES = 8 * 1024;
|
|
23
|
+
const WELCOME_TEMPLATE_VARS = new Set([
|
|
24
|
+
'agentName', 'agentDescription', 'agentAid', 'agentTags', 'agentTagsText',
|
|
25
|
+
'ownerName', 'ownerAid', 'channel',
|
|
26
|
+
]);
|
|
27
|
+
/** Validate the small, data-only template language used by Bootstrap welcome text. */
|
|
28
|
+
export function validateWelcomeTemplate(template) {
|
|
29
|
+
const errors = [];
|
|
30
|
+
if (typeof template !== 'string' || !template.trim()) {
|
|
31
|
+
return { valid: false, errors: ['welcome template must be non-empty'] };
|
|
32
|
+
}
|
|
33
|
+
if (template.includes('\0') || Buffer.from(template, 'utf8').toString('utf8') !== template) {
|
|
34
|
+
errors.push('welcome template must contain valid UTF-8 text only');
|
|
35
|
+
}
|
|
36
|
+
if (Buffer.byteLength(template, 'utf8') > MAX_WELCOME_TEMPLATE_BYTES) {
|
|
37
|
+
return { valid: false, errors: [`welcome template must be at most ${MAX_WELCOME_TEMPLATE_BYTES} bytes`] };
|
|
38
|
+
}
|
|
39
|
+
const stack = [];
|
|
40
|
+
const tokenPattern = /\{\{|\}\}/g;
|
|
41
|
+
let match;
|
|
42
|
+
while ((match = tokenPattern.exec(template)) !== null) {
|
|
43
|
+
const end = template.indexOf('}}', tokenPattern.lastIndex);
|
|
44
|
+
if (match[0] !== '{{' || end < 0) {
|
|
45
|
+
errors.push('unmatched template delimiter');
|
|
46
|
+
break;
|
|
47
|
+
}
|
|
48
|
+
const token = template.slice(tokenPattern.lastIndex, end);
|
|
49
|
+
tokenPattern.lastIndex = end + 2;
|
|
50
|
+
if (token === '#each agentTags') {
|
|
51
|
+
if (stack.includes('each'))
|
|
52
|
+
errors.push('nested tag loops are not supported');
|
|
53
|
+
stack.push('each');
|
|
54
|
+
}
|
|
55
|
+
else if (token === '/each' || token === '/') {
|
|
56
|
+
const expected = token === '/each' ? 'each' : 'condition';
|
|
57
|
+
if (stack.pop() !== expected)
|
|
58
|
+
errors.push(`unexpected {{${token}}}`);
|
|
59
|
+
}
|
|
60
|
+
else if (/^\?\w+$/.test(token) && WELCOME_TEMPLATE_VARS.has(token.slice(1))) {
|
|
61
|
+
stack.push('condition');
|
|
62
|
+
}
|
|
63
|
+
else if ((token === '.' || token === '@index') && stack.includes('each')) {
|
|
64
|
+
// Loop-local variables are valid only inside the tag loop.
|
|
65
|
+
}
|
|
66
|
+
else if (!WELCOME_TEMPLATE_VARS.has(token)) {
|
|
67
|
+
errors.push(`unsupported template variable or block: ${token}`);
|
|
68
|
+
}
|
|
69
|
+
if (stack.length > 8) {
|
|
70
|
+
errors.push('template blocks are nested too deeply');
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
if (stack.includes('each'))
|
|
75
|
+
errors.push('unclosed {{#each}} block');
|
|
76
|
+
if (stack.includes('condition'))
|
|
77
|
+
errors.push('unclosed condition block');
|
|
78
|
+
return { valid: errors.length === 0, errors };
|
|
79
|
+
}
|
|
80
|
+
function checkedWelcomePath(aid) {
|
|
81
|
+
if (!isValidAid(aid))
|
|
82
|
+
throw new Error('invalid Agent AID');
|
|
83
|
+
const target = agentWelcomePath(aid);
|
|
84
|
+
const root = path.resolve(resolveRoot());
|
|
85
|
+
for (let cursor = path.resolve(target); cursor !== root; cursor = path.dirname(cursor)) {
|
|
86
|
+
try {
|
|
87
|
+
if (fs.lstatSync(cursor).isSymbolicLink())
|
|
88
|
+
throw new Error('welcome path must not contain symbolic links');
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
if (error.code !== 'ENOENT')
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return target;
|
|
96
|
+
}
|
|
97
|
+
export function saveAgentWelcomeTemplate(aid, template) {
|
|
98
|
+
const validation = validateWelcomeTemplate(template);
|
|
99
|
+
if (!validation.valid)
|
|
100
|
+
throw new Error(`invalid welcome template: ${validation.errors.join('; ')}`);
|
|
101
|
+
const target = checkedWelcomePath(aid);
|
|
102
|
+
const staging = target + '.tmp.' + process.pid;
|
|
103
|
+
try {
|
|
104
|
+
if (fs.lstatSync(staging).isSymbolicLink())
|
|
105
|
+
throw new Error('invalid welcome staging path');
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
if (error.code !== 'ENOENT')
|
|
109
|
+
throw error;
|
|
110
|
+
}
|
|
111
|
+
try {
|
|
112
|
+
atomicWriteText(target, template);
|
|
113
|
+
}
|
|
114
|
+
finally {
|
|
115
|
+
fs.rmSync(staging, { force: true });
|
|
116
|
+
}
|
|
117
|
+
return { path: target, bytes: Buffer.byteLength(template, 'utf8'), sha256: createHash('sha256').update(template).digest('hex') };
|
|
118
|
+
}
|
|
119
|
+
export function readAgentWelcomeTemplate(aid) {
|
|
120
|
+
const target = checkedWelcomePath(aid);
|
|
121
|
+
let stat;
|
|
122
|
+
try {
|
|
123
|
+
stat = fs.lstatSync(target);
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
if (error.code === 'ENOENT')
|
|
127
|
+
return null;
|
|
128
|
+
throw error;
|
|
129
|
+
}
|
|
130
|
+
if (!stat.isFile() || stat.size > MAX_WELCOME_TEMPLATE_BYTES)
|
|
131
|
+
throw new Error('invalid welcome template file');
|
|
132
|
+
const template = new TextDecoder('utf-8', { fatal: true, ignoreBOM: true }).decode(fs.readFileSync(target));
|
|
133
|
+
const validation = validateWelcomeTemplate(template);
|
|
134
|
+
if (!validation.valid)
|
|
135
|
+
throw new Error(`invalid welcome template at ${target}: ${validation.errors.join('; ')}`);
|
|
136
|
+
return template;
|
|
137
|
+
}
|
|
138
|
+
export function parseAgentWelcomeMetadata(content) {
|
|
139
|
+
const frontmatter = content.match(/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/)?.[1];
|
|
140
|
+
if (!frontmatter)
|
|
141
|
+
return { tags: [] };
|
|
142
|
+
try {
|
|
143
|
+
const document = parseDocument(frontmatter);
|
|
144
|
+
if (document.errors.length)
|
|
145
|
+
return { tags: [] };
|
|
146
|
+
const value = document.toJS();
|
|
147
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
148
|
+
return { tags: [] };
|
|
149
|
+
return {
|
|
150
|
+
name: typeof value.name === 'string' ? value.name.trim() : undefined,
|
|
151
|
+
description: typeof value.description === 'string' ? value.description.trim() : undefined,
|
|
152
|
+
tags: Array.isArray(value.tags) ? value.tags.filter((tag) => typeof tag === 'string').map(tag => tag.trim()) : [],
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
catch {
|
|
156
|
+
return { tags: [] };
|
|
157
|
+
}
|
|
158
|
+
}
|
|
15
159
|
// ============================================================================
|
|
16
160
|
// 欢迎消息生成
|
|
17
161
|
// ============================================================================
|
|
@@ -50,6 +194,35 @@ ${agentIntro}${channelInfo}
|
|
|
50
194
|
|
|
51
195
|
现在就可以开始工作了!`;
|
|
52
196
|
}
|
|
197
|
+
export function renderPostBootstrapWelcomeMessage(options) {
|
|
198
|
+
const validation = validateWelcomeTemplate(options.template);
|
|
199
|
+
if (!validation.valid)
|
|
200
|
+
throw new Error(`invalid welcome template: ${validation.errors.join('; ')}`);
|
|
201
|
+
// ECK renders loop bodies recursively. Mask data so names/descriptions containing
|
|
202
|
+
// template syntax remain literal even when inserted inside a loop or condition.
|
|
203
|
+
const values = [];
|
|
204
|
+
const literal = (value) => {
|
|
205
|
+
if (!value)
|
|
206
|
+
return '';
|
|
207
|
+
values.push(value);
|
|
208
|
+
return `\0WELCOME${values.length - 1}\0`;
|
|
209
|
+
};
|
|
210
|
+
const rendered = renderTemplate(options.template, {
|
|
211
|
+
agentName: literal(options.agentName),
|
|
212
|
+
agentDescription: literal(options.agentDescription),
|
|
213
|
+
agentAid: literal(options.agentAid),
|
|
214
|
+
agentTags: (options.agentTags ?? []).map(literal),
|
|
215
|
+
agentTagsText: literal((options.agentTags ?? []).join(', ')),
|
|
216
|
+
ownerName: literal(options.ownerName),
|
|
217
|
+
ownerAid: literal(options.ownerAid),
|
|
218
|
+
channel: literal('aun'),
|
|
219
|
+
}, false).replace(/\0WELCOME(\d+)\0/g, (_match, index) => values[Number(index)]);
|
|
220
|
+
if (!rendered.trim())
|
|
221
|
+
throw new Error('welcome template rendered to an empty message');
|
|
222
|
+
if (Buffer.byteLength(rendered, 'utf8') > MAX_RENDERED_WELCOME_BYTES)
|
|
223
|
+
throw new Error('rendered welcome exceeds 8192 bytes');
|
|
224
|
+
return rendered;
|
|
225
|
+
}
|
|
53
226
|
/**
|
|
54
227
|
* 生成简化版欢迎消息(用于快速场景)
|
|
55
228
|
*/
|
|
@@ -36,6 +36,10 @@ export function isTrustedShellSignature(kind, evidence) {
|
|
|
36
36
|
function windowsSystemRoot() {
|
|
37
37
|
return process.env.SystemRoot || process.env.WINDIR || 'C:\\Windows';
|
|
38
38
|
}
|
|
39
|
+
/** Return the only cmd.exe that EvolCore is willing to use as a shell carrier. */
|
|
40
|
+
export function windowsSystemCmdPath() {
|
|
41
|
+
return path.win32.join(windowsSystemRoot(), 'System32', 'cmd.exe');
|
|
42
|
+
}
|
|
39
43
|
function systemPowerShellPath() {
|
|
40
44
|
return path.win32.join(windowsSystemRoot(), 'System32', 'WindowsPowerShell', 'v1.0', 'powershell.exe');
|
|
41
45
|
}
|
|
@@ -195,6 +199,39 @@ export function isTrustedWindowsShellExecutable(executable, kind) {
|
|
|
195
199
|
}
|
|
196
200
|
return trusted;
|
|
197
201
|
}
|
|
202
|
+
/**
|
|
203
|
+
* Resolve an inherited ComSpec to the system cmd.exe and authenticate it.
|
|
204
|
+
* npm shims are not signed Microsoft binaries, so this helper intentionally
|
|
205
|
+
* validates only the interpreter and never the `.cmd`/`.bat` target.
|
|
206
|
+
*/
|
|
207
|
+
export function resolveTrustedWindowsCmdPath(comSpec) {
|
|
208
|
+
if (process.platform !== 'win32')
|
|
209
|
+
return comSpec || 'cmd.exe';
|
|
210
|
+
const systemCmd = windowsSystemCmdPath();
|
|
211
|
+
const candidate = (comSpec || process.env.ComSpec || process.env.COMSPEC || systemCmd).trim();
|
|
212
|
+
if (!candidate)
|
|
213
|
+
return undefined;
|
|
214
|
+
let candidatePath = candidate;
|
|
215
|
+
if (!isAbsoluteWindowsPath(candidatePath)) {
|
|
216
|
+
if (/^cmd(?:\.exe)?$/i.test(candidatePath))
|
|
217
|
+
candidatePath = systemCmd;
|
|
218
|
+
else
|
|
219
|
+
return undefined;
|
|
220
|
+
}
|
|
221
|
+
let candidateReal;
|
|
222
|
+
let systemReal;
|
|
223
|
+
try {
|
|
224
|
+
candidateReal = fs.realpathSync.native(candidatePath);
|
|
225
|
+
systemReal = fs.realpathSync.native(systemCmd);
|
|
226
|
+
}
|
|
227
|
+
catch {
|
|
228
|
+
return undefined;
|
|
229
|
+
}
|
|
230
|
+
if (path.win32.normalize(candidateReal).toLowerCase() !== path.win32.normalize(systemReal).toLowerCase()) {
|
|
231
|
+
return undefined;
|
|
232
|
+
}
|
|
233
|
+
return isTrustedWindowsShellExecutable(systemReal, 'cmd') ? systemReal : undefined;
|
|
234
|
+
}
|
|
198
235
|
/** Test hook: clear cached signature decisions after a fixture is replaced. */
|
|
199
236
|
export function clearWindowsShellTrustCache() {
|
|
200
237
|
signatureCache.clear();
|
|
@@ -412,6 +412,9 @@ export class AgentHarness {
|
|
|
412
412
|
}
|
|
413
413
|
async handleAgentEvent(event, signal) {
|
|
414
414
|
if (event.type === "message_end") {
|
|
415
|
+
// Persist the same multimodal message that was sent to the provider.
|
|
416
|
+
// Provider rollouts (Claude/Codex) retain image bytes in their own
|
|
417
|
+
// session files, so ecagent must do the same for resumable context.
|
|
415
418
|
await this.session.appendMessage(event.message);
|
|
416
419
|
await this.emitAny(event, signal);
|
|
417
420
|
return;
|
|
@@ -1,6 +1,25 @@
|
|
|
1
1
|
import { SessionError, toError } from "../types.js";
|
|
2
2
|
import { getFileSystemResultOrThrow } from "./repo-utils.js";
|
|
3
3
|
import { uuidv7 } from "./uuid.js";
|
|
4
|
+
// Multiple harness instances can briefly reference the same session during a
|
|
5
|
+
// replacement turn. Node's appendFile does not guarantee that large writes
|
|
6
|
+
// from separate calls stay contiguous, so serialize appends per physical file.
|
|
7
|
+
const appendQueues = new Map();
|
|
8
|
+
async function appendSerialized(fs, filePath, content) {
|
|
9
|
+
const previous = appendQueues.get(filePath) ?? Promise.resolve();
|
|
10
|
+
let release;
|
|
11
|
+
const current = new Promise((resolve) => { release = resolve; });
|
|
12
|
+
appendQueues.set(filePath, current);
|
|
13
|
+
try {
|
|
14
|
+
await previous.catch(() => undefined);
|
|
15
|
+
getFileSystemResultOrThrow(await fs.appendFile(filePath, content), `Failed to append session entry ${filePath}`);
|
|
16
|
+
}
|
|
17
|
+
finally {
|
|
18
|
+
release();
|
|
19
|
+
if (appendQueues.get(filePath) === current)
|
|
20
|
+
appendQueues.delete(filePath);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
4
23
|
function updateLabelCache(labelsById, entry) {
|
|
5
24
|
if (entry.type !== "label")
|
|
6
25
|
return;
|
|
@@ -185,7 +204,7 @@ export class JsonlSessionStorage {
|
|
|
185
204
|
timestamp: new Date().toISOString(),
|
|
186
205
|
targetId: leafId,
|
|
187
206
|
};
|
|
188
|
-
|
|
207
|
+
await appendSerialized(this.fs, this.filePath, `${JSON.stringify(entry)}\n`);
|
|
189
208
|
this.entries.push(entry);
|
|
190
209
|
this.byId.set(entry.id, entry);
|
|
191
210
|
this.currentLeafId = leafId;
|
|
@@ -194,7 +213,7 @@ export class JsonlSessionStorage {
|
|
|
194
213
|
return generateEntryId(this.byId);
|
|
195
214
|
}
|
|
196
215
|
async appendEntry(entry) {
|
|
197
|
-
|
|
216
|
+
await appendSerialized(this.fs, this.filePath, `${JSON.stringify(entry)}\n`);
|
|
198
217
|
this.entries.push(entry);
|
|
199
218
|
this.byId.set(entry.id, entry);
|
|
200
219
|
updateLabelCache(this.labelsById, entry);
|
package/kits/docs/INDEX.md
CHANGED
|
@@ -58,9 +58,3 @@
|
|
|
58
58
|
| 路径注册表模板 | `eck_templates/path-registry.template.md` | 路径实例模板 |
|
|
59
59
|
| 索引模板 | `eck_templates/INDEX.template.md` | agent 级索引模板 |
|
|
60
60
|
| 指南模板 | `eck_templates/GUIDE.template.md` | agent 级查阅指南模板 |
|
|
61
|
-
|
|
62
|
-
## Base Agent
|
|
63
|
-
|
|
64
|
-
| 文档 | 路径 | 说明 |
|
|
65
|
-
|------|------|------|
|
|
66
|
-
| Claude Code 日志 | `baseagent/cc-logs.md` | CC 会话日志查阅(找完整对话/工具调用/注入) |
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# AUN 渠道
|
|
2
2
|
|
|
3
3
|
> 知识性文档:AUN 渠道的配置、参数与特有机制。**不依赖当前会话渠道**——任意会话都可按需 Read。
|
|
4
|
-
>
|
|
4
|
+
> 运行时回复方式由共用 `[reply]` 段按实际 chatMode 决定;active 的 `[channel]` 补充文件、链接、@ 等能力。AUN 主动发送使用托管的 `ec msg send` / `ec group send`。
|
|
5
5
|
> 群聊使用 `evolcore/group.md`;群文件使用 `evolcore/fs.md`。
|
|
6
6
|
|
|
7
7
|
## 概述
|
|
@@ -51,6 +51,27 @@ AUN keystore seed 由 EvolCore 使用固定应用值管理,不再提供配置
|
|
|
51
51
|
- 关系层另存一份**派生**的精简身份 `relations/<peerKey>/peer-identity.json`(type/isAgent/name),由 evolcore 从 agent.md 提取,不是 agent.md 本体。
|
|
52
52
|
- **E2EE 加密**:可选端到端加密,回复默认跟随对端消息加密状态(密文回密文,明文回明文);keystore seed 由 EvolCore 固定管理。
|
|
53
53
|
- **断线重连**:SDK 内置退避策略自动重连。实时连接状态用 `ec watch aid` 查看(`ec aid` 是身份/证书管理,不显示连接状态)。
|
|
54
|
-
- **群 ID
|
|
54
|
+
- **群 ID 格式**:使用 `{base}.{issuer}`,如 `ontology.agentid.cn` 或 `g-12345.agentid.cn`。EvolCore 默认创建 `g-` 加五位数字(10000–99999)的名称,issuer 以群服务返回为准。群命令支持 base 简写;不再支持或转换 `group.{issuer}/{base}`,也不支持 `base@issuer`。`g-` 是名称的一部分,不应剥离,也不能仅凭群 AID 的格式判断主体类型。
|
|
55
55
|
- **群 @ 处理策略**:`mention_mode=disabled|mention-only` 是群级配置,只决定哪些群消息进入 Agent LLM 上下文,不影响 AUN 协议层投递;被过滤消息仍应本地存档。
|
|
56
56
|
- **身份体系**:对端以 AID 标识,关系层 peerKey 形如 `aun#alice.aid.pub`。
|
|
57
|
+
|
|
58
|
+
### 私聊最终回复标题
|
|
59
|
+
|
|
60
|
+
AUN 私聊中,`result.text` 的 `isFinal=true` 会在 `payload.text` 正文前添加 `✅ 最终回复:`。AUN 文本客户端按正文展示,标题随 outbox 上下文持久化,断线恢复发送时仍保留。群聊、中间文本、命令回执及错误消息不自动添加该标题。
|
|
61
|
+
|
|
62
|
+
Interactive 私聊的最终正文保留到本轮结束后统一发送,避免定时 flush 提前当作中间文本发出。Codex 明确标记的 commentary 可按原定时窗口发送;没有阶段标记的正文等到下一文本块、工具调用或本轮结束后确定发送方式。标题和正文之间留一个空行,正文已经以同一标题开头时不重复添加,也不额外发送 `payload.title`。
|
|
63
|
+
|
|
64
|
+
标题仅表示最终回复的展示信息,任务完成或失败仍由 `task.status` 表达。
|
|
65
|
+
|
|
66
|
+
### 出站关注状态
|
|
67
|
+
|
|
68
|
+
AUN runner 状态和 action card 可携带顶层 `attention`,值只能是以下四种之一:
|
|
69
|
+
|
|
70
|
+
| 值 | 语义 |
|
|
71
|
+
|---|---|
|
|
72
|
+
| `completed` | 正常终态,任务已完成并交付结果 |
|
|
73
|
+
| `failed` | 异常终态,任务无法继续完成 |
|
|
74
|
+
| `required` | 需要人处理,例如授权确认或补充输入 |
|
|
75
|
+
| `interrupted` | runner 被用户、新消息或基础设施中断 |
|
|
76
|
+
|
|
77
|
+
普通持久化业务消息(含最终文本、错误正文、Activity、命令回执)不携带 `terminal` 或 `attention`。`task.status` 的 completed/error/timeout/interrupted 成对携带终态字段,requires_action 携带 `false/required`,其他过程状态两字段都省略。所有 action card 固定携带 `terminal:false` 和 `attention:"required"`;卡片投递本身不会创建 runner 等待状态。可恢复 system.error 投影为 `notice + severity:warn`。线上值按类型和状态统一生成,显式旧值不覆盖该规则。
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# 飞书渠道
|
|
2
2
|
|
|
3
3
|
> 知识性文档:飞书渠道的配置、参数与特有机制。**不依赖当前会话渠道**——任意会话都可按需 Read(在 aun 会话里也可查飞书)。
|
|
4
|
-
>
|
|
4
|
+
> 运行时回复方式由共用 `[reply]` 段按实际 chatMode 决定:interactive 由 evolcore 自动投递普通输出,proactive 用 `ec ctl send` 正式回复;active 的 `[channel]` 补充文件等能力。
|
|
5
5
|
|
|
6
6
|
## 概述
|
|
7
7
|
|
|
@@ -263,6 +263,7 @@ vars 由 evolcore 在 `message-processor.ts` 按当前会话构造。分两类
|
|
|
263
263
|
| `chatType` | `private` / `group` / `null`(coding) |
|
|
264
264
|
| `channel` | 渠道类型(aun/feishu/...)|
|
|
265
265
|
| `mentionMode` | 群 @ 处理模式(mention-only/disabled) |
|
|
266
|
+
| `groupHistoryAvailable` | 当前 AUN 群是否允许读取本地群历史 |
|
|
266
267
|
| `clientType` | 客户端类型(desktop/web/mobile) |
|
|
267
268
|
| `permissionMode` / `readonly` | 权限模式 / 是否只读 |
|
|
268
269
|
| `capabilities` | 当前渠道能力(图片输入/输出、文件发送) |
|
|
@@ -285,25 +286,36 @@ coding 场景(无 channel/无身份)下,`chatType`、`channel`、`selfAid`
|
|
|
285
286
|
|
|
286
287
|
## 默认 manifest 的段(按 order)
|
|
287
288
|
|
|
289
|
+
常规段均要求 `lifecycle=active`,下表的其它条件在此基础上叠加;Bootstrap 引导与共用回复段单独列出完整条件。
|
|
290
|
+
|
|
288
291
|
| order | id | 类型 | 加载条件(when) | inject |
|
|
289
292
|
|-------|----|----|------------------|--------|
|
|
290
|
-
| 10 | rules | 目录 `$KITS_RULES` |
|
|
291
|
-
|
|
|
292
|
-
|
|
|
293
|
-
| 21
|
|
294
|
-
|
|
|
295
|
-
|
|
|
296
|
-
|
|
|
297
|
-
|
|
|
298
|
-
|
|
|
299
|
-
|
|
|
300
|
-
|
|
|
301
|
-
|
|
|
302
|
-
|
|
|
303
|
-
|
|
|
304
|
-
|
|
|
305
|
-
|
|
306
|
-
|
|
293
|
+
| 10 | rules | 目录 `$KITS_RULES` | active | ✗ |
|
|
294
|
+
| 15 | bootstrap-guide | `bootstrap.md` | lifecycle=bootstrapping | ✓ |
|
|
295
|
+
| 20 | identity-layer | fragment | active 且 chatType≠null | ✓ |
|
|
296
|
+
| 21 | persona | `$PERSONAL_DIR/persona.md` | active 且 chatType≠null | ✗ |
|
|
297
|
+
| 21.5 | personal-profile | `$PERSONAL_DIR/personal.md` | active 且 chatType≠null | ✗ |
|
|
298
|
+
| 22 | working-memory | `$PERSONAL_DIR/memory/working.md` | active 且 chatType≠null | ✗ |
|
|
299
|
+
| 23 | preferences | `$PERSONAL_DIR/preferences/active-preferences.md` | active 且 chatType=private | ✗ |
|
|
300
|
+
| 30 | relation-layer | fragment | active 且 chatType∈{private,group} | ✓ |
|
|
301
|
+
| 35 | peer-profile | `$RELATIONS_DIR/{{peerKey}}/profile.md` | active 且 peerKey≠null | ✗ |
|
|
302
|
+
| 40 | venue-fragment | fragment | active 且 chatType≠null | ✓ |
|
|
303
|
+
| 41 | venue-chattype | `$KITS_DOCS/venues/{{chatType}}.md` | active 且 chatType≠null | ✗ |
|
|
304
|
+
| 42 | venue-channel-chattype | `$KITS_DOCS/venues/{{channel}}-{{chatType}}.md` | active 且 chatType≠null | ✗ |
|
|
305
|
+
| 43.2 | relation-group-rules | `$RELATIONS_DIR/{{peerKey}}/rules.md` | active 且 groupRulesPath≠null | ✗ |
|
|
306
|
+
| 44 | venue-client | `$KITS_DOCS/venues/client-{{clientType}}.md` | active 且 clientType≠null | ✗ |
|
|
307
|
+
| 49 | reply-contract | `reply.md` | channel≠null 且 lifecycle∈{active,bootstrapping} | ✓ |
|
|
308
|
+
| 50 | channel-layer | fragment | active 且 channel≠null | ✓ |
|
|
309
|
+
| 55 | commands | fragment | active 且 channel≠null | ✓ |
|
|
310
|
+
| 60 | session | fragment | active | ✓ |
|
|
311
|
+
| 70 | baseagent | fragment | active 且 baseAgent≠null | ✓ |
|
|
312
|
+
|
|
313
|
+
Bootstrap 只加载引导与有渠道时的最小通信上下文 `[reply]`,不加载完整身份/关系/渠道能力、个人记忆或普通任务命令。
|
|
314
|
+
`[reply]` 展示 selfAid、peerId、peerType、channel、chatType、chatMode;未知身份显示 unknown,回复方式只取运行时已解析的 chatMode,不从身份或私聊场景重新推断。命令经当前会话 delegated sender / daemon IPC 发送,遵守现有身份、目标、话题与加密约束。
|
|
315
|
+
`needsInjection` 仅是是否进行模板渲染的布尔开关,不是变量白名单;上述变量原本已存在于运行时 vars。
|
|
316
|
+
|
|
317
|
+
`session` 与 `baseagent` 不依赖 chatType,因此 active 的 coding 场景仍命中 rules + session + baseagent;无渠道时不加载共用回复段。
|
|
318
|
+
生命周期缺失兼容 active;created 与显式非法生命周期不命中主 manifest 的引导、回复或常规段。
|
|
307
319
|
|
|
308
320
|
## 环境层文档目录结构
|
|
309
321
|
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
注入一张精简能力卡,指向本目录下对应文档;需要完整用法时 Read 对应文档。
|
|
6
6
|
|
|
7
7
|
> 对外通信命令以自己的 AID 为发送者;当前渠道是否需要 CLI 回复,以运行时注入的
|
|
8
|
-
> `channel`
|
|
8
|
+
> `[reply]` 规则为准,active 的 `[channel]` 补充扩展能力。参数不是全局通用的:`--format json` 仅用于对应帮助中明确支持的命令,
|
|
9
9
|
> `--app <name>` 仅用于消息 pull/ack、消费类 RPC 和明确支持 app slot 的文件操作。
|
|
10
10
|
|
|
11
11
|
## 如何使用本索引
|
|
@@ -14,12 +14,14 @@
|
|
|
14
14
|
2. **不确定有没有命令**时,直接 `ec <猜测的子命令> --help` 试一下(如 `ec stats --help`)
|
|
15
15
|
3. **已知场景需求**(如"要给对端发消息")→ 看下方分类表 → 定位到对应命令集
|
|
16
16
|
|
|
17
|
+
托管 Agent 任务禁止调用 `ec start`、`ec stop`、`ec restart` 或 `ec restart-monitor`。这些进程生命周期命令只能由宿主终端执行;源码改动后 Agent 只应完成构建并报告需要宿主重启。
|
|
18
|
+
|
|
17
19
|
## 服务运维类(本地,无需 AUN)
|
|
18
20
|
|
|
19
21
|
| 命令 | 用途 | 触发词 |
|
|
20
22
|
|------|------|--------|
|
|
21
23
|
| `ec --version` / `-v` / `-V` | 查看版本号 | 版本 |
|
|
22
|
-
| `ec restart` |
|
|
24
|
+
| `ec restart` | 宿主终端重启服务(托管 Agent 禁止调用) | 重启 |
|
|
23
25
|
| `ec status` | 查看运行状态、进程、会话、渠道连接 | 状态/查看状态 |
|
|
24
26
|
| `ec logs` | 查看日志(`--level` `--module` `--raw` `--no-color`) | 日志/查看日志 |
|
|
25
27
|
| `ec diagnose` | 诊断启动环境 | 诊断/环境诊断 |
|
|
@@ -31,9 +33,11 @@ Windows 上 Codex 托管任务出现 `helper_sandbox_lock_failed`、`SetNamedSec
|
|
|
31
33
|
| 命令集 | 用途 | 触发词 | 适用场景 | 文档 |
|
|
32
34
|
|--------|------|--------|----------|------|
|
|
33
35
|
| `ec msg` | 私聊收发消息 | 回复/发消息/拉取/撤回/查在线 | 有对端(peerId) | `msg.md` |
|
|
34
|
-
| `ec group` | 群聊收发与群管理 |
|
|
36
|
+
| `ec group` | 群聊收发与群管理 | 群发/建群/本地群历史/邀请/踢人/退群/群成员/角色/封禁/屏蔽/成员状态/规则/协作 | 群聊(groupId) | `group.md`;完整协作流程见 `group-collaboration.md` |
|
|
37
|
+
| `/invites` / `ec group invites` | 收到群邀请、Owner 卡片审核与恢复 | 入群邀请/接受邀请/拒绝邀请/审核卡片/待处理邀请 | 当前 Agent Owner 的 AUN 私聊 | `group.md` |
|
|
35
38
|
| `ec group rules` | 群规则文件发布与上下文注入 | 群规则/工作流程/职责分工/rules.md/发布规则 | AUN 群聊(groupId) | `group-rules.md` |
|
|
36
39
|
| `ec aid` | AID 身份管理 | 身份/证书/名片/探测对端 | 任意有渠道场景 | `aid.md` |
|
|
40
|
+
| `ec aid` | AID 身份、名片与头像管理 | 身份/证书/名片/头像/换头像/探测对端 | 任意有渠道场景 | `aid.md` |
|
|
37
41
|
| `ec fs` | AUN 文件系统统一入口 | 上传/下载/看文件/列目录/删文件/配额/群空间 | 任意有渠道场景 | `fs.md` |
|
|
38
42
|
| `ec storage` | 文件存储底层调试入口 | storage 调试/旧命令/底层上传下载 | 任意有渠道场景 | `storage.md` |
|
|
39
43
|
| `ec agent` | EvolAgent 生命周期 | 创建/启停/热重载/改配置 | 管理员(owner/admin) | `agent.md`;完整创建与 Bootstrap 见 `agent-create.md` |
|
|
@@ -57,6 +61,7 @@ Windows 上 Codex 托管任务出现 `helper_sandbox_lock_failed`、`SetNamedSec
|
|
|
57
61
|
| `ec stats` | Token 用量与费用统计 | 用量/费用/统计/预算/token/cost | `stats.md` |
|
|
58
62
|
| `ec trigger` | 定时与事件触发器管理(创建用 `create`,`set` 为兼容别名) | 触发器/定时任务/cron/提醒/定时检查/自动执行/巡检/禁用 trigger/删除 trigger | `trigger.md` |
|
|
59
63
|
| `ec trigger event` | EventBus 事件目录 | 事件触发/事件目录/EventBus/source.type=event/filter.match | `event.md` |
|
|
64
|
+
| `ec task` | 恢复暂停或异常中断的会话任务 | 任务恢复/异常中断/继续任务/resume | `task.md` |
|
|
60
65
|
|
|
61
66
|
## 开发者工具(非 agent 会话能力)
|
|
62
67
|
|
|
@@ -27,6 +27,25 @@ active
|
|
|
27
27
|
|
|
28
28
|
## 1. 创建者创建 Agent
|
|
29
29
|
|
|
30
|
+
### 一次性初始化模式
|
|
31
|
+
|
|
32
|
+
如果创建者已经明确确认最终名片字段和人格,可以使用 `--initialize` 一次完成创建与激活:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
ec agent new helper.agentid.pub --initialize \
|
|
36
|
+
--project /home/user/helper-project --baseagent codex \
|
|
37
|
+
--owner owner.agentid.pub --name "Helper" \
|
|
38
|
+
--description "协助处理项目开发任务" \
|
|
39
|
+
--tags '["coding","maintenance","typescript"]' \
|
|
40
|
+
--persona-file /home/user/helper-project/persona.md
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
`--initialize` 自动包含 `--non-interactive`。它要求 `name`、`description`、`tags` 和 Owner 显式提供,由 daemon 写入 persona、签名发布最终 `agent.md`、热加载并完成欢迎消息及 lifecycle `active`。它不启动目标 Agent 的确认对话,也不要求创建者成为新 Agent 的 Owner。默认等待 60 秒,可用 `--wait 0..300` 调整;超时返回可查询的初始化操作,不代表失败。
|
|
44
|
+
|
|
45
|
+
初始化期间不处理目标 Agent 的普通入站消息。初始化失败或 daemon 重启后,使用 `ec agent initialize <aid> --resume` 恢复原操作;不要重复 `new` 或使用 `--force` 覆盖。`ec agent show <aid>` 会显示初始化阶段、错误和下一步,但不会暴露 persona 正文。
|
|
46
|
+
|
|
47
|
+
没有得到创建者明确最终字段时,继续使用下方的普通非交互式创建,让目标 Agent 自己完成 Bootstrap。
|
|
48
|
+
|
|
30
49
|
多个 Agent 必须串行创建和观察。不要并行启动多个 `ec agent new`:证书、热加载和 Bootstrap 会竞争连接与资源,容易造成超时、锁等待或把失败误判为未创建。
|
|
31
50
|
|
|
32
51
|
在人类直接创建时,可以使用交互模式:
|
|
@@ -85,7 +104,7 @@ ec agent show helper.agentid.pub
|
|
|
85
104
|
|
|
86
105
|
部分 channel 不能在连接时主动定位 Owner。这种情况下 Agent 会保持 `created`;Owner 需要先在该 channel 向新 Agent 发送一条消息,系统获得回复上下文后再启动 Bootstrap。
|
|
87
106
|
|
|
88
|
-
`created` 状态下 Base Agent 不处理普通消息。`bootstrapping`
|
|
107
|
+
`created` 状态下 Base Agent 不处理普通消息。`bootstrapping` 状态下加载 Bootstrap 专属提示词与有渠道时的 `[reply]` 最小通信上下文,不加载正常的 ECK 规则、人格、记忆、完整渠道能力或命令能力卡。回复方式遵循实际 chatMode,不根据 Owner 是人类还是 AI 推断。
|
|
89
108
|
|
|
90
109
|
## 3. Owner 与新 Agent 确认名片信息
|
|
91
110
|
|
|
@@ -115,7 +134,7 @@ ec agent show helper.agentid.pub
|
|
|
115
134
|
|
|
116
135
|
Bootstrap 完成前,新 Agent 不处理普通任务,也不执行与本流程无关的工具或命令。如果 Owner 要求跳过、先工作或同时交办普通任务,新 Agent 应说明必须先完成首次设定,并继续确认缺失字段。
|
|
117
136
|
|
|
118
|
-
## 4. 新 Agent
|
|
137
|
+
## 4. 新 Agent 修改自己的 agent.md
|
|
119
138
|
|
|
120
139
|
Owner 明确确认最终值后,新 Agent 才能编辑系统提示词中 `agentMdPath` 指向的本地文件,并且:
|
|
121
140
|
|
|
@@ -123,15 +142,27 @@ Owner 明确确认最终值后,新 Agent 才能编辑系统提示词中 `agent
|
|
|
123
142
|
- 保留其他 frontmatter 字段、Markdown 正文和文件结构。
|
|
124
143
|
- 修改后检查 YAML 合法,且三个字段满足上述格式要求。
|
|
125
144
|
|
|
126
|
-
|
|
145
|
+
## 5. 生成并确认 Bootstrap Welcome
|
|
146
|
+
|
|
147
|
+
名片字段确认后,新 Agent 在当前 Bootstrap 对话中直接输出完整的个性化 welcome 文案,并请求 Owner 明确确认。
|
|
148
|
+
Owner 要求修改时,重新输出完整文案并再次确认;未确认的文本不写入文件,也不创建草稿。Owner 明确确认后执行:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
ec agent welcome --text '<最后展示且确认的完整文案>'
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
该命令固定保存到 `$PERSONAL_DIR/welcome.md`。保存成功后才能继续发布名片和执行 `ready`。如果 Bootstrap 会话在确认前中断,下一次继续时重新生成并确认。
|
|
155
|
+
|
|
156
|
+
随后由新 Agent 使用自己的 AID 签名并发布名片:
|
|
127
157
|
|
|
128
158
|
```bash
|
|
129
159
|
ec aid agentmd put helper.agentid.pub
|
|
130
160
|
```
|
|
131
161
|
|
|
132
|
-
|
|
162
|
+
只有命令明确成功后才能继续。发布失败时保留已经确认的 welcome,修正发布问题后续做,不重复生成。
|
|
163
|
+
多 Owner 共用该模板;需要称呼时保留 `{{ownerName}}` / `{{ownerAid}}` 供逐人渲染。投递文本不再追加未确认内容。
|
|
133
164
|
|
|
134
|
-
##
|
|
165
|
+
## 6. 新 Agent 完成 Bootstrap
|
|
135
166
|
|
|
136
167
|
发布成功后,新 Agent 执行整个 Bootstrap 的最后一个操作:
|
|
137
168
|
|
|
@@ -150,7 +181,7 @@ ec agent ready helper.agentid.pub
|
|
|
150
181
|
|
|
151
182
|
新 Agent 在 `ready` 成功后不要从旧 Bootstrap 上下文再输出一段完成说明,也不要继续处理先前夹带的普通任务;后续工作从新主会话开始。
|
|
152
183
|
|
|
153
|
-
##
|
|
184
|
+
## 7. 创建者验收
|
|
154
185
|
|
|
155
186
|
```bash
|
|
156
187
|
ec agent get helper.agentid.pub lifecycle
|
|
@@ -170,9 +201,10 @@ Bootstrap 首条消息只发送给 `owners[0]`;`ready` 成功后,正式欢
|
|
|
170
201
|
- `lifecycle` 为 `active`;`ec agent show` 的 `lifecycle` 字段也必须为 `active`。
|
|
171
202
|
- `agent.md` 已成功签名发布。
|
|
172
203
|
- 本地与远端 `agent.md` 的 `name`、`description`、`tags` 与 Owner 确认值一致;创建流程 skill 必须在发布后复读核验,不以初始上传响应代替。
|
|
204
|
+
- `personal/welcome.md` 是当前 Bootstrap 对话最后展示并经 Owner 确认的全文,未确认文案没有另存草稿。
|
|
173
205
|
- 系统已创建新的主会话并发送正式欢迎消息。
|
|
174
206
|
- 新 Agent 能在新主会话中处理普通任务。
|
|
175
207
|
|
|
176
208
|
如果仍为 `created`,检查 channel 是否已能联系 Owner,必要时由 Owner 主动发送首条消息。如果仍为 `bootstrapping`,回到新 Agent 的 Bootstrap 会话完成字段确认、名片发布和 `ready`,不要由创建者直接绕过引导。
|
|
177
209
|
|
|
178
|
-
|
|
210
|
+
失败重试前必须先执行状态检查:若名片已发布且 welcome 已保存,只续做 `ready`;若 welcome 尚未确认保存,则由新 Agent 在自己的 Bootstrap 对话中补做全文生成和确认。不要重复创建、改名片或发布。仅在确认创建记录不存在且名片未发布时,才重新发起创建。
|
|
@@ -23,6 +23,16 @@ ec agent new <aid> --non-interactive \
|
|
|
23
23
|
[--tags '<json-array>'] \
|
|
24
24
|
[--dry-run] [--force]
|
|
25
25
|
|
|
26
|
+
# 创建并一次性完成首次设定(隐含 --non-interactive)
|
|
27
|
+
ec agent new <aid> --initialize \
|
|
28
|
+
--project <路径> --baseagent <claude|codex|gemini|ecagent> \
|
|
29
|
+
--owner <aid> --name "<显示名>" --description "<text>" \
|
|
30
|
+
--tags '<json-array>' [--persona-file <path> | --persona-text <text>] \
|
|
31
|
+
[--wait <seconds>] [--dry-run]
|
|
32
|
+
|
|
33
|
+
# 恢复一次性初始化
|
|
34
|
+
ec agent initialize <aid> --resume [--wait <seconds>]
|
|
35
|
+
|
|
26
36
|
# 启用 / 停用
|
|
27
37
|
ec agent enable <aid>
|
|
28
38
|
ec agent disable <aid>
|
|
@@ -36,6 +46,10 @@ ec agent persona show
|
|
|
36
46
|
ec agent persona --text <text>
|
|
37
47
|
ec agent persona --file <path>
|
|
38
48
|
|
|
49
|
+
# 读取或保存 Bootstrap 中经 Owner 确认的 welcome 文案
|
|
50
|
+
ec agent welcome show
|
|
51
|
+
ec agent welcome --text '<完整 Markdown 文案>'
|
|
52
|
+
|
|
39
53
|
# 修改 agent.md 显示名称
|
|
40
54
|
ec agent rename <aid> "<name>"
|
|
41
55
|
|
|
@@ -59,8 +73,13 @@ ec agent delete <aid> [--purge]
|
|
|
59
73
|
- `--dry-run` 只输出最终创建计划,不注册 AID、不写配置、不上传 `agent.md`。
|
|
60
74
|
- `--force` 覆盖已有 `config.json`;AID 密钥保留。
|
|
61
75
|
- `--tags` 接受 3 到 6 个标签的 JSON 数组;每个标签只允许 Unicode 字母、数字和连字符(`-`),最长 50 字符。
|
|
76
|
+
- `--initialize` 要求显式提供 `--name`、`--description`、`--tags` 和 Owner;它不从项目元数据推断名片,成功条件是目标 Agent 已进入 `active`。`--initialize` 自动包含 `--non-interactive`,不需要同时填写后者。
|
|
77
|
+
- `--persona-file` / `--persona-text` 可选;两者互斥。初始化失败可用 `ec agent initialize <aid> --resume` 按原计划恢复,不能用普通 `new --force` 覆盖。
|
|
62
78
|
- `ec agent persona show` 读取当前 Agent 的 `$PERSONAL_DIR/persona.md`;`--text` 或 `--file <path>` 可由当前 Agent 的 owner 写入。文件内容限制为 UTF-8 文本,`--file` 仅接受 `.md`/`.txt`。
|
|
79
|
+
- `ec agent welcome --text <text>` 只用于 Bootstrap 中 Owner 已明确确认的完整文案;命令固定写入当前 Agent 的 `$PERSONAL_DIR/welcome.md`,不接受自定义路径,也不保存未确认草稿。`welcome show` 读取该文件。
|
|
80
|
+
- welcome 托管写入要求当前 Agent 私聊 Owner;admin 仅可读。模板上限 4 KiB,渲染上限 8 KiB;变量为 `agentName`、`agentDescription`、`agentAid`、`agentTags`、`agentTagsText`、`ownerName`、`ownerAid`、`channel`,支持标签循环和真值条件。写入保留原始文本,投递不附加额外文案。
|
|
63
81
|
- `agent show <target-aid>` 与 `agent get <target-aid> <key>` 的跨 Agent 读取对 owner/admin 开放,但普通 Agent 角色只获得安全摘要;敏感配置值和物理路径仅对 DaemonOwner 返回原值。跨 Agent 写入、启停、删除和 reload 仍遵循各自的目标与 DaemonOwner 权限边界。
|
|
82
|
+
- Agent 配置可包含 `fullaccess.enabled`(默认关闭),仅可通过已认证的 EC Web Agent 设置修改。该开关受 `daemon.json.fullaccess.enabled` 总开关约束;daemon 关闭时 EC Web 隐藏该设置项。实际运行时,只有同时属于该 AgentOwner 和当前 daemonOwner 的直接私聊任务才会按调用使用宿主级 fullaccess;群聊、普通 Owner、跨 Agent 和 Trigger 不会因该开关自动提权。daemon 总开关也控制 `/fa`、`/fullaccess` 和 Fullaccess Trigger。
|
|
64
83
|
|
|
65
84
|
## 创建 Agent
|
|
66
85
|
|
|
@@ -68,6 +87,19 @@ ec agent delete <aid> [--purge]
|
|
|
68
87
|
|
|
69
88
|
完整的创建、Bootstrap、名片发布和验收示例见:`$KITS_DOCS/evolcore/agent-create.md`。
|
|
70
89
|
|
|
90
|
+
## Bootstrap 通知状态与重试
|
|
91
|
+
|
|
92
|
+
交互式 Bootstrap 的 `ready` 要求有效的 `personal/welcome.md`:缺失返回 `WELCOME_REQUIRED`,损坏返回 `WELCOME_INVALID`,均保持 Bootstrap 状态。已准备 completion outbox 后修改文案返回 `WELCOME_FROZEN`。已有 active Agent 和独立的 `--initialize` 流程不需要补做此确认。
|
|
93
|
+
|
|
94
|
+
`ready` 成功表示 Agent 已进入 `active`;欢迎消息单独返回在 `welcome.deliveries`,每位 Owner 一项:
|
|
95
|
+
|
|
96
|
+
- `sent`:网关已接受,带 `messageId`。后续送达由网关保障。
|
|
97
|
+
- `queued`:已持久化到发件箱,带 `outboxId`;临时故障自动重试,重启后继续恢复。
|
|
98
|
+
- `failed`:永久失败,带错误原因和代码;普通重连或重复 `ready` 不会重新发送。
|
|
99
|
+
- `not_prepared`:没有找到投递记录,不能当作发送成功。
|
|
100
|
+
|
|
101
|
+
24 小时提示窗口从成功发送计算,待发提示不会因超过窗口而被删除。完成引导后取消尚未发送的首次提示。
|
|
102
|
+
|
|
71
103
|
## 头像更新
|
|
72
104
|
|
|
73
105
|
头像上传通过 menu 协议或 `ec aid avatar` 暴露:
|
|
@@ -86,7 +118,7 @@ ec agent delete <aid> [--purge]
|
|
|
86
118
|
|
|
87
119
|
约束:
|
|
88
120
|
- 规范入口使用 `args.data`(data URL)或 `args.url`(HTTPS URL)二选一;控制面可用顶层 `agent` 或 `args.aid` 选择目标,Agent channel 只能修改当前 self AID。
|
|
89
|
-
-
|
|
121
|
+
- 新客户端使用 `name=aid action=avatar`。兼容旧版 App 的 `name=agent action=update` + `args.patch.avatar=<data URL>`:头像必须单独提交,复用相同图片校验、上传和名片发布流程,不写入 config.json,成功后同样发布头像更新事件。`patch.avatar_url` 仍不支持。
|
|
90
122
|
- 支持真实 MIME 为 PNG/JPEG/WebP 的图片;大小不超过 500KB,分辨率为 128–2048 像素,宽高比为 0.8–1.25。
|
|
91
123
|
- 成功后头像上传到该 agent 自己的 AUN storage,`agent.md` frontmatter 写入 AID 风格 URL,并重新签名发布。
|
|
92
124
|
- 托管会话中的 CLI 形式为 `ec aid avatar <当前 self AID> (--file <path> | --url <https-url>)`;仅允许 owner 在 `request`/`bypass` 模式下执行。`--file` 只能从项目目录或当前会话 `$TMPDIR` 读取,`--url` 由 daemon 下载并做 SSRF、重定向和大小校验。
|