evolclaw 3.1.11 → 3.3.0
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 +41 -0
- package/README.md +27 -2
- package/dist/agents/{resolve.js → baseagent.js} +34 -5
- package/dist/agents/claude-runner.js +120 -27
- package/dist/agents/codex-app-server-client.js +364 -0
- package/dist/agents/codex-runner.js +1069 -141
- package/dist/agents/gemini-runner.js +2 -2
- package/dist/agents/runner-types.js +28 -0
- package/dist/aun/aid/control-aid.js +67 -0
- package/dist/aun/aid/identity.js +20 -7
- package/dist/aun/aid/store.js +2 -2
- package/dist/aun/storage/download.js +1 -1
- package/dist/aun/storage/upload.js +13 -1
- package/dist/channels/aun.js +538 -325
- package/dist/channels/dingtalk.js +77 -140
- package/dist/channels/feishu.js +98 -151
- package/dist/channels/qqbot.js +75 -138
- package/dist/channels/wechat.js +75 -136
- package/dist/channels/wecom.js +75 -138
- package/dist/cli/agent.js +44 -13
- package/dist/cli/index.js +207 -46
- package/dist/cli/init-channel.js +38 -148
- package/dist/cli/init.js +192 -85
- package/dist/cli/model.js +1 -1
- package/dist/cli/stats.js +558 -0
- package/dist/cli/version.js +87 -0
- package/dist/cli/watch-msg.js +5 -2
- package/dist/config-store.js +48 -11
- package/dist/core/channel-loader.js +84 -82
- package/dist/core/command-handler.js +754 -172
- package/dist/core/daemon-file-cache.js +216 -0
- package/dist/core/evolagent-registry.js +4 -0
- package/dist/core/evolagent.js +28 -23
- package/dist/core/interaction-router.js +8 -0
- package/dist/core/message/command-handler-agent-control.js +215 -0
- package/dist/core/message/create-status.js +67 -0
- package/dist/core/message/im-renderer.js +35 -13
- package/dist/core/message/items-formatter.js +9 -1
- package/dist/core/message/message-bridge.js +52 -22
- package/dist/core/message/message-log.js +1 -0
- package/dist/core/message/message-processor.js +336 -68
- package/dist/core/message/message-queue.js +15 -8
- package/dist/core/message/pending-hints.js +232 -0
- package/dist/core/message/response-depth.js +56 -0
- package/dist/core/model/model-catalog.js +1 -1
- package/dist/core/model/model-scope.js +40 -7
- package/dist/core/permission.js +9 -12
- package/dist/core/relation/peer-identity.js +16 -1
- package/dist/core/session/adapters/claude-session-file-adapter.js +48 -5
- package/dist/core/session/adapters/codex-session-file-adapter.js +4 -2
- package/dist/core/session/session-manager.js +27 -13
- package/dist/core/session/session-title.js +26 -0
- package/dist/core/stats/billing.js +151 -0
- package/dist/core/stats/budget.js +93 -0
- package/dist/core/stats/db.js +314 -0
- package/dist/core/stats/eck-vars.js +84 -0
- package/dist/core/stats/index.js +10 -0
- package/dist/core/stats/normalizer.js +78 -0
- package/dist/core/stats/query.js +760 -0
- package/dist/core/stats/writer.js +115 -0
- package/dist/core/trigger/manager.js +34 -0
- package/dist/core/trigger/parser.js +9 -3
- package/dist/core/trigger/scheduler.js +20 -17
- package/dist/{agents → eck}/kit-renderer.js +5 -1
- package/dist/{agents → eck}/manifest-engine.js +127 -35
- package/dist/{agents → eck}/message-renderer.js +26 -1
- package/dist/index.js +185 -8
- package/dist/ipc.js +22 -0
- package/dist/paths.js +7 -3
- package/dist/utils/cross-platform.js +23 -5
- package/dist/utils/ecweb-pair.js +20 -0
- package/dist/utils/stats.js +14 -0
- package/kits/docs/evolclaw/INDEX.md +3 -1
- package/kits/docs/evolclaw/fs-architecture.md +1215 -0
- package/kits/docs/evolclaw/fs.md +131 -0
- package/kits/docs/evolclaw/group-fs.md +209 -0
- package/kits/docs/evolclaw/stats.md +70 -0
- package/kits/docs/venues/aun-group.md +29 -6
- package/kits/docs/venues/group.md +5 -4
- package/kits/eck_manifest.json +12 -0
- package/kits/eck_message_manifest.json +30 -3
- package/kits/rules/05-venue.md +1 -1
- package/kits/templates/message-fragments/inject-default.md +2 -0
- package/kits/templates/message-fragments/item.md +1 -1
- package/kits/templates/system-fragments/response-depth.md +16 -0
- package/package.json +4 -4
- package/dist/agents/baseagent-normalize.js +0 -19
- package/dist/core/relation/peer-key.js +0 -16
- package/dist/utils/channel-helpers.js +0 -46
|
@@ -13,7 +13,7 @@ import { createInterface } from 'readline';
|
|
|
13
13
|
import fs from 'fs';
|
|
14
14
|
import path from 'path';
|
|
15
15
|
import os from 'os';
|
|
16
|
-
import { resolveGoogleConfig } from './
|
|
16
|
+
import { resolveGoogleConfig } from './baseagent.js';
|
|
17
17
|
import { commandExists } from '../utils/cross-platform.js';
|
|
18
18
|
import { GeminiSessionFileAdapter } from '../core/session/adapters/gemini-session-file-adapter.js';
|
|
19
19
|
import { logger } from '../utils/logger.js';
|
|
@@ -41,7 +41,7 @@ const GEMINI_MODELS = [
|
|
|
41
41
|
// ── Gemini Runner ──
|
|
42
42
|
export class GeminiRunner {
|
|
43
43
|
name = 'gemini';
|
|
44
|
-
capabilities = { clear: true, compact: false, fork: false };
|
|
44
|
+
capabilities = { clear: true, compact: false, fork: false, askUserQuestion: false, planApproval: false, fileRewind: 'unsupported' };
|
|
45
45
|
resolved;
|
|
46
46
|
model;
|
|
47
47
|
activeProcesses = new Map();
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
// ── 类型守卫 ──
|
|
2
|
+
export function hasModelSwitcher(agent) {
|
|
3
|
+
return typeof agent.setModel === 'function' && typeof agent.listModels === 'function';
|
|
4
|
+
}
|
|
5
|
+
export function hasPermissionController(agent) {
|
|
6
|
+
return typeof agent.setMode === 'function' && typeof agent.listModes === 'function';
|
|
7
|
+
}
|
|
8
|
+
export function hasCompact(agent) {
|
|
9
|
+
return typeof agent.compact === 'function';
|
|
10
|
+
}
|
|
11
|
+
// ── Token usage helper functions ──
|
|
12
|
+
export function numericToken(value) {
|
|
13
|
+
return typeof value === 'number' && Number.isFinite(value) ? value : 0;
|
|
14
|
+
}
|
|
15
|
+
export function contextTokensForUsage(usage, isClaudeModel) {
|
|
16
|
+
if (!usage)
|
|
17
|
+
return 0;
|
|
18
|
+
if (!isClaudeModel)
|
|
19
|
+
return numericToken(usage.input_tokens);
|
|
20
|
+
return numericToken(usage.input_tokens)
|
|
21
|
+
+ numericToken(usage.cache_creation_input_tokens)
|
|
22
|
+
+ numericToken(usage.cache_read_input_tokens);
|
|
23
|
+
}
|
|
24
|
+
export function usageForContext(usage) {
|
|
25
|
+
const iterations = Array.isArray(usage?.iterations) ? usage.iterations : undefined;
|
|
26
|
+
const lastIteration = iterations?.slice().reverse().find(it => contextTokensForUsage(it, true) > 0);
|
|
27
|
+
return lastIteration ?? usage;
|
|
28
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
import { aidCreate } from './index.js';
|
|
3
|
+
import { getAidStore, SLOT } from './store.js';
|
|
4
|
+
import { logger } from '../../utils/logger.js';
|
|
5
|
+
const MAX_ATTEMPTS = 5;
|
|
6
|
+
/** 生成候选控制 AID:ec + 5位随机数字 + .agentid.pub */
|
|
7
|
+
export function candidateAid() {
|
|
8
|
+
const n = crypto.randomInt(10000, 100000); // 5 位:10000-99999
|
|
9
|
+
return `ec${n}.agentid.pub`;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* 候选 AID 是否已在 PKI 注册。
|
|
13
|
+
*
|
|
14
|
+
* 不用 store.exists(它走 HTTP HEAD /pki/cert/<aid>)——部分 Gateway 实现
|
|
15
|
+
* (Python websockets HTTP 处理)对 HEAD 直接空响应断连(curl 52 / socket hang up),
|
|
16
|
+
* 导致 exists 误报"网关不可达"。改用 store.resolve(走 GET),语义等价且 GET 正常返回:
|
|
17
|
+
* - resolve ok → 证书存在(HTTP 200)→ 已注册
|
|
18
|
+
* - CERT_NOT_FOUND → 404 → 未注册
|
|
19
|
+
* - 其它 error → 真·网络错误,向上抛出供 fail-fast
|
|
20
|
+
* skipAgentMd:true 避免多拉一次 agent.md(控制 AID 本就不传 agent.md)。
|
|
21
|
+
*/
|
|
22
|
+
async function candidateExists(store, candidate) {
|
|
23
|
+
const r = await store.resolve(candidate, { skipAgentMd: true });
|
|
24
|
+
if (r.ok)
|
|
25
|
+
return true;
|
|
26
|
+
if (r.error?.code === 'CERT_NOT_FOUND')
|
|
27
|
+
return false;
|
|
28
|
+
throw new Error(`Gateway 不可达,无法查重控制 AID:${r.error?.message ?? 'unknown'}`);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* 生成控制 AID:循环候选 → candidateExists 查重(权威 PKI 判据)→ 不冲突则 aidCreate。
|
|
32
|
+
* - 查重走 GET 证书(见 candidateExists;不拉 agent.md,控制 AID 本就不传 agent.md)
|
|
33
|
+
* - fail-fast:查重探测失败(网关不可达)立即抛错,不掩盖成"均冲突"
|
|
34
|
+
* - agent.md 不上传:aidCreate 仅注册身份 + 写私钥,不调 agentmdPut
|
|
35
|
+
*/
|
|
36
|
+
export async function generateControlAid() {
|
|
37
|
+
const store = await getAidStore({ slotId: SLOT.cli });
|
|
38
|
+
try {
|
|
39
|
+
for (let i = 0; i < MAX_ATTEMPTS; i++) {
|
|
40
|
+
const candidate = candidateAid();
|
|
41
|
+
if (await candidateExists(store, candidate)) {
|
|
42
|
+
logger.info(`[control-aid] ${candidate} 已注册,重试 (${i + 1}/${MAX_ATTEMPTS})`);
|
|
43
|
+
continue;
|
|
44
|
+
}
|
|
45
|
+
const created = await aidCreate(candidate);
|
|
46
|
+
// 清理 aidCreate 内部另开的 client/store——关闭失败不可丢弃已注册的 AID(否则下次 init
|
|
47
|
+
// 会把它当冲突,白白消耗一次重试)。close 异常降级为 warn。
|
|
48
|
+
try {
|
|
49
|
+
await created.client?.close?.();
|
|
50
|
+
}
|
|
51
|
+
catch (e) {
|
|
52
|
+
logger.warn(`[control-aid] client.close() 失败(非致命): ${e}`);
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
await created.store?.close?.();
|
|
56
|
+
}
|
|
57
|
+
catch (e) {
|
|
58
|
+
logger.warn(`[control-aid] store.close() 失败(非致命): ${e}`);
|
|
59
|
+
}
|
|
60
|
+
return { aid: created.aid, gateway: created.gateway };
|
|
61
|
+
}
|
|
62
|
+
throw new Error(`无法生成控制 AID:连续 ${MAX_ATTEMPTS} 次候选均冲突`);
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
store.close();
|
|
66
|
+
}
|
|
67
|
+
}
|
package/dist/aun/aid/identity.js
CHANGED
|
@@ -443,6 +443,7 @@ export async function probePkiRecoverability(aid, opts) {
|
|
|
443
443
|
}
|
|
444
444
|
// ==================== Lookup ====================
|
|
445
445
|
export async function aidLookup(aid) {
|
|
446
|
+
// gateway:well-known 探测(保留,供 aid lookup 命令展示)
|
|
446
447
|
let gateway = '';
|
|
447
448
|
try {
|
|
448
449
|
const gwResp = await fetch(`https://${aid}/.well-known/aun-gateway`, { redirect: 'follow' });
|
|
@@ -464,16 +465,28 @@ export async function aidLookup(aid) {
|
|
|
464
465
|
}
|
|
465
466
|
}
|
|
466
467
|
catch { /* ignore */ }
|
|
468
|
+
const { agentmdGet } = await import('./agentmd.js');
|
|
469
|
+
const store = await getAidStore({ slotId: SLOT.cli });
|
|
467
470
|
try {
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
return { exists:
|
|
471
|
+
// 权威注册判据:PKI 证书 HEAD(与 agent.md 无关)
|
|
472
|
+
const existsResult = await store.exists(aid);
|
|
473
|
+
if (!existsResult.ok) {
|
|
474
|
+
return { exists: false, aid, gateway, error: existsResult.error?.message ?? 'exists check failed' };
|
|
472
475
|
}
|
|
473
|
-
|
|
476
|
+
const exists = existsResult.data.exists;
|
|
477
|
+
if (!exists) {
|
|
478
|
+
return { exists: false, aid, gateway };
|
|
479
|
+
}
|
|
480
|
+
// 已注册:尽力拉 agent.md content(无 agent.md 不影响 exists)
|
|
481
|
+
let content;
|
|
482
|
+
try {
|
|
483
|
+
content = await agentmdGet(aid, { store });
|
|
484
|
+
}
|
|
485
|
+
catch { /* registered but no agent.md — content stays undefined */ }
|
|
486
|
+
return { exists, aid, gateway, content };
|
|
474
487
|
}
|
|
475
|
-
|
|
476
|
-
|
|
488
|
+
finally {
|
|
489
|
+
store.close();
|
|
477
490
|
}
|
|
478
491
|
}
|
|
479
492
|
function lifecycleLogPath(aid) {
|
package/dist/aun/aid/store.js
CHANGED
|
@@ -39,10 +39,10 @@ export class AidLoadError extends Error {
|
|
|
39
39
|
*/
|
|
40
40
|
export async function getAidStore(opts) {
|
|
41
41
|
const { aunPath: defaultAunPath } = await import('../../paths.js');
|
|
42
|
-
const {
|
|
42
|
+
const { loadEvolclawConfig } = await import('../../config-store.js');
|
|
43
43
|
const { AIDStore } = await import('@agentunion/fastaun');
|
|
44
44
|
const aunPath = opts.aunPath ?? defaultAunPath();
|
|
45
|
-
const encryptionSeed =
|
|
45
|
+
const encryptionSeed = loadEvolclawConfig().aun?.encryptionSeed
|
|
46
46
|
?? process.env.AUN_ENCRYPTION_SEED
|
|
47
47
|
?? 'evol';
|
|
48
48
|
const caCertPath = path.join(aunPath, 'CA', 'root', 'root.crt');
|
|
@@ -11,7 +11,7 @@ export async function storageDownload(aid, url, localPath, opts) {
|
|
|
11
11
|
const ownerAid = cleaned.slice(0, slashIdx);
|
|
12
12
|
const objectKey = cleaned.slice(slashIdx + 1);
|
|
13
13
|
const ticketResult = await rpcCall(aid, 'storage.create_download_ticket', {
|
|
14
|
-
|
|
14
|
+
owner_aid: ownerAid,
|
|
15
15
|
object_key: objectKey,
|
|
16
16
|
}, { aunPath: opts?.aunPath });
|
|
17
17
|
if (!ticketResult.ok) {
|
|
@@ -27,9 +27,21 @@ export async function storageUpload(aid, localFile, remotePath, opts) {
|
|
|
27
27
|
const completeResult = await rpcCall(aid, 'storage.complete_upload', {
|
|
28
28
|
object_key: remotePath,
|
|
29
29
|
sha256,
|
|
30
|
+
is_private: !(opts?.isPublic),
|
|
30
31
|
}, { aunPath: opts?.aunPath });
|
|
31
32
|
if (!completeResult.ok) {
|
|
32
33
|
return { ok: false, objectKey: remotePath, error: JSON.stringify(completeResult.error) };
|
|
33
34
|
}
|
|
34
|
-
|
|
35
|
+
// 公开上传时获取可访问的 URL
|
|
36
|
+
let publicUrl;
|
|
37
|
+
if (opts?.isPublic) {
|
|
38
|
+
const ticketResult = await rpcCall(aid, 'storage.create_download_ticket', {
|
|
39
|
+
object_key: remotePath,
|
|
40
|
+
expire_in_seconds: 86400 * 30, // 30天
|
|
41
|
+
}, { aunPath: opts?.aunPath });
|
|
42
|
+
if (ticketResult.ok) {
|
|
43
|
+
publicUrl = `https://${aid}/storage/${remotePath}`;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return { ok: true, objectKey: remotePath, publicUrl };
|
|
35
47
|
}
|