evolclaw 3.1.4 → 3.1.5

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.
Files changed (85) hide show
  1. package/CHANGELOG.md +10 -0
  2. package/dist/agents/claude-runner.js +348 -156
  3. package/dist/agents/kit-renderer.js +176 -21
  4. package/dist/aun/aid/agentmd.js +68 -103
  5. package/dist/aun/aid/client.js +1 -29
  6. package/dist/aun/aid/identity.js +105 -64
  7. package/dist/aun/aid/index.js +2 -1
  8. package/dist/aun/aid/store.js +74 -0
  9. package/dist/aun/msg/p2p.js +26 -2
  10. package/dist/aun/rpc/connection.js +23 -30
  11. package/dist/channels/aun.js +77 -88
  12. package/dist/channels/dingtalk.js +1 -0
  13. package/dist/channels/feishu.js +270 -190
  14. package/dist/channels/qqbot.js +1 -0
  15. package/dist/channels/wechat.js +1 -0
  16. package/dist/channels/wecom.js +1 -0
  17. package/dist/cli/agent.js +11 -5
  18. package/dist/cli/bench.js +40 -23
  19. package/dist/cli/index.js +170 -44
  20. package/dist/cli/init-channel.js +5 -1
  21. package/dist/cli/model.js +324 -0
  22. package/dist/cli/net-check.js +133 -50
  23. package/dist/cli/watch-msg.js +7 -7
  24. package/dist/cli/watch-web/debug-log.js +18 -0
  25. package/dist/cli/watch-web/server.js +306 -0
  26. package/dist/cli/watch-web/sources/aid.js +63 -0
  27. package/dist/cli/watch-web/sources/msg.js +70 -0
  28. package/dist/cli/watch-web/sources/session.js +638 -0
  29. package/dist/cli/watch-web/sources/types.js +10 -0
  30. package/dist/cli/watch-web/static/app.js +546 -0
  31. package/dist/cli/watch-web/static/index.html +54 -0
  32. package/dist/cli/watch-web/static/style.css +247 -0
  33. package/dist/core/channel-loader.js +7 -4
  34. package/dist/core/command-handler.js +81 -86
  35. package/dist/core/evolagent-registry.js +1 -1
  36. package/dist/core/evolagent.js +4 -4
  37. package/dist/core/interaction-router.js +59 -0
  38. package/dist/core/message/message-bridge.js +6 -6
  39. package/dist/core/message/message-log.js +2 -2
  40. package/dist/core/message/message-processor.js +86 -101
  41. package/dist/core/message/stream-idle-monitor.js +21 -0
  42. package/dist/core/model/model-catalog.js +215 -0
  43. package/dist/core/model/model-scope.js +250 -0
  44. package/dist/core/relation/peer-identity.js +40 -49
  45. package/dist/core/relation/peer-key.js +16 -0
  46. package/dist/core/session/session-fs-store.js +34 -55
  47. package/dist/core/session/session-key.js +24 -0
  48. package/dist/core/session/session-manager.js +308 -251
  49. package/dist/core/session/session-mapper.js +9 -4
  50. package/dist/core/trigger/manager.js +3 -3
  51. package/dist/core/trigger/scheduler.js +2 -1
  52. package/dist/index.js +6 -2
  53. package/dist/ipc.js +22 -0
  54. package/kits/docs/GUIDE.md +2 -2
  55. package/kits/docs/INDEX.md +11 -7
  56. package/kits/docs/channels/aun.md +56 -17
  57. package/kits/docs/channels/feishu.md +41 -12
  58. package/kits/docs/context-assembly.md +181 -0
  59. package/kits/docs/evolclaw/agent.md +49 -0
  60. package/kits/docs/evolclaw/aid.md +49 -0
  61. package/kits/docs/evolclaw/ctl.md +46 -0
  62. package/kits/docs/evolclaw/group.md +82 -0
  63. package/kits/docs/evolclaw/msg.md +86 -0
  64. package/kits/docs/evolclaw/rpc.md +35 -0
  65. package/kits/docs/evolclaw/storage.md +49 -0
  66. package/kits/docs/venues/aun-group.md +10 -0
  67. package/kits/docs/venues/aun-private.md +10 -0
  68. package/kits/docs/venues/client-desktop.md +10 -0
  69. package/kits/docs/venues/client-mobile.md +10 -0
  70. package/kits/docs/venues/feishu-group.md +13 -0
  71. package/kits/docs/venues/feishu-private.md +9 -0
  72. package/kits/docs/venues/group.md +11 -0
  73. package/kits/docs/venues/private.md +10 -0
  74. package/kits/eck_manifest.json +72 -36
  75. package/kits/rules/01-overview.md +20 -10
  76. package/kits/rules/06-channel.md +30 -27
  77. package/kits/templates/system-fragments/session.md +10 -3
  78. package/kits/templates/system-fragments/venue.md +9 -0
  79. package/package.json +11 -6
  80. package/dist/aun/aid/lifecycle-log.js +0 -33
  81. package/dist/utils/aid-lifecycle-log.js +0 -33
  82. package/kits/docs/evolclaw/AGENT_CMD.md +0 -31
  83. package/kits/docs/evolclaw/MSG_GROUP.md +0 -30
  84. package/kits/docs/evolclaw/MSG_PRIVATE.md +0 -72
  85. package/kits/docs/evolclaw/tools.md +0 -25
