evolcore 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +93 -778
- package/README.md +45 -10
- package/bin/ec-safe-output.js +89 -24
- package/dist/agents/baseagent.js +46 -0
- package/dist/agents/claude-runner.js +198 -48
- package/dist/agents/codex-app-server-client.js +68 -0
- package/dist/agents/codex-runner.js +203 -8
- package/dist/agents/runner-types.js +2 -2
- package/dist/aun/aid/agentmd.js +79 -0
- package/dist/aun/aid/encryption-seed-policy.js +29 -0
- package/dist/aun/aid/index.js +1 -1
- package/dist/aun/aid/store.js +2 -5
- package/dist/aun/outbox.js +8 -0
- package/dist/channels/aun.js +241 -116
- package/dist/channels/daemon.js +18 -4
- package/dist/channels/dingtalk.js +1005 -260
- package/dist/channels/feishu.js +184 -56
- package/dist/channels/qqbot.js +23 -1
- package/dist/channels/wechat.js +303 -155
- package/dist/channels/wecom.js +1132 -164
- package/dist/cli/agent-command.js +2 -1
- package/dist/cli/aun-commands.js +98 -43
- package/dist/cli/bench.js +2 -2
- package/dist/cli/contact.js +71 -0
- package/dist/cli/ctl-command.js +2 -2
- package/dist/cli/daemon-commands.js +77 -214
- package/dist/cli/handoff-command.js +4 -3
- package/dist/cli/help.js +9 -5
- package/dist/cli/index.js +132 -116
- package/dist/cli/init-channel.js +242 -129
- package/dist/cli/init.js +70 -31
- package/dist/cli/model.js +2 -1
- package/dist/cli/net-check.js +2 -2
- package/dist/cli/queue-command.js +30 -6
- package/dist/cli/raw-key-input.js +25 -0
- package/dist/cli/response.js +5 -6
- package/dist/cli/restart-monitor.js +25 -1
- package/dist/cli/stats.js +6 -4
- package/dist/cli/trigger-command.js +146 -25
- package/dist/cli/version.js +6 -1
- package/dist/config/access-policy-domain.js +38 -0
- package/dist/config/access-policy.js +134 -0
- package/dist/config/builtin-role-templates.js +42 -17
- package/dist/config/builtin-roles.js +31 -6
- package/dist/config/config-field-policy.js +17 -5
- package/dist/config/config-manager.js +409 -29
- package/dist/config/config-operation-service.js +35 -38
- package/dist/config/contact-alias.js +68 -0
- package/dist/config/contact-bind-code.js +274 -0
- package/dist/config/contact-book-store.js +622 -0
- package/dist/config/contact-book-v2-startup.js +35 -0
- package/dist/config/contact-book.js +185 -300
- package/dist/config/contact-operation-service.js +116 -0
- package/dist/config/contact-request-service.js +331 -0
- package/dist/config/peer-role-resolver.js +136 -55
- package/dist/config/role-ranks.js +18 -0
- package/dist/config/role-service.js +16 -19
- package/dist/config/role-store.js +16 -5
- package/dist/config/roles.js +10 -1
- package/dist/config/schema-registry.js +49 -24
- package/dist/config-store.js +14 -4
- package/dist/core/auth/agent-delegation.js +105 -11
- package/dist/core/auth/authorization-audit.js +16 -1
- package/dist/core/auth/operation-authorizer.js +10 -0
- package/dist/core/auth/operation-catalog.js +105 -1
- package/dist/core/auth/trigger-authorization.js +15 -0
- package/dist/core/bootstrap-service.js +2 -9
- package/dist/core/channel-loader.js +6 -2
- package/dist/core/command/command-handler.js +113 -21
- package/dist/core/command/connect-menu.js +599 -0
- package/dist/core/command/evol-menu-version-gate.js +38 -0
- package/dist/core/command/group-menu.js +421 -0
- package/dist/core/command/menu-handler.js +382 -100
- package/dist/core/command/menu-protocol.js +8 -2
- package/dist/core/command/menu-token-store.js +102 -0
- package/dist/core/command/role-menu.js +128 -29
- package/dist/core/command/slash-gate.js +1 -1
- package/dist/core/command/slash-handler.js +186 -49
- package/dist/core/daemon-file-cache.js +40 -6
- package/dist/core/event-catalog.js +99 -0
- package/dist/core/evolagent-registry.js +4 -40
- package/dist/core/evolagent.js +20 -9
- package/dist/core/handoff/runtime.js +162 -37
- package/dist/core/handoff/store.js +46 -2
- package/dist/core/handoff/types.js +1 -0
- package/dist/core/inference/text-inference.js +16 -74
- package/dist/core/message/file-markers.js +7 -0
- package/dist/core/message/im-renderer.js +20 -14
- package/dist/core/message/inbound-admission.js +124 -0
- package/dist/core/message/message-bridge.js +670 -57
- package/dist/core/message/message-log.js +1 -0
- package/dist/core/message/message-queue.js +195 -10
- package/dist/core/message/message-utils.js +8 -2
- package/dist/core/message/peer-mode.js +7 -8
- package/dist/core/message/response-engine.js +642 -96
- package/dist/core/message/send-receipt.js +24 -0
- package/dist/core/message/stream-debouncer.js +11 -2
- package/dist/core/permission/approval-gateway.js +17 -10
- package/dist/core/permission/ec-command-parser.js +101 -46
- package/dist/core/permission/tool-policy.js +115 -38
- package/dist/core/protected-paths.js +38 -11
- package/dist/core/session/session-fs-store.js +44 -3
- package/dist/core/session/session-manager.js +86 -8
- package/dist/core/session/session-mapper.js +2 -0
- package/dist/core/session/session-renew.js +125 -69
- package/dist/core/session/session-turn-coordinator.js +5 -1
- package/dist/eck/kit-renderer.js +12 -1
- package/dist/eck/message-renderer.js +79 -1
- package/dist/index.js +285 -94
- package/dist/ipc.js +114 -8
- package/dist/paths.js +3 -0
- package/dist/response-system/config-resolver.js +29 -0
- package/dist/response-system/coordinator.js +8 -32
- package/dist/response-system/engines/v1/proactive-flow.js +1 -1
- package/dist/response-system/index.js +1 -0
- package/dist/response-system/modes/single-session/index.js +7 -4
- package/dist/stats/billing.js +20 -8
- package/dist/trigger/manager.js +3 -0
- package/dist/trigger/parser.js +126 -11
- package/dist/trigger/patch.js +12 -2
- package/dist/trigger/scheduler.js +444 -40
- package/dist/trigger/validation.js +13 -0
- package/dist/utils/aid-bind.js +43 -29
- package/dist/utils/error-dict.json +7 -0
- package/dist/utils/evolcore-version.js +21 -0
- package/dist/utils/instance-registry.js +14 -7
- package/dist/utils/log-writer.js +46 -0
- package/dist/utils/logger.js +2 -2
- package/dist/utils/media-cache.js +4 -1
- package/dist/utils/model-prices.jsonl +6 -3
- package/dist/utils/restart-safety.js +31 -0
- package/dist/utils/stable-semver.js +21 -0
- package/dist/utils/stats.js +33 -9
- package/dist/utils/system-memory.js +62 -0
- package/kits/docs/INDEX.md +2 -1
- package/kits/docs/channels/aun.md +4 -13
- package/kits/docs/evolcore/INDEX.md +5 -3
- package/kits/docs/evolcore/agent.md +9 -1
- package/kits/docs/evolcore/aid.md +5 -2
- package/kits/docs/evolcore/config.md +47 -2
- package/kits/docs/evolcore/contact.md +61 -0
- package/kits/docs/evolcore/fs.md +9 -0
- package/kits/docs/evolcore/group-rules.md +46 -4
- package/kits/docs/evolcore/group.md +15 -6
- package/kits/docs/evolcore/model.md +4 -1
- package/kits/docs/evolcore/msg.md +12 -6
- package/kits/docs/evolcore/response.md +16 -21
- package/kits/docs/evolcore/rpc.md +2 -0
- package/kits/docs/evolcore/stats.md +15 -2
- package/kits/docs/evolcore/storage.md +1 -0
- package/kits/docs/evolcore/trigger.md +42 -10
- package/kits/docs/path-registry.md +36 -17
- package/kits/eck_manifest.json +12 -0
- package/kits/eck_message_manifest.json +12 -1
- package/kits/migrations/migrate-contact-book-v2.mjs +754 -0
- package/kits/rules/01-overview.md +17 -7
- package/kits/rules/02-navigation.md +38 -18
- package/kits/rules/03-identity.md +28 -24
- package/kits/rules/04-relation.md +44 -28
- package/kits/rules/05-venue.md +31 -15
- package/kits/rules/06-channel.md +11 -7
- package/kits/schemas/_meta.json +21 -7
- package/kits/schemas/agent-config.schema.6.json +322 -0
- package/kits/schemas/agent-config.schema.7.json +303 -0
- package/kits/schemas/agent-config.schema.8.json +304 -0
- package/kits/schemas/agent-config.schema.9.json +374 -0
- package/kits/schemas/contact-book.schema.2.json +43 -0
- package/kits/schemas/contact-book.schema.3.json +67 -0
- package/kits/schemas/daemon.schema.1.json +3 -2
- package/kits/schemas/daemon.schema.2.json +101 -0
- package/kits/schemas/daemon.schema.3.json +123 -0
- package/kits/schemas/defaults.schema.2.json +85 -0
- package/kits/schemas/defaults.schema.3.json +73 -0
- package/kits/schemas/relation-config.schema.5.json +47 -0
- package/kits/schemas/relation-config.schema.6.json +46 -0
- package/kits/schemas/relation-config.schema.7.json +59 -0
- package/kits/schemas/role-config.schema.1.json +1 -0
- package/kits/schemas/role-registry.schema.1.json +2 -2
- package/kits/schemas/single-session.schema.2.json +57 -0
- package/kits/templates/message-fragments/handoff-context-to-target.md +9 -0
- package/kits/templates/message-fragments/handoff-request-to-target.md +14 -8
- package/kits/templates/message-fragments/handoff-response-to-origin.md +5 -6
- package/kits/templates/roles/admin.json +47 -0
- package/kits/templates/roles/member.json +5 -0
- package/kits/templates/roles/owner.json +1 -0
- package/kits/templates/roles/visitor.json +5 -0
- package/kits/templates/system-fragments/channel.md +12 -2
- package/kits/templates/system-fragments/commands.md +3 -1
- package/kits/templates/system-fragments/identity.md +3 -1
- package/kits/templates/system-fragments/relation.md +1 -1
- package/kits/templates/system-fragments/session.md +6 -2
- package/package.json +7 -5
- package/MIGRATION-0.5.0.md +0 -378
- package/ROLE_ACCESS_CONTROL.md +0 -174
- package/assets/brand/evolcore/README.md +0 -19
- package/assets/brand/evolcore/evolcore-app-icon.png +0 -0
- package/assets/brand/evolcore/evolcore-app-icon.svg +0 -13
- package/assets/brand/evolcore/evolcore-brand-board.png +0 -0
- package/assets/brand/evolcore/evolcore-brand-board.svg +0 -126
- package/assets/brand/evolcore/evolcore-logo-kit.zip +0 -0
- package/assets/brand/evolcore/evolcore-logo-reverse.png +0 -0
- package/assets/brand/evolcore/evolcore-logo-reverse.svg +0 -14
- package/assets/brand/evolcore/evolcore-logo.png +0 -0
- package/assets/brand/evolcore/evolcore-logo.svg +0 -14
- package/assets/brand/evolcore/evolcore-mark.png +0 -0
- package/assets/brand/evolcore/evolcore-mark.svg +0 -10
package/dist/utils/aid-bind.js
CHANGED
|
@@ -133,56 +133,70 @@ export class BindService {
|
|
|
133
133
|
return fail('TASK_NOT_FOUND', 'binding task not found');
|
|
134
134
|
if (payload.bindType !== task.bindType)
|
|
135
135
|
return fail('BIND_TYPE_MISMATCH', 'bindType mismatch');
|
|
136
|
-
if (
|
|
136
|
+
if (!fromAid)
|
|
137
|
+
return fail('INTERNAL_ERROR', 'missing AUN sender');
|
|
138
|
+
if (task.status === 'pending' && Date.now() > task.expiresAt) {
|
|
137
139
|
task.status = 'expired';
|
|
138
140
|
task.finishedAt ??= task.expiresAt;
|
|
139
141
|
return fail('TASK_EXPIRED', 'binding task expired');
|
|
140
142
|
}
|
|
141
|
-
if (task.status === 'bound')
|
|
143
|
+
if (task.status === 'bound') {
|
|
144
|
+
// The owner write and task transition necessarily happen before the caller
|
|
145
|
+
// can send bind.response. If that send fails, the App retries the same
|
|
146
|
+
// authenticated request. Replay the original success only to the AID that
|
|
147
|
+
// completed the bind; other senders must not receive daemonInfo.
|
|
148
|
+
if (task.boundAid === fromAid && task.boundResponse)
|
|
149
|
+
return task.boundResponse;
|
|
142
150
|
return fail('ALREADY_BOUND', 'binding task already completed');
|
|
151
|
+
}
|
|
143
152
|
if (task.status !== 'pending')
|
|
144
153
|
return fail('TASK_NOT_FOUND', 'binding task is not pending');
|
|
145
154
|
if (!timingSafeTokenEqual(payload.token, task.tokenHash)) {
|
|
146
155
|
return fail('INVALID_TOKEN', 'invalid token');
|
|
147
156
|
}
|
|
148
|
-
if (!fromAid)
|
|
149
|
-
return fail('INTERNAL_ERROR', 'missing AUN sender');
|
|
150
157
|
try {
|
|
158
|
+
// Build and retain the exact response before committing the bind so a
|
|
159
|
+
// post-commit transport failure can be recovered by an idempotent retry.
|
|
160
|
+
const response = this.buildSuccessResponse(task);
|
|
151
161
|
this.applyOwnerBinding(task, fromAid);
|
|
152
162
|
task.status = 'bound';
|
|
153
163
|
task.boundAid = fromAid;
|
|
154
164
|
task.boundName = payload.clientName;
|
|
165
|
+
task.boundResponse = response;
|
|
155
166
|
task.finishedAt = Date.now();
|
|
156
|
-
|
|
157
|
-
return {
|
|
158
|
-
type: 'bind.response',
|
|
159
|
-
bindType: task.bindType,
|
|
160
|
-
success: true,
|
|
161
|
-
daemonInfo: {
|
|
162
|
-
daemonAid: task.receiverAid,
|
|
163
|
-
...(task.bindType === 'agent' ? { agentAid: task.targetAid } : {}),
|
|
164
|
-
bindType: task.bindType,
|
|
165
|
-
...(task.bindType === 'daemon'
|
|
166
|
-
? {
|
|
167
|
-
version: readEvolcoreVersion(),
|
|
168
|
-
platform: getPlatform(),
|
|
169
|
-
uptime: this.opts.getUptimeSeconds(),
|
|
170
|
-
baseagents: this.opts.getAvailableBaseagents(),
|
|
171
|
-
}
|
|
172
|
-
: {
|
|
173
|
-
active_baseagent: details.baseagent.active_baseagent,
|
|
174
|
-
model: details.baseagent.model,
|
|
175
|
-
effort: details.baseagent.effort,
|
|
176
|
-
channels: details.channels,
|
|
177
|
-
agentName: task.agentName,
|
|
178
|
-
}),
|
|
179
|
-
},
|
|
180
|
-
};
|
|
167
|
+
return response;
|
|
181
168
|
}
|
|
182
169
|
catch (e) {
|
|
183
170
|
return fail('INTERNAL_ERROR', e?.message || String(e));
|
|
184
171
|
}
|
|
185
172
|
}
|
|
173
|
+
buildSuccessResponse(task) {
|
|
174
|
+
const details = task.bindType === 'agent' ? this.buildAgentBindDetails(task) : null;
|
|
175
|
+
return {
|
|
176
|
+
type: 'bind.response',
|
|
177
|
+
bindType: task.bindType,
|
|
178
|
+
success: true,
|
|
179
|
+
daemonInfo: {
|
|
180
|
+
daemonAid: task.receiverAid,
|
|
181
|
+
...(task.bindType === 'agent' ? { agentAid: task.targetAid } : {}),
|
|
182
|
+
bindType: task.bindType,
|
|
183
|
+
...(task.bindType === 'daemon'
|
|
184
|
+
? {
|
|
185
|
+
version: readEvolcoreVersion(),
|
|
186
|
+
platform: getPlatform(),
|
|
187
|
+
uptime: this.opts.getUptimeSeconds(),
|
|
188
|
+
baseagents: this.opts.getAvailableBaseagents(),
|
|
189
|
+
}
|
|
190
|
+
: {
|
|
191
|
+
active_baseagent: details.baseagent.active_baseagent,
|
|
192
|
+
model: details.baseagent.model,
|
|
193
|
+
effort: details.baseagent.effort,
|
|
194
|
+
channels: details.channels,
|
|
195
|
+
agentName: task.agentName,
|
|
196
|
+
}),
|
|
197
|
+
},
|
|
198
|
+
};
|
|
199
|
+
}
|
|
186
200
|
buildAgentBindDetails(task) {
|
|
187
201
|
const agent = loadAgent(task.targetAid);
|
|
188
202
|
const config = resolveEffective({ self: task.targetAid }, { expand: true });
|
|
@@ -56,6 +56,13 @@
|
|
|
56
56
|
"type": "api_error",
|
|
57
57
|
"message": "⚠️ 当前算力池切换中,请稍后重试"
|
|
58
58
|
},
|
|
59
|
+
{
|
|
60
|
+
"id": "retry-attempt-stalled",
|
|
61
|
+
"match": "retry_attempt_stalled",
|
|
62
|
+
"action": "retry",
|
|
63
|
+
"type": "api_error",
|
|
64
|
+
"message": "⚠️ API 重试调用长时间无响应"
|
|
65
|
+
},
|
|
59
66
|
{
|
|
60
67
|
"id": "selected-model-at-capacity",
|
|
61
68
|
"match": "selected model is at capacity",
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { getPackageRoot } from '../paths.js';
|
|
4
|
+
let cachedVersion;
|
|
5
|
+
export function readInstalledEvolcoreVersion() {
|
|
6
|
+
if (cachedVersion !== undefined)
|
|
7
|
+
return cachedVersion;
|
|
8
|
+
let version;
|
|
9
|
+
try {
|
|
10
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(getPackageRoot(), 'package.json'), 'utf-8'));
|
|
11
|
+
version = typeof pkg.version === 'string' && pkg.version ? pkg.version : 'unknown';
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
version = 'unknown';
|
|
15
|
+
}
|
|
16
|
+
cachedVersion = version;
|
|
17
|
+
return version;
|
|
18
|
+
}
|
|
19
|
+
export function _resetInstalledEvolcoreVersionForTests() {
|
|
20
|
+
cachedVersion = undefined;
|
|
21
|
+
}
|
|
@@ -14,6 +14,7 @@ import { spawnSync } from 'child_process';
|
|
|
14
14
|
import { resolvePaths } from '../paths.js';
|
|
15
15
|
import { isProcessRunning, killProcess, isWindows, findProcesses } from './cross-platform.js';
|
|
16
16
|
import { getProcessStartTime, startTimeMatches } from './process-introspect.js';
|
|
17
|
+
import { isConfirmedLeakedTestDaemon, runtimeHomeFromEnv } from './restart-safety.js';
|
|
17
18
|
// ── Helpers ──
|
|
18
19
|
function instanceDir() {
|
|
19
20
|
return resolvePaths().instanceDir;
|
|
@@ -339,10 +340,11 @@ function killPid(pid) {
|
|
|
339
340
|
* 用途:检测跨 HOME 残留的 evolcore 主进程(例如测试套件 spawn 后未清理、
|
|
340
341
|
* 旧版本 pidfile 模式遗留等),由 cmdStart/cmdRestart 在启动前提示用户。
|
|
341
342
|
*
|
|
342
|
-
* Linux 下额外读取 /proc/<pid>/environ 提取 EVOLCORE_HOME
|
|
343
|
+
* Linux 下额外读取 /proc/<pid>/environ 提取 EVOLCORE_HOME,
|
|
344
|
+
* 并对 Vitest 泄漏的 restart-monitor daemon 做严格标记。
|
|
343
345
|
* Windows / macOS 取不到环境变量时 evolcoreHome 为 null。
|
|
344
346
|
*
|
|
345
|
-
* 不会主动 kill
|
|
347
|
+
* 不会主动 kill——清理由调用方决定。
|
|
346
348
|
*/
|
|
347
349
|
export function findOrphanProcesses() {
|
|
348
350
|
// 1. 已登记 PID(自己 HOME 下的 main + 自己进程)
|
|
@@ -367,10 +369,12 @@ export function findOrphanProcesses() {
|
|
|
367
369
|
// 三次验证:排除 ecweb(/ecweb/dist/index.js)
|
|
368
370
|
if (/[\\/]ecweb[\\/]dist[\\/]index\.js/.test(cmdline))
|
|
369
371
|
continue;
|
|
372
|
+
const processEnv = readProcessEnvironment(pid);
|
|
370
373
|
orphans.push({
|
|
371
374
|
pid,
|
|
372
|
-
evolcoreHome:
|
|
375
|
+
evolcoreHome: processEnv ? runtimeHomeFromEnv(processEnv) : null,
|
|
373
376
|
cmdline,
|
|
377
|
+
confirmedTestDaemon: processEnv ? isConfirmedLeakedTestDaemon(processEnv) : false,
|
|
374
378
|
});
|
|
375
379
|
}
|
|
376
380
|
return orphans;
|
|
@@ -418,16 +422,19 @@ function readCmdline(pid) {
|
|
|
418
422
|
}
|
|
419
423
|
}
|
|
420
424
|
}
|
|
421
|
-
function
|
|
425
|
+
function readProcessEnvironment(pid) {
|
|
422
426
|
// Linux: /proc/<pid>/environ
|
|
423
427
|
if (!isWindows && process.platform !== 'darwin') {
|
|
424
428
|
try {
|
|
425
429
|
const env = fs.readFileSync(`/proc/${pid}/environ`, 'utf-8');
|
|
430
|
+
const result = {};
|
|
426
431
|
for (const entry of env.split('\0')) {
|
|
427
|
-
|
|
428
|
-
|
|
432
|
+
const separator = entry.indexOf('=');
|
|
433
|
+
if (separator <= 0)
|
|
434
|
+
continue;
|
|
435
|
+
result[entry.slice(0, separator)] = entry.slice(separator + 1);
|
|
429
436
|
}
|
|
430
|
-
return
|
|
437
|
+
return result;
|
|
431
438
|
}
|
|
432
439
|
catch {
|
|
433
440
|
return null;
|
package/dist/utils/log-writer.js
CHANGED
|
@@ -24,6 +24,52 @@ import path from 'path';
|
|
|
24
24
|
import { clearInterval as clearNativeInterval, clearTimeout as clearNativeTimeout, setInterval as setNativeInterval, setTimeout as setNativeTimeout, } from 'node:timers';
|
|
25
25
|
const HOUR_MS = 60 * 60 * 1000;
|
|
26
26
|
const DAY_MS = 24 * HOUR_MS;
|
|
27
|
+
/**
|
|
28
|
+
* Rotate the daemon's redirected stdout before a launcher opens it for append.
|
|
29
|
+
* stdout is owned by the launcher rather than LogWriter, so both start and
|
|
30
|
+
* restart paths must call this after the previous daemon has exited.
|
|
31
|
+
*/
|
|
32
|
+
export function rotateStdoutLog(logDir, options = {}) {
|
|
33
|
+
const maxSize = options.maxSize ?? 10 * 1024 * 1024;
|
|
34
|
+
const retentionMs = options.retentionMs ?? 7 * DAY_MS;
|
|
35
|
+
const now = options.now ?? Date.now();
|
|
36
|
+
const stdoutLog = path.join(logDir, 'stdout.log');
|
|
37
|
+
let rotatedPath = null;
|
|
38
|
+
try {
|
|
39
|
+
if (fs.statSync(stdoutLog).size > maxSize) {
|
|
40
|
+
const timestamp = new Date(now).toISOString().replace(/[:.]/g, '').slice(0, 15);
|
|
41
|
+
const baseArchive = `${stdoutLog}.${timestamp}`;
|
|
42
|
+
let archive = baseArchive;
|
|
43
|
+
let suffix = 1;
|
|
44
|
+
while (fs.existsSync(archive))
|
|
45
|
+
archive = `${baseArchive}.${suffix++}`;
|
|
46
|
+
fs.renameSync(stdoutLog, archive);
|
|
47
|
+
rotatedPath = archive;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Missing/unreadable stdout must not prevent the daemon from starting.
|
|
52
|
+
}
|
|
53
|
+
const removedArchives = [];
|
|
54
|
+
const cutoff = now - retentionMs;
|
|
55
|
+
try {
|
|
56
|
+
for (const name of fs.readdirSync(logDir)) {
|
|
57
|
+
if (!name.startsWith('stdout.log.'))
|
|
58
|
+
continue;
|
|
59
|
+
const full = path.join(logDir, name);
|
|
60
|
+
try {
|
|
61
|
+
const stat = fs.lstatSync(full);
|
|
62
|
+
if (stat.isSymbolicLink() || stat.mtimeMs < cutoff) {
|
|
63
|
+
fs.unlinkSync(full);
|
|
64
|
+
removedArchives.push(full);
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
catch { }
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
catch { }
|
|
71
|
+
return { rotatedPath, removedArchives };
|
|
72
|
+
}
|
|
27
73
|
export class LogWriter {
|
|
28
74
|
baseName;
|
|
29
75
|
logDir;
|
package/dist/utils/logger.js
CHANGED
|
@@ -51,8 +51,8 @@ function log(level, ...args) {
|
|
|
51
51
|
getWriters().main.write(msg);
|
|
52
52
|
}
|
|
53
53
|
/**
|
|
54
|
-
* 设置日志级别(
|
|
55
|
-
* 优先级:
|
|
54
|
+
* 设置日志级别(daemon.json 加载后调用,覆盖环境变量默认值)
|
|
55
|
+
* 优先级:daemon.json debug.logLevel → LOG_LEVEL 环境变量 → 'INFO'
|
|
56
56
|
*/
|
|
57
57
|
export function setLogLevel(level) {
|
|
58
58
|
const upper = level.toUpperCase();
|
|
@@ -183,7 +183,10 @@ export async function safeFetch(url, opts) {
|
|
|
183
183
|
const controller = new AbortController();
|
|
184
184
|
const timer = setTimeout(() => controller.abort(), timeout);
|
|
185
185
|
try {
|
|
186
|
-
const res = await fetch(url, {
|
|
186
|
+
const res = await fetch(url, {
|
|
187
|
+
signal: controller.signal,
|
|
188
|
+
redirect: opts?.rejectRedirects ? 'error' : 'follow',
|
|
189
|
+
});
|
|
187
190
|
if (!res.ok)
|
|
188
191
|
throw new Error(`Download failed: ${res.status} ${res.statusText}`);
|
|
189
192
|
// 检查 Content-Length(如果可用)
|
|
@@ -3,9 +3,12 @@
|
|
|
3
3
|
{"model":"claude-opus-4-6","effective_from":0,"billing_fn":"per_token_v1","currency":"USD","price_input":15,"price_output":75,"price_cache_creation":18.75,"price_cache_read":1.5}
|
|
4
4
|
{"model":"claude-sonnet-4-6","effective_from":0,"billing_fn":"per_token_v1","currency":"USD","price_input":3,"price_output":15,"price_cache_creation":3.75,"price_cache_read":0.3}
|
|
5
5
|
{"model":"claude-haiku-4-5-20251001","effective_from":0,"billing_fn":"per_token_v1","currency":"USD","price_input":0.8,"price_output":4,"price_cache_creation":1,"price_cache_read":0.08}
|
|
6
|
-
{"model":"gpt-5.
|
|
7
|
-
{"model":"gpt-5.
|
|
8
|
-
{"model":"gpt-5.
|
|
6
|
+
{"model":"gpt-5.6-sol","effective_from":0,"billing_fn":"per_token_v1","currency":"USD","price_input":5,"price_output":30,"price_cache_creation":6.25,"price_cache_read":0.5,"tiers":[{"up_to_input_tokens":272000,"price_input":5,"price_output":30,"price_cache_creation":6.25,"price_cache_read":0.5},{"up_to_input_tokens":null,"price_input":10,"price_output":45,"price_cache_creation":12.5,"price_cache_read":1}]}
|
|
7
|
+
{"model":"gpt-5.6-terra","effective_from":0,"billing_fn":"per_token_v1","currency":"USD","price_input":2.5,"price_output":15,"price_cache_creation":3.125,"price_cache_read":0.25,"tiers":[{"up_to_input_tokens":272000,"price_input":2.5,"price_output":15,"price_cache_creation":3.125,"price_cache_read":0.25},{"up_to_input_tokens":null,"price_input":5,"price_output":22.5,"price_cache_creation":6.25,"price_cache_read":0.5}]}
|
|
8
|
+
{"model":"gpt-5.6-luna","effective_from":0,"billing_fn":"per_token_v1","currency":"USD","price_input":1,"price_output":6,"price_cache_creation":1.25,"price_cache_read":0.1,"tiers":[{"up_to_input_tokens":272000,"price_input":1,"price_output":6,"price_cache_creation":1.25,"price_cache_read":0.1},{"up_to_input_tokens":null,"price_input":2,"price_output":9,"price_cache_creation":2.5,"price_cache_read":0.2}]}
|
|
9
|
+
{"model":"gpt-5.5","effective_from":0,"billing_fn":"per_token_v1","currency":"USD","price_input":5,"price_output":30,"price_cache_creation":0,"price_cache_read":0.5,"tiers":[{"up_to_input_tokens":272000,"price_input":5,"price_output":30,"price_cache_creation":0,"price_cache_read":0.5},{"up_to_input_tokens":null,"price_input":10,"price_output":45,"price_cache_creation":0,"price_cache_read":1}]}
|
|
10
|
+
{"model":"gpt-5.4","effective_from":0,"billing_fn":"per_token_v1","currency":"USD","price_input":2.5,"price_output":15,"price_cache_creation":0,"price_cache_read":0.25,"tiers":[{"up_to_input_tokens":272000,"price_input":2.5,"price_output":15,"price_cache_creation":0,"price_cache_read":0.25},{"up_to_input_tokens":null,"price_input":5,"price_output":22.5,"price_cache_creation":0,"price_cache_read":0.5}]}
|
|
11
|
+
{"model":"gpt-5.3-codex","effective_from":0,"billing_fn":"per_token_v1","currency":"USD","price_input":1.75,"price_output":14,"price_cache_creation":0,"price_cache_read":0.175}
|
|
9
12
|
{"model":"deepseek-v4-pro","effective_from":0,"billing_fn":"per_token_deepseek_v1","currency":"CNY","price_cache_hit":0.5,"price_cache_miss":2,"price_output":8}
|
|
10
13
|
{"model":"deepseek-v4-flash","effective_from":0,"billing_fn":"per_token_deepseek_v1","currency":"CNY","price_cache_hit":0.1,"price_cache_miss":0.5,"price_output":2}
|
|
11
14
|
{"model":"deepseek-v3.2","effective_from":0,"billing_fn":"per_token_deepseek_v1","currency":"CNY","price_cache_hit":0.5,"price_cache_miss":2,"price_output":8}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const REAL_RESTART_TEST_OVERRIDE = 'EVOLCORE_ALLOW_REAL_RESTART_IN_TEST';
|
|
2
|
+
export function isRestartTestRuntime(env = process.env) {
|
|
3
|
+
return env.VITEST === 'true'
|
|
4
|
+
|| env.EVOLCORE_TEST === '1';
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Unit tests must never detach a real restart-monitor/daemon pair by accident.
|
|
8
|
+
* Dedicated process-level integration tests can opt in explicitly.
|
|
9
|
+
*/
|
|
10
|
+
export function shouldSuppressRealRestart(env = process.env) {
|
|
11
|
+
return isRestartTestRuntime(env) && env[REAL_RESTART_TEST_OVERRIDE] !== '1';
|
|
12
|
+
}
|
|
13
|
+
export function runtimeHomeFromEnv(env) {
|
|
14
|
+
return env.EVOLCORE_HOME || null;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Strict classifier used before automatically killing leaked test daemons.
|
|
18
|
+
* All markers must agree so a legitimate secondary runtime is never mistaken
|
|
19
|
+
* for a disposable test process.
|
|
20
|
+
*/
|
|
21
|
+
export function isConfirmedLeakedTestDaemon(env) {
|
|
22
|
+
const home = runtimeHomeFromEnv(env);
|
|
23
|
+
if (!home || !/[\\/]evolcore-test-[^\\/]+$/.test(home))
|
|
24
|
+
return false;
|
|
25
|
+
const launchedBy = env.EVOLCORE_LAUNCHED_BY;
|
|
26
|
+
const testRuntime = env.VITEST === 'true'
|
|
27
|
+
|| env.EVOLCORE_TEST === '1';
|
|
28
|
+
return testRuntime
|
|
29
|
+
&& env.NODE_ENV === 'test'
|
|
30
|
+
&& launchedBy === 'restart-monitor';
|
|
31
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
const STABLE_SEMVER = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/;
|
|
2
|
+
export function parseStableSemver(value) {
|
|
3
|
+
if (typeof value !== 'string')
|
|
4
|
+
return null;
|
|
5
|
+
const match = STABLE_SEMVER.exec(value);
|
|
6
|
+
if (!match)
|
|
7
|
+
return null;
|
|
8
|
+
const parsed = [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
9
|
+
if (parsed.some(part => !Number.isSafeInteger(part)))
|
|
10
|
+
return null;
|
|
11
|
+
return parsed;
|
|
12
|
+
}
|
|
13
|
+
export function compareStableSemver(left, right) {
|
|
14
|
+
for (let index = 0; index < 3; index += 1) {
|
|
15
|
+
if (left[index] < right[index])
|
|
16
|
+
return -1;
|
|
17
|
+
if (left[index] > right[index])
|
|
18
|
+
return 1;
|
|
19
|
+
}
|
|
20
|
+
return 0;
|
|
21
|
+
}
|
package/dist/utils/stats.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { formatPeerKey } from '../core/relation/peer-identity.js';
|
|
1
2
|
export class StatsCollector {
|
|
2
3
|
events = [];
|
|
3
4
|
recentErrors = [];
|
|
@@ -136,6 +137,7 @@ export class StatsCollector {
|
|
|
136
137
|
}
|
|
137
138
|
export class AidStatsCollector {
|
|
138
139
|
entries = new Map();
|
|
140
|
+
routePeers = new Map();
|
|
139
141
|
queueStatsProvider;
|
|
140
142
|
/** sessionId → 当前正在跑该 session 的 agent,task:started 写入,task:completed/error 清除 */
|
|
141
143
|
sessionToAgent = new Map();
|
|
@@ -233,10 +235,12 @@ export class AidStatsCollector {
|
|
|
233
235
|
lastReceivedFrom: null,
|
|
234
236
|
lastReceivedEncrypt: null,
|
|
235
237
|
lastReceivedChatmode: null,
|
|
238
|
+
lastReceivedChannel: null,
|
|
236
239
|
lastSentText: null,
|
|
237
240
|
lastSentTo: null,
|
|
238
241
|
lastSentEncrypt: null,
|
|
239
242
|
lastSentChatmode: null,
|
|
243
|
+
lastSentChannel: null,
|
|
240
244
|
lastReceivedKind: null,
|
|
241
245
|
lastSentKind: null,
|
|
242
246
|
uniquePeers: new Set(),
|
|
@@ -256,6 +260,9 @@ export class AidStatsCollector {
|
|
|
256
260
|
}
|
|
257
261
|
return entry;
|
|
258
262
|
}
|
|
263
|
+
routePeerKey(aid, channel, routeId) {
|
|
264
|
+
return `${aid}\u001f${channel}\u001f${routeId}`;
|
|
265
|
+
}
|
|
259
266
|
onTaskStart(aid, encrypt, chatmode) {
|
|
260
267
|
const entry = this.getOrCreate(aid);
|
|
261
268
|
entry.currentTaskStartAt = Date.now();
|
|
@@ -298,25 +305,31 @@ export class AidStatsCollector {
|
|
|
298
305
|
const entry = this.getOrCreate(aid);
|
|
299
306
|
entry.selfName = name;
|
|
300
307
|
}
|
|
301
|
-
recordInbound(aid, fromPeer, byteLength, text, isSystem = false, encrypt, chatmode, kind = 'send') {
|
|
308
|
+
recordInbound(aid, fromPeer, byteLength, text, isSystem = false, encrypt, chatmode, kind = 'send', ctx) {
|
|
302
309
|
const entry = this.getOrCreate(aid);
|
|
310
|
+
const channel = ctx?.channelType || 'aun';
|
|
311
|
+
const peerLabel = ctx?.peerLabel || fromPeer;
|
|
312
|
+
if (ctx?.routeId && fromPeer) {
|
|
313
|
+
this.routePeers.set(this.routePeerKey(aid, channel, ctx.routeId), { peerId: fromPeer, peerLabel });
|
|
314
|
+
}
|
|
303
315
|
if (isSystem) {
|
|
304
316
|
entry.systemReceived++;
|
|
305
317
|
}
|
|
306
318
|
else {
|
|
307
319
|
entry.messagesReceived++;
|
|
308
320
|
entry.lastReceivedAt = Date.now();
|
|
309
|
-
entry.lastReceivedFrom =
|
|
321
|
+
entry.lastReceivedFrom = peerLabel;
|
|
310
322
|
if (text)
|
|
311
323
|
entry.lastReceivedText = text.length > 100 ? text.slice(0, 100) + '…' : text;
|
|
312
324
|
if (encrypt != null)
|
|
313
325
|
entry.lastReceivedEncrypt = encrypt;
|
|
314
326
|
if (chatmode)
|
|
315
327
|
entry.lastReceivedChatmode = chatmode;
|
|
328
|
+
entry.lastReceivedChannel = channel;
|
|
316
329
|
entry.lastReceivedKind = kind;
|
|
317
330
|
// ring buffer:最近 10 轮
|
|
318
331
|
if (text) {
|
|
319
|
-
entry.recentMessages.unshift({ dir: 'in', peer:
|
|
332
|
+
entry.recentMessages.unshift({ dir: 'in', peer: peerLabel, text: text.slice(0, 100), ts: Date.now(), kind, encrypt: encrypt ?? null, chatmode: chatmode ?? null, channel });
|
|
320
333
|
if (entry.recentMessages.length > 10)
|
|
321
334
|
entry.recentMessages.pop();
|
|
322
335
|
}
|
|
@@ -325,30 +338,39 @@ export class AidStatsCollector {
|
|
|
325
338
|
entry.uniquePeers.add(fromPeer);
|
|
326
339
|
// 持久化
|
|
327
340
|
this.onMessage?.({
|
|
328
|
-
ts: Date.now(), agent_aid: aid, peer_key:
|
|
341
|
+
ts: Date.now(), agent_aid: aid, peer_key: formatPeerKey(channel, fromPeer),
|
|
329
342
|
direction: 'in', msg_type: isSystem ? 'system' : 'private',
|
|
330
343
|
bytes: byteLength, encrypted: encrypt, chatmode,
|
|
331
344
|
});
|
|
332
345
|
}
|
|
333
|
-
recordOutbound(aid, toPeer, byteLength, text, isSystem = false, encrypt, chatmode, kind = 'send') {
|
|
346
|
+
recordOutbound(aid, toPeer, byteLength, text, isSystem = false, encrypt, chatmode, kind = 'send', ctx) {
|
|
334
347
|
const entry = this.getOrCreate(aid);
|
|
348
|
+
const channel = ctx?.channelType || 'aun';
|
|
349
|
+
const routePeer = ctx?.routeId
|
|
350
|
+
? this.routePeers.get(this.routePeerKey(aid, channel, ctx.routeId))
|
|
351
|
+
: undefined;
|
|
352
|
+
const stablePeer = routePeer?.peerId || toPeer;
|
|
353
|
+
const peerLabel = ctx?.peerLabel && ctx.peerLabel !== toPeer
|
|
354
|
+
? ctx.peerLabel
|
|
355
|
+
: routePeer?.peerLabel || ctx?.peerLabel || toPeer;
|
|
335
356
|
if (isSystem) {
|
|
336
357
|
entry.systemSent++;
|
|
337
358
|
}
|
|
338
359
|
else {
|
|
339
360
|
entry.messagesSent++;
|
|
340
361
|
entry.lastSentAt = Date.now();
|
|
341
|
-
entry.lastSentTo =
|
|
362
|
+
entry.lastSentTo = peerLabel;
|
|
342
363
|
if (text)
|
|
343
364
|
entry.lastSentText = text.length > 100 ? text.slice(0, 100) + '…' : text;
|
|
344
365
|
if (encrypt != null)
|
|
345
366
|
entry.lastSentEncrypt = encrypt;
|
|
346
367
|
if (chatmode)
|
|
347
368
|
entry.lastSentChatmode = chatmode;
|
|
369
|
+
entry.lastSentChannel = channel;
|
|
348
370
|
entry.lastSentKind = kind;
|
|
349
371
|
// ring buffer:最近 10 轮
|
|
350
372
|
if (text) {
|
|
351
|
-
entry.recentMessages.unshift({ dir: 'out', peer:
|
|
373
|
+
entry.recentMessages.unshift({ dir: 'out', peer: peerLabel, text: text.slice(0, 100), ts: Date.now(), kind, encrypt: encrypt ?? null, chatmode: chatmode ?? null, channel });
|
|
352
374
|
if (entry.recentMessages.length > 10)
|
|
353
375
|
entry.recentMessages.pop();
|
|
354
376
|
}
|
|
@@ -362,10 +384,10 @@ export class AidStatsCollector {
|
|
|
362
384
|
}
|
|
363
385
|
}
|
|
364
386
|
entry.bytesSent += byteLength;
|
|
365
|
-
entry.uniquePeers.add(
|
|
387
|
+
entry.uniquePeers.add(stablePeer);
|
|
366
388
|
// 持久化
|
|
367
389
|
this.onMessage?.({
|
|
368
|
-
ts: Date.now(), agent_aid: aid, peer_key:
|
|
390
|
+
ts: Date.now(), agent_aid: aid, peer_key: formatPeerKey(channel, stablePeer),
|
|
369
391
|
direction: 'out', msg_type: isSystem ? 'system' : 'private',
|
|
370
392
|
bytes: byteLength, encrypted: encrypt, chatmode,
|
|
371
393
|
});
|
|
@@ -391,10 +413,12 @@ export class AidStatsCollector {
|
|
|
391
413
|
lastReceivedFrom: entry.lastReceivedFrom,
|
|
392
414
|
lastReceivedEncrypt: entry.lastReceivedEncrypt,
|
|
393
415
|
lastReceivedChatmode: entry.lastReceivedChatmode,
|
|
416
|
+
lastReceivedChannel: entry.lastReceivedChannel,
|
|
394
417
|
lastSentText: entry.lastSentText,
|
|
395
418
|
lastSentTo: entry.lastSentTo,
|
|
396
419
|
lastSentEncrypt: entry.lastSentEncrypt,
|
|
397
420
|
lastSentChatmode: entry.lastSentChatmode,
|
|
421
|
+
lastSentChannel: entry.lastSentChannel,
|
|
398
422
|
lastReceivedKind: entry.lastReceivedKind,
|
|
399
423
|
lastSentKind: entry.lastSentKind,
|
|
400
424
|
uniquePeerCount: entry.uniquePeers.size,
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import fs from 'fs';
|
|
2
|
+
import os from 'os';
|
|
3
|
+
function readNumber(filePath) {
|
|
4
|
+
try {
|
|
5
|
+
const value = Number(fs.readFileSync(filePath, 'utf8').trim());
|
|
6
|
+
return Number.isFinite(value) && value >= 0 ? value : null;
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function parseCgroupV2MemoryStat(input) {
|
|
13
|
+
const values = new Map();
|
|
14
|
+
for (const line of input.split('\n')) {
|
|
15
|
+
const [key, raw] = line.trim().split(/\s+/, 2);
|
|
16
|
+
const value = Number(raw);
|
|
17
|
+
if (key && Number.isFinite(value) && value >= 0)
|
|
18
|
+
values.set(key, value);
|
|
19
|
+
}
|
|
20
|
+
return values;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* System memory for the current container/host namespace.
|
|
24
|
+
*
|
|
25
|
+
* Linux cgroup v2 uses memory.current - memory.stat:file so the value matches
|
|
26
|
+
* common host/container dashboards: anonymous + kernel memory, excluding
|
|
27
|
+
* reclaimable filesystem page cache. Other environments fall back to the
|
|
28
|
+
* portable total - available calculation exposed by Node.js.
|
|
29
|
+
*/
|
|
30
|
+
export function readSystemMemoryUsage(cgroupRoot = '/sys/fs/cgroup') {
|
|
31
|
+
const memTotal = os.totalmem();
|
|
32
|
+
const memAvailable = os.freemem();
|
|
33
|
+
if (process.platform === 'linux') {
|
|
34
|
+
const current = readNumber(`${cgroupRoot}/memory.current`);
|
|
35
|
+
if (current !== null) {
|
|
36
|
+
try {
|
|
37
|
+
const stat = parseCgroupV2MemoryStat(fs.readFileSync(`${cgroupRoot}/memory.stat`, 'utf8'));
|
|
38
|
+
const fileCache = stat.get('file');
|
|
39
|
+
if (fileCache !== undefined) {
|
|
40
|
+
const memUsed = Math.max(0, current - fileCache);
|
|
41
|
+
return {
|
|
42
|
+
memTotal,
|
|
43
|
+
memUsed,
|
|
44
|
+
memFree: Math.max(0, memTotal - memUsed),
|
|
45
|
+
memAvailable,
|
|
46
|
+
memorySource: 'cgroup-v2-current-minus-file',
|
|
47
|
+
cgroupCurrent: current,
|
|
48
|
+
fileCache,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
catch { /* fall through to portable OS metrics */ }
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
memTotal,
|
|
57
|
+
memUsed: Math.max(0, memTotal - memAvailable),
|
|
58
|
+
memFree: memAvailable,
|
|
59
|
+
memAvailable,
|
|
60
|
+
memorySource: 'os-total-minus-available',
|
|
61
|
+
};
|
|
62
|
+
}
|
package/kits/docs/INDEX.md
CHANGED
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
| 文档 | 路径 | 说明 |
|
|
26
26
|
|------|------|------|
|
|
27
27
|
| 命令集目录 | `evolcore/INDEX.md` | msg/group/agent/aid/storage/ctl/rpc/bench 全集索引 |
|
|
28
|
+
| 联系人命令 | `evolcore/contact.md` | Contact Book 拉黑与托管会话权限边界 |
|
|
28
29
|
|
|
29
30
|
## 身份
|
|
30
31
|
|
|
@@ -46,7 +47,7 @@
|
|
|
46
47
|
|
|
47
48
|
| 文档 | 路径 | 说明 |
|
|
48
49
|
|------|------|------|
|
|
49
|
-
| Trigger 命令手册 | `evolcore/trigger.md` |
|
|
50
|
+
| Trigger 命令手册 | `evolcore/trigger.md` | 使用 `create` 创建并管理、运行定时与事件 trigger;`set` 为兼容别名 |
|
|
50
51
|
| EventBus 事件目录 | `evolcore/event.md` | event source 可监听事件、payload、filter 与循环防护规则 |
|
|
51
52
|
|
|
52
53
|
## ECK 模板
|
|
@@ -35,19 +35,10 @@ AUN 渠道是**隐式**的——它不写在 `channels[]` 数组里,而是从
|
|
|
35
35
|
|
|
36
36
|
> `owners`/`admins` 用 **AID**,不是渠道原生 ID。
|
|
37
37
|
|
|
38
|
-
###
|
|
38
|
+
### AUN keystore seed
|
|
39
39
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
```json
|
|
43
|
-
{
|
|
44
|
-
"aun": {
|
|
45
|
-
"encryptionSeed": "<seed>"
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
留空时 SDK 依次回退 `AUN_ENCRYPTION_SEED` 环境变量 → 默认 `'evol'`。
|
|
40
|
+
AUN keystore seed 由 EvolCore 使用固定应用值管理,不再提供配置项或环境变量入口。
|
|
41
|
+
检测到历史自定义值时 daemon 会拒绝启动并提示联系管理人员,避免用错误值加载现有身份。
|
|
51
42
|
|
|
52
43
|
> Gateway 不在配置里手填:连接时从 AID 自动发现(见下)。Keystore 默认落在 `$EVOLCORE_HOME`。
|
|
53
44
|
|
|
@@ -58,7 +49,7 @@ E2EE 加密种子是**进程级**的,所有 agent 共享,不在 agent config
|
|
|
58
49
|
- **身份与信任**:每条入站消息携带发送者 AID,经四级 X.509 证书链(Root CA → Registry CA → Issuer CA → Agent)验签。
|
|
59
50
|
- **agent.md 缓存**:对端名片 `https://<aid>/agent.md` 由 **AUN SDK 自动拉取并缓存**(`AgentMdManager`,带 ETag/TTL,默认 1 天内不重复探测)。缓存落在 **`$EVOLCORE_HOME/AIDs/<aid>/`**,每个 AID 两个文件:`agent.md`(带签名正文)+ `agentmd.json`(元数据:etag/last_modified/checked_at/verify_status)。本端与对端的 agent.md 都缓存于此。
|
|
60
51
|
- 关系层另存一份**派生**的精简身份 `relations/<peerKey>/peer-identity.json`(type/isAgent/name),由 evolcore 从 agent.md 提取,不是 agent.md 本体。
|
|
61
|
-
- **E2EE
|
|
52
|
+
- **E2EE 加密**:可选端到端加密,回复默认跟随对端消息加密状态(密文回密文,明文回明文);keystore seed 由 EvolCore 固定管理。
|
|
62
53
|
- **断线重连**:SDK 内置退避策略自动重连。实时连接状态用 `ec watch aid` 查看(`ec aid` 是身份/证书管理,不显示连接状态)。
|
|
63
54
|
- **群 ID 格式**:当前协议规范使用 `g-{slug}.issuer-domain` canonical 形式,输入也可接受本域简写 `g-{slug}` 或兼容形式 `g-{slug}@issuer-domain`。历史会话里可能仍出现 `group.{issuer}/{group_no}` 一类旧格式,运行时需兼容读取。
|
|
64
55
|
- **群分发模式**:`dispatch_mode=broadcast|mention` 是群级配置,只决定哪些群消息进入 Agent LLM 上下文,不影响 AUN 协议层投递;被过滤消息仍应本地存档。
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
运行时 evolcore 会通过 `commands` fragment 按当前场景(有无 peer/group、对端角色)
|
|
5
5
|
注入一张精简能力卡,指向本目录下对应文档;需要完整用法时 Read 对应文档。
|
|
6
6
|
|
|
7
|
-
>
|
|
8
|
-
>
|
|
7
|
+
> 对外通信命令以自己的 AID 为发送者;当前渠道是否需要 CLI 回复,以运行时注入的
|
|
8
|
+
> `channel` 规则为准。参数不是全局通用的:`--format json` 仅用于对应帮助中明确支持的命令,
|
|
9
|
+
> `--app <name>` 仅用于消息 pull/ack、消费类 RPC 和明确支持 app slot 的文件操作。
|
|
9
10
|
|
|
10
11
|
## 如何使用本索引
|
|
11
12
|
|
|
@@ -34,6 +35,7 @@
|
|
|
34
35
|
| `ec fs` | AUN 文件系统统一入口 | 上传/下载/看文件/列目录/删文件/配额/群空间 | 任意有渠道场景 | `fs.md` |
|
|
35
36
|
| `ec storage` | 文件存储底层调试入口 | storage 调试/旧命令/底层上传下载 | 任意有渠道场景 | `storage.md` |
|
|
36
37
|
| `ec agent` | EvolAgent 生命周期 | 创建/启停/热重载/改配置 | 管理员(owner/admin) | `agent.md` |
|
|
38
|
+
| `ec contact` | Contact Book 与访问控制 | 拉黑/解除拉黑/查拉黑 | 读 owner/admin;写仅 owner | `contact.md` |
|
|
37
39
|
| `ec rpc` | 底层 AUN RPC(逃生通道) | 直接调协议方法 | 高级/兜底 | `rpc.md` |
|
|
38
40
|
|
|
39
41
|
## 会话自管理类(不连 AUN,操作当前会话)
|
|
@@ -50,7 +52,7 @@
|
|
|
50
52
|
| `ec response` | 响应模式管理(按作用域持久化) | 切换响应模式/列响应模式/看当前模式/改响应配置 | `response.md` |
|
|
51
53
|
| `ec config` | 配置体系底层入口(读写/快照/回滚) | 看配置/改配置/查字段/查schema/校验/快照/回滚/历史/启动记录 | `config.md` |
|
|
52
54
|
| `ec stats` | Token 用量与费用统计 | 用量/费用/统计/预算/token/cost | `stats.md` |
|
|
53
|
-
| `ec trigger` |
|
|
55
|
+
| `ec trigger` | 定时与事件触发器管理(创建用 `create`,`set` 为兼容别名) | 触发器/定时任务/cron/提醒/定时检查/自动执行/巡检/禁用 trigger/删除 trigger | `trigger.md` |
|
|
54
56
|
| `ec trigger event` | EventBus 事件目录 | 事件触发/事件目录/EventBus/source.type=event/filter.match | `event.md` |
|
|
55
57
|
|
|
56
58
|
## 开发者工具(非 agent 会话能力)
|