@@ -12,8 +12,8 @@ import { appendAidEvent } from '../utils/instance-registry.js';
12
12
  import { appendMessageLog, buildOutboundEntry } from '../core/message/message-log.js';
13
13
  import { chatDirPath } from '../core/session/session-fs-store.js';
14
14
  import { appendAidLifecycle } from '../aun/aid/identity.js';
15
- import { createAunClient } from '../aun/aid/client.js';
16
- import { loadAgent, saveAgent, loadProcessConfig } from '../config-store.js';
15
+ import { getAidStore, loadClient, SLOT } from '../aun/aid/store.js';
16
+ import { loadAgent, saveAgent } from '../config-store.js';
17
17
  import { getProcessStartTime } from '../utils/process-introspect.js';
18
18
  import * as outbox from '../aun/outbox.js';
19
19
  import { guessMime, formatSize } from '../utils/media-cache.js';
@@ -61,6 +61,9 @@ function getEvolclawVersion() {
61
61
  export class AUNChannel {
62
62
  config;
63
63
  client = null;
64
+ store = null;
65
+ /** 实际连接的网关 URL(来自 authenticate() 返回值 / connection.state 事件),替代旧 (client as any)._gatewayUrl。 */
66
+ gatewayUrl = '';
64
67
  projectPathProvider;
65
68
  messageHandler;
66
69
  recallHandler;
@@ -115,11 +118,6 @@ export class AUNChannel {
115
118
  */
116
119
  async callAndTrace(method, params, opts) {
117
120
  this.trace('OUT', method, params);
118
- // [DIAG-STALE] 记录调用瞬间 SDK 内部 _state,证明是否在 reconnecting 中误发
119
- const sdkStateBefore = this.client?._state ?? 'no-client';
120
- if (sdkStateBefore !== 'connected') {
121
- logger.warn(`[AUN][DIAG-STALE] callAndTrace ${method} on non-connected SDK: sdk_state=${sdkStateBefore} evolclaw_connected=${this.connected}`);
122
- }
123
121
  try {
124
122
  const result = await this.client.call(method, params);
125
123
  if (!opts?.silentOk) {
@@ -137,9 +135,6 @@ export class AUNChannel {
137
135
  code: e?.code,
138
136
  name: e?.name,
139
137
  });
140
- // [DIAG-STALE] 失败时再记录一次 SDK _state,看错误类型是否为 ConnectionError
141
- const sdkStateAfter = this.client?._state ?? 'no-client';
142
- logger.warn(`[AUN][DIAG-STALE] callAndTrace ${method} FAILED: err_name=${e?.name ?? '?'} err_code=${e?.code ?? '?'} sdk_state_before=${sdkStateBefore} sdk_state_after=${sdkStateAfter} evolclaw_connected=${this.connected}`);
143
138
  logger.warn(`${this.logPrefix()} rpc ${method} failed: ${e?.name ?? ''}(${e?.code ?? ''}) ${e?.message ?? e}`);
144
139
  throw e;
145
140
  }
@@ -545,12 +540,17 @@ export class AUNChannel {
545
540
  }
546
541
  this.client = null;
547
542
  }
543
+ if (this.store) {
544
+ try {
545
+ this.store.close();
546
+ }
547
+ catch { /* ignore */ }
548
+ this.store = null;
549
+ }
548
550
  this.connected = false;
549
551
  const aunPath = this.config.keystorePath || resolveRoot();
550
552
  const aidName = this.config.aid;
551
- const encryptionSeed = loadProcessConfig().aun?.encryptionSeed
552
- || process.env.AUN_ENCRYPTION_SEED
553
- || 'evol';
553
+ // encryptionSeed getAidStore 内部解析(config / env / 'evol')
554
554
  // Migration from ~/.aun is handled by ensureDataDirs() at startup with a marker file.
555
555
  // Gateway URL 解析:优先用配置的 gatewayUrl,否则通过 well-known 自动发现
556
556
  let gateway = this.config.gatewayUrl || '';
@@ -571,16 +571,18 @@ export class AUNChannel {
571
571
  throw new Error('Cannot resolve gateway URL from AID');
572
572
  }
573
573
  logger.info(`${this.logPrefix()} Initializing: aid=${aidName}, gateway=${gateway}, aun_path=${aunPath}`);
574
- // Create client with FileSecretStore (AES-256-GCM)
575
- // 不传 encryption_seed 时,SDK 自动从 {aun_path}/.seed 文件派生密钥(与 aun_cli.py 对齐)
576
- const client = await createAunClient({
574
+ // 构造 AIDStore(slot=evolclaw daemon,与 cli/netcheck 共享 evolclaw 隔离键)
575
+ // encryptionSeed / rootCaPath getAidStore 内部注入
576
+ const store = await getAidStore({
577
+ slotId: SLOT.daemon,
577
578
  aunPath,
578
- encryptionSeed,
579
- aunSdkLog: this.config.aunSdkLog ?? true,
579
+ debug: this.config.aunSdkLog ?? true,
580
580
  });
581
+ this.store = store;
582
+ const client = await loadClient(store, aidName);
581
583
  this.client = client;
582
- // Set gateway URL (internal property, same as Python SDK)
583
- client._gatewayUrl = gateway;
584
+ // 记录应用层发现的 gateway 作为初始值(authenticate 后会用权威值覆盖)
585
+ this.gatewayUrl = gateway;
584
586
  // Register event handlers before connecting
585
587
  client.on('message.received', (data) => {
586
588
  this.trace('IN', 'message.received', data);
@@ -629,30 +631,16 @@ export class AUNChannel {
629
631
  const d = data;
630
632
  logger.warn(`${this.logPrefix()} Group message undecryptable: group=${d.group_id} from=${d.from} mid=${d.message_id} err=${d._decrypt_error}`);
631
633
  });
632
- // Authenticate
633
- // Workaround: SDK 0.3.x _loadIdentityOrRaise doesn't set identity.aid from requested aid,
634
- // causing gateway "missing aid" error. Patch to backfill aid on loaded identity.
635
- const authFlow = client._auth;
636
- if (authFlow && typeof authFlow._loadIdentityOrRaise === 'function') {
637
- const origLoad = authFlow._loadIdentityOrRaise.bind(authFlow);
638
- authFlow._loadIdentityOrRaise = (aid) => {
639
- const identity = origLoad(aid);
640
- if (identity && !identity.aid)
641
- identity.aid = aid ?? authFlow._aid;
642
- return identity;
643
- };
644
- }
645
- let accessToken;
634
+ // Authenticate(拿权威 gateway 用于日志/状态;connect 内部也会复用 token)
646
635
  try {
647
636
  logger.info(`${this.logPrefix()} Authenticating as ${aidName}...`);
648
637
  this.trace('OUT', 'auth.authenticate', { aid: aidName });
649
- const auth = await client.auth.authenticate(aidName ? { aid: aidName } : undefined);
650
- this.trace('OUT', 'auth.authenticate.ok', { aid: auth.aid, gateway: auth.gateway, hasToken: !!auth.access_token });
651
- this.trace('IN', 'auth.result', { aid: auth.aid, gateway: auth.gateway, hasToken: !!auth.access_token });
652
- accessToken = auth.access_token;
653
- const resolvedGateway = auth.gateway || gateway;
654
- client._gatewayUrl = resolvedGateway;
655
- logger.info(`${this.logPrefix()} Authenticated as ${auth.aid ?? '?'}, gateway=${resolvedGateway}`);
638
+ const auth = await client.authenticate();
639
+ this.trace('OUT', 'auth.authenticate.ok', { aid: client.aid, gateway: auth?.gateway, hasToken: !!auth?.access_token });
640
+ this.trace('IN', 'auth.result', { aid: client.aid, gateway: auth?.gateway, hasToken: !!auth?.access_token });
641
+ const resolvedGateway = String(auth?.gateway ?? gateway);
642
+ this.gatewayUrl = resolvedGateway;
643
+ logger.info(`${this.logPrefix()} Authenticated as ${client.aid ?? '?'}, gateway=${resolvedGateway}`);
656
644
  }
657
645
  catch (e) {
658
646
  const errMsg = e.message || String(e);
@@ -661,15 +649,9 @@ export class AUNChannel {
661
649
  logger.error(`${this.logPrefix()} Authentication failed (${errName}): ${errMsg}`);
662
650
  if (e.stack)
663
651
  logger.debug(`${this.logPrefix()} Auth stack: ${e.stack}`);
664
- // Fallback: try direct token from env/config (legacy)
665
- accessToken = this.config.accessToken || process.env.AUN_ACCESS_TOKEN || '';
666
- if (!accessToken) {
667
- logger.error(`${this.logPrefix()} No accessToken fallback available, scheduling retry`);
668
- this.setAidStatus('failed', { lastError: `${errName}: ${errMsg}`.slice(0, 80) });
669
- this.scheduleReconnect();
670
- throw new Error('Authentication failed and no accessToken fallback available');
671
- }
672
- logger.warn(`${this.logPrefix()} Using accessToken fallback`);
652
+ this.setAidStatus('failed', { lastError: `${errName}: ${errMsg}`.slice(0, 80) });
653
+ this.scheduleReconnect();
654
+ throw new Error(`Authentication failed: ${errName}: ${errMsg}`);
673
655
  }
674
656
  // Connect (SDK auto_reconnect handles transient failures)
675
657
  try {
@@ -678,11 +660,18 @@ export class AUNChannel {
678
660
  agentName: this.config.agentName,
679
661
  channelName: this.config.channelName,
680
662
  });
681
- this.trace('OUT', 'client.connect', { gateway: client._gatewayUrl, extra_info: extraInfo });
682
- await client.connect({ access_token: accessToken, gateway: client._gatewayUrl, extra_info: extraInfo },
683
- // max_attempts=0 = 无限重试(与 Go/Python 对齐),交由 SDK 自己跑指数退避
684
- // initial_delay=1s,max_delay=300s(5min 封顶)
685
- { auto_reconnect: true, retry: { max_attempts: 0, initial_delay: 1.0, max_delay: 300.0 } });
663
+ this.trace('OUT', 'client.connect', { gateway: this.gatewayUrl, extra_info: extraInfo });
664
+ await client.connect({
665
+ // connection_kind 默认 long;slot 已由 AID 携带(evolclaw daemon)
666
+ // extra_info:互踢诊断名片(0.4.3 公开 connect 已支持透传)
667
+ extra_info: extraInfo,
668
+ // max_attempts=0 = 无限重试(与 Go/Python 对齐),交由 SDK 自己跑指数退避
669
+ // initial_delay=1s,max_delay=300s(5min 封顶)
670
+ auto_reconnect: true,
671
+ retry_max_attempts: 0,
672
+ retry_initial_delay: 1.0,
673
+ retry_max_delay: 300.0,
674
+ });
686
675
  this.trace('OUT', 'client.connect.ok', { aid: client.aid });
687
676
  this._aid = this.client.aid ?? undefined;
688
677
  const deviceId = this.client._device_id ?? '';
@@ -692,7 +681,7 @@ export class AUNChannel {
692
681
  this.aidStatsCollector.setSelfName(this.config.aid, this._selfName);
693
682
  this.connected = true;
694
683
  this.connectedAt = Date.now();
695
- this.setAidStatus('connected', { lastConnectedAt: Date.now(), lastError: undefined, gatewayUrl: this.client?._gatewayUrl });
684
+ this.setAidStatus('connected', { lastConnectedAt: Date.now(), lastError: undefined, gatewayUrl: this.gatewayUrl });
696
685
  // Workaround: SDK e2ee uses _identity.cert for sender_cert_fingerprint;
697
686
  // if cert is missing, it falls back to public key SPKI fingerprint which
698
687
  // causes peer cert lookup failures. Backfill from keystore if needed.
@@ -705,8 +694,8 @@ export class AUNChannel {
705
694
  }
706
695
  }
707
696
  logger.info(`${this.logPrefix()} Connected as ${this._aid}`);
708
- appendAidEvent({ ts: Date.now(), iso: new Date().toISOString(), event: 'connected', aid: this.config.aid, gateway: this.client._gatewayUrl });
709
- appendAidLifecycle({ ts: Date.now(), iso: new Date().toISOString(), event: 'connected', aid: this.config.aid, gateway: this.client._gatewayUrl });
697
+ appendAidEvent({ ts: Date.now(), iso: new Date().toISOString(), event: 'connected', aid: this.config.aid, gateway: this.gatewayUrl });
698
+ appendAidLifecycle({ ts: Date.now(), iso: new Date().toISOString(), event: 'connected', aid: this.config.aid, gateway: this.gatewayUrl });
710
699
  // Send welcome message to owner after first connection
711
700
  await this.sendWelcomeMessage();
712
701
  }
@@ -785,13 +774,10 @@ tags:
785
774
 
786
775
  EvolClaw AI Agent 网关,支持多项目会话管理和多 AI 后端切换。
787
776
  `;
788
- // Write locally
789
- fs.mkdirSync(path.dirname(agentMdLocalPath), { recursive: true });
790
- fs.writeFileSync(agentMdLocalPath, newAgentMd, 'utf-8');
791
- logger.info(`${this.logPrefix()} Updated agent.md for ${aidName}`);
792
- // Publish to AUN network via publishAgentMd (auto-sign)
777
+ // Write locally and publish to AUN network (auto-sign)
793
778
  try {
794
- await this.client.publishAgentMd();
779
+ const { agentmdPut } = await import('../aun/aid/agentmd.js');
780
+ await agentmdPut(newAgentMd, { aid: aidName, store: this.store });
795
781
  logger.info(`${this.logPrefix()} Published agent.md to AUN network`);
796
782
  }
797
783
  catch (e) {
@@ -961,7 +947,7 @@ EvolClaw AI Agent 网关,支持多项目会话管理和多 AI 后端切换。
961
947
  const chatId = fromAid;
962
948
  // 解析对端身份(30天缓存)
963
949
  const selfAgentDir = path.join(resolvePaths().agentsDir, this.config.aid);
964
- const peerIdentity = await PeerIdentityCache.resolve('aun', fromAid, selfAgentDir, this.client, false);
950
+ const peerIdentity = await PeerIdentityCache.resolve('aun', fromAid, selfAgentDir, this.store, false);
965
951
  const shortAid = this.getShortAid(fromAid);
966
952
  const displayName = peerIdentity.name || shortAid;
967
953
  // 详细 dispatch 决策日志:记录消息为何被路由到 agent
@@ -1177,7 +1163,7 @@ EvolClaw AI Agent 网关,支持多项目会话管理和多 AI 后端切换。
1177
1163
  }
1178
1164
  }
1179
1165
  const selfAgentDir = path.join(resolvePaths().agentsDir, this.config.aid);
1180
- const peerIdentity = await PeerIdentityCache.resolve('aun', senderAid, selfAgentDir, this.client, false);
1166
+ const peerIdentity = await PeerIdentityCache.resolve('aun', senderAid, selfAgentDir, this.store, false);
1181
1167
  const shortAid = this.getShortAid(senderAid);
1182
1168
  const displayName = peerIdentity.name || shortAid;
1183
1169
  // 详细 dispatch 决策日志:记录消息为何被路由到 agent
@@ -1268,7 +1254,7 @@ EvolClaw AI Agent 网关,支持多项目会话管理和多 AI 后端切换。
1268
1254
  channelId: event.channelId || '',
1269
1255
  channelType: 'aun',
1270
1256
  content: event.text || '',
1271
- selfId: this._aid,
1257
+ selfAID: this._aid,
1272
1258
  groupId: event.groupId,
1273
1259
  chatType: event.chatType,
1274
1260
  peerId: event.userId || event.channelId || '',
@@ -1351,17 +1337,16 @@ EvolClaw AI Agent 网关,支持多项目会话管理和多 AI 后端切换。
1351
1337
  if (!data || typeof data !== 'object')
1352
1338
  return;
1353
1339
  const state = data.state ?? '';
1354
- // [DIAG-STALE] 记录状态切换瞬间 evolclaw 的 connected 标志和 SDK 的内部 _state,
1355
- // 用于证明"reconnecting 时 connected 保持 true,导致 sendMessage 误放行"的假设
1356
- const sdkState = this.client?._state ?? 'no-client';
1357
- const connectedBefore = this.connected;
1358
- logger.info(`[AUN][DIAG-STALE] connection.state event: state=${state} attempt=${data.attempt ?? '-'} | connected_before=${connectedBefore} sdk_state=${sdkState}`);
1359
1340
  if (state === 'connected') {
1360
1341
  this.connected = true;
1361
1342
  this.connectedAt = Date.now();
1362
1343
  this.lastReconnectLogTime = 0;
1363
1344
  this.lastReconnectLogAttempt = 0;
1364
- this.setAidStatus('connected', { lastConnectedAt: Date.now(), lastError: undefined, gatewayUrl: this.client?._gatewayUrl });
1345
+ // connection.state 事件 payload 带实际连接的 gateway,更新本地缓存
1346
+ const evtGateway = data.gateway;
1347
+ if (typeof evtGateway === 'string' && evtGateway)
1348
+ this.gatewayUrl = evtGateway;
1349
+ this.setAidStatus('connected', { lastConnectedAt: Date.now(), lastError: undefined, gatewayUrl: this.gatewayUrl });
1365
1350
  this.trace('IN', 'connection.state', data);
1366
1351
  logger.info(`${this.logPrefix()} Connected`);
1367
1352
  // 不在这里清 flapCount —— 短命连接一上来就会触发本分支,
@@ -1816,11 +1801,11 @@ EvolClaw AI Agent 网关,支持多项目会话管理和多 AI 后端切换。
1816
1801
  appendOutboundJsonl(channelId, text, msgId, encrypt, context, isGroup, msgType = 'text', source = 'daemon') {
1817
1802
  try {
1818
1803
  const sessionsDir = resolvePaths().sessionsDir;
1819
- const selfId = this.config.aid;
1820
- const chatDir = chatDirPath(sessionsDir, 'aun', channelId, selfId);
1804
+ const selfAID = this.config.aid;
1805
+ const chatDir = chatDirPath(sessionsDir, 'aun', channelId, selfAID);
1821
1806
  const chatmode = context?.metadata?.chatmode;
1822
1807
  appendMessageLog(chatDir, buildOutboundEntry({
1823
- from: selfId,
1808
+ from: selfAID,
1824
1809
  to: channelId,
1825
1810
  chatType: isGroup ? 'group' : 'private',
1826
1811
  groupId: isGroup ? channelId : null,
@@ -1891,8 +1876,8 @@ EvolClaw AI Agent 网关,支持多项目会话管理和多 AI 后端切换。
1891
1876
  const tid = putRes?.thought_id;
1892
1877
  logger.info(`${this.logPrefix()} thought.put ok group=${targetId} task=${taskId} stage=${stage} encrypt=${encrypt} tid=${tid ?? '?'}`);
1893
1878
  this.eventBus?.publish?.({ type: 'message:thought-put', agentName: this.config.aid, channelId, taskId, text: thoughtText });
1894
- // 文本类 thought 写入 jsonl(只对有 text 的 item,过滤 tool 等结构化项)
1895
1879
  if (thoughtText) {
1880
+ this.aidStatsCollector?.recordOutbound(this.config.aid, channelId, Buffer.byteLength(thoughtText, 'utf-8'), thoughtText, false, encrypt, context?.metadata?.chatmode ?? 'proactive');
1896
1881
  this.appendOutboundJsonl(channelId, thoughtText, tid ?? `thought-${Date.now()}`, encrypt, context, true, 'thought', 'daemon');
1897
1882
  }
1898
1883
  }
@@ -1903,6 +1888,7 @@ EvolClaw AI Agent 网关,支持多项目会话管理和多 AI 后端切换。
1903
1888
  logger.info(`${this.logPrefix()} thought.put ok p2p=${this.peerLabel(targetId)} task=${taskId} stage=${stage} encrypt=${encrypt} tid=${tid ?? '?'}`);
1904
1889
  this.eventBus?.publish?.({ type: 'message:thought-put', agentName: this.config.aid, channelId, taskId, text: thoughtText });
1905
1890
  if (thoughtText) {
1891
+ this.aidStatsCollector?.recordOutbound(this.config.aid, targetId, Buffer.byteLength(thoughtText, 'utf-8'), thoughtText, false, encrypt, context?.metadata?.chatmode ?? 'proactive');
1906
1892
  this.appendOutboundJsonl(channelId, thoughtText, tid ?? `thought-${Date.now()}`, encrypt, context, false, 'thought', 'daemon');
1907
1893
  }
1908
1894
  }
@@ -2280,6 +2266,13 @@ EvolClaw AI Agent 网关,支持多项目会话管理和多 AI 后端切换。
2280
2266
  }
2281
2267
  this.client = null;
2282
2268
  }
2269
+ if (this.store) {
2270
+ try {
2271
+ this.store.close();
2272
+ }
2273
+ catch { /* ignore */ }
2274
+ this.store = null;
2275
+ }
2283
2276
  this.connected = false;
2284
2277
  appendAidEvent({ ts: Date.now(), iso: new Date().toISOString(), event: 'disconnected', aid: this.config.aid, reason: 'intentional' });
2285
2278
  appendAidLifecycle({ ts: Date.now(), iso: new Date().toISOString(), event: 'disconnected', aid: this.config.aid, reason: 'intentional' });
@@ -2381,7 +2374,7 @@ EvolClaw AI Agent 网关,支持多项目会话管理和多 AI 后端切换。
2381
2374
  return { type: null };
2382
2375
  try {
2383
2376
  const selfAgentDir = path.join(resolvePaths().agentsDir, this.config.aid);
2384
- const identity = await PeerIdentityCache.resolve('aun', aid, selfAgentDir, this.client, false);
2377
+ const identity = await PeerIdentityCache.resolve('aun', aid, selfAgentDir, this.store, false);
2385
2378
  const type = identity.type === 'human' ? 'human' : 'ai';
2386
2379
  const name = identity.name || undefined;
2387
2380
  const info = { type, name };
@@ -2405,19 +2398,16 @@ EvolClaw AI Agent 网关,支持多项目会话管理和多 AI 后端切换。
2405
2398
  void this.fetchPeerInfo(aid).catch(() => { });
2406
2399
  }
2407
2400
  async uploadAgentMd(content) {
2408
- if (!this.client)
2401
+ if (!this.store)
2409
2402
  throw new Error('not connected');
2410
- const { agentMdPath } = await import('../paths.js');
2411
- const localPath = agentMdPath(this.config.aid);
2412
- fs.mkdirSync(path.dirname(localPath), { recursive: true });
2413
- fs.writeFileSync(localPath, content, 'utf-8');
2414
- await this.client.publishAgentMd();
2403
+ const { agentmdPut } = await import('../aun/aid/agentmd.js');
2404
+ await agentmdPut(content, { aid: this.config.aid, store: this.store });
2415
2405
  }
2416
2406
  async downloadAgentMd(aid) {
2417
- if (!this.client)
2407
+ if (!this.store)
2418
2408
  throw new Error('not connected');
2419
2409
  const { agentmdSync } = await import('../aun/aid/agentmd.js');
2420
- const result = await agentmdSync(aid, { client: this.client });
2410
+ const result = await agentmdSync(aid, { store: this.store ?? undefined });
2421
2411
  return result.content ?? '';
2422
2412
  }
2423
2413
  }
@@ -2445,7 +2435,6 @@ export class AUNChannelPlugin {
2445
2435
  gatewayUrl: inst.gatewayUrl,
2446
2436
  accessToken: inst.accessToken,
2447
2437
  flushDelay: inst.flushDelay,
2448
- encryptionSeed: inst.encryptionSeed,
2449
2438
  owner: inst.owner,
2450
2439
  agentName: inst.agentName,
2451
2440
  channelName: inst.name,
@@ -2636,7 +2625,7 @@ export class AUNChannelPlugin {
2636
2625
  channel: adapter.channelName,
2637
2626
  channelType,
2638
2627
  channelId: opts.channelId,
2639
- selfId: opts.selfId,
2628
+ selfAID: opts.selfAID,
2640
2629
  groupId: opts.groupId,
2641
2630
  content: opts.content,
2642
2631
  chatType: opts.chatType || 'private',
@@ -540,6 +540,7 @@ export class DingtalkChannelPlugin {
540
540
  channel: adapter.channelName,
541
541
  channelType,
542
542
  channelId: event.channelId,
543
+ selfAID: inst.agentName,
543
544
  content: event.content,
544
545
  images: event.images,
545
546
  chatType: event.chatType || 'private',