evolclaw 2.1.2 → 2.2.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/README.md +10 -3
- package/data/evolclaw.sample.json +9 -1
- package/dist/agents/claude-runner.js +612 -0
- package/dist/agents/codex-runner.js +310 -0
- package/dist/channels/aun.js +416 -9
- package/dist/channels/feishu.js +397 -104
- package/dist/channels/wechat.js +84 -2
- package/dist/cli.js +427 -126
- package/dist/config.js +102 -4
- package/dist/core/adapters/claude-session-file-adapter.js +144 -0
- package/dist/core/adapters/codex-session-file-adapter.js +196 -0
- package/dist/core/agent-loader.js +39 -0
- package/dist/core/channel-loader.js +60 -0
- package/dist/core/command-handler.js +908 -304
- package/dist/core/event-bus.js +32 -0
- package/dist/core/ipc-server.js +71 -0
- package/dist/core/message-bridge.js +187 -0
- package/dist/core/message-processor.js +370 -227
- package/dist/core/message-queue.js +153 -29
- package/dist/core/permission.js +58 -0
- package/dist/core/session-file-adapter.js +7 -0
- package/dist/core/session-manager.js +567 -205
- package/dist/core/stats-collector.js +86 -0
- package/dist/index.js +309 -243
- package/dist/paths.js +1 -0
- package/dist/utils/init-feishu.js +2 -0
- package/dist/utils/init-wechat.js +2 -0
- package/dist/utils/init.js +285 -53
- package/dist/utils/ipc-client.js +36 -0
- package/dist/utils/migrate-project.js +122 -0
- package/dist/utils/{permission.js → permission-utils.js} +31 -3
- package/dist/utils/rich-content-renderer.js +228 -0
- package/dist/utils/session-file-health.js +11 -34
- package/dist/utils/stream-debouncer.js +122 -0
- package/dist/utils/stream-idle-monitor.js +1 -1
- package/package.json +3 -1
- package/dist/core/agent-runner.js +0 -348
- package/dist/core/message-stream.js +0 -59
- package/dist/index.js.bak +0 -340
- package/dist/utils/markdown-to-feishu.js +0 -94
- /package/dist/utils/{platform.js → cross-platform.js} +0 -0
- /package/dist/{core → utils}/message-cache.js +0 -0
package/dist/channels/aun.js
CHANGED
|
@@ -1,28 +1,435 @@
|
|
|
1
|
+
import { AUNClient } from '@aun/core-node';
|
|
1
2
|
import { logger } from '../utils/logger.js';
|
|
2
3
|
export class AUNChannel {
|
|
3
4
|
config;
|
|
5
|
+
client = null;
|
|
4
6
|
messageHandler;
|
|
5
7
|
connected = false;
|
|
8
|
+
_aid;
|
|
9
|
+
seenMessages = new Map();
|
|
10
|
+
messageSeqMap = new Map(); // messageId → seq (for ack)
|
|
11
|
+
sentCount = new Map(); // channelId → 已发消息计数(用于判断最终回复)
|
|
12
|
+
// Reconnect state (TS-layer fallback, on top of SDK auto_reconnect)
|
|
13
|
+
intentionalDisconnect = false;
|
|
14
|
+
reconnectAttempt = 0;
|
|
15
|
+
reconnectTimer = null;
|
|
16
|
+
static RECONNECT_DELAYS = [60, 120, 300, 600]; // seconds
|
|
17
|
+
onChannelDown;
|
|
6
18
|
constructor(config) {
|
|
7
19
|
this.config = config;
|
|
8
20
|
}
|
|
9
21
|
async connect() {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
this.
|
|
13
|
-
logger.info(`[AUN] Connected as ${this.config.agentName}@${this.config.domain}`);
|
|
22
|
+
this.intentionalDisconnect = false;
|
|
23
|
+
this.reconnectAttempt = 0;
|
|
24
|
+
await this.initClient();
|
|
14
25
|
}
|
|
26
|
+
async initClient() {
|
|
27
|
+
// Clean up existing client if any
|
|
28
|
+
if (this.client) {
|
|
29
|
+
try {
|
|
30
|
+
await this.client.close();
|
|
31
|
+
}
|
|
32
|
+
catch { /* ignore */ }
|
|
33
|
+
this.client = null;
|
|
34
|
+
}
|
|
35
|
+
this.connected = false;
|
|
36
|
+
const aunPath = this.config.keystorePath || `${process.env.HOME || '~'}/.aun`;
|
|
37
|
+
const aidName = this.config.aid;
|
|
38
|
+
const encryptionSeed = this.config.encryptionSeed || process.env.AUN_ENCRYPTION_SEED || undefined;
|
|
39
|
+
// Gateway URL: 旧配置 gatewayUrl 优先,否则从 AID 推导
|
|
40
|
+
let gateway = this.config.gatewayUrl || '';
|
|
41
|
+
if (!gateway) {
|
|
42
|
+
const parts = aidName.split('.');
|
|
43
|
+
if (parts.length >= 3) {
|
|
44
|
+
const domain = parts.slice(1).join('.'); // alice.agentid.pub → agentid.pub
|
|
45
|
+
const port = this.config.gatewayPort || 443;
|
|
46
|
+
gateway = `wss://gateway.${domain}:${port}/aun`;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (!gateway) {
|
|
50
|
+
logger.error('[AUN] Cannot derive gateway URL from AID');
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
logger.info(`[AUN] Initializing: aid=${aidName}, gateway=${gateway}, aun_path=${aunPath}`);
|
|
54
|
+
// Create client with FileSecretStore (AES-256-GCM)
|
|
55
|
+
// 不传 encryption_seed 时,SDK 自动从 {aun_path}/.seed 文件派生密钥(与 aun_cli.py 对齐)
|
|
56
|
+
this.client = new AUNClient({
|
|
57
|
+
aun_path: aunPath,
|
|
58
|
+
...(encryptionSeed && { encryption_seed: encryptionSeed }),
|
|
59
|
+
});
|
|
60
|
+
// Set gateway URL (internal property, same as Python SDK)
|
|
61
|
+
this.client._gatewayUrl = gateway;
|
|
62
|
+
// Register event handlers before connecting
|
|
63
|
+
this.client.on('message.received', (data) => this.handleIncomingPrivateMessage(data));
|
|
64
|
+
this.client.on('group.message_created', (data) => this.handleIncomingGroupMessage(data));
|
|
65
|
+
this.client.on('connection.state', (data) => this.handleConnectionState(data));
|
|
66
|
+
// Authenticate
|
|
67
|
+
let accessToken;
|
|
68
|
+
try {
|
|
69
|
+
logger.info(`[AUN] Authenticating as ${aidName}...`);
|
|
70
|
+
const auth = await this.client.auth.authenticate(aidName ? { aid: aidName } : undefined);
|
|
71
|
+
accessToken = auth.access_token;
|
|
72
|
+
const resolvedGateway = auth.gateway || gateway;
|
|
73
|
+
this.client._gatewayUrl = resolvedGateway;
|
|
74
|
+
logger.info(`[AUN] Authenticated as ${auth.aid ?? '?'}, gateway=${resolvedGateway}`);
|
|
75
|
+
}
|
|
76
|
+
catch (e) {
|
|
77
|
+
const errMsg = e.message || String(e);
|
|
78
|
+
const errName = e.constructor?.name || 'Error';
|
|
79
|
+
logger.error(`[AUN] Authentication failed (${errName}): ${errMsg}`);
|
|
80
|
+
if (e.stack)
|
|
81
|
+
logger.debug(`[AUN] Auth stack: ${e.stack}`);
|
|
82
|
+
// Fallback: try direct token from env/config (legacy)
|
|
83
|
+
accessToken = this.config.accessToken || process.env.AUN_ACCESS_TOKEN || '';
|
|
84
|
+
if (!accessToken) {
|
|
85
|
+
logger.error(`[AUN] No accessToken fallback available, AUN channel disabled`);
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
logger.warn(`[AUN] Using accessToken fallback`);
|
|
89
|
+
}
|
|
90
|
+
// Connect (SDK auto_reconnect handles transient failures)
|
|
91
|
+
try {
|
|
92
|
+
await this.client.connect({ access_token: accessToken, gateway: this.client._gatewayUrl }, { auto_reconnect: true, retry: { max_attempts: 5, initial_delay: 1.0, max_delay: 30.0 } });
|
|
93
|
+
this._aid = this.client.aid ?? undefined;
|
|
94
|
+
this.connected = true;
|
|
95
|
+
this.reconnectAttempt = 0;
|
|
96
|
+
logger.info(`[AUN] Connected as ${this._aid}`);
|
|
97
|
+
}
|
|
98
|
+
catch (e) {
|
|
99
|
+
logger.error(`[AUN] Connection failed: ${e}`);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
// ── Event handlers ──────────────────────────────────────────
|
|
104
|
+
async handleIncomingPrivateMessage(data) {
|
|
105
|
+
if (!data || typeof data !== 'object')
|
|
106
|
+
return;
|
|
107
|
+
const msg = data;
|
|
108
|
+
const fromAid = msg.from ?? '';
|
|
109
|
+
const payload = msg.payload ?? '';
|
|
110
|
+
const text = typeof payload === 'string' ? payload : (payload ? JSON.stringify(payload) : '');
|
|
111
|
+
const taskId = msg.task_id;
|
|
112
|
+
const messageId = msg.message_id ?? '';
|
|
113
|
+
const seq = msg.seq;
|
|
114
|
+
// Detect @mentions
|
|
115
|
+
const mentions = [];
|
|
116
|
+
if (this._aid && text.includes(`@${this._aid}`)) {
|
|
117
|
+
mentions.push(this._aid);
|
|
118
|
+
}
|
|
119
|
+
this.dispatchMessage({
|
|
120
|
+
channelId: fromAid,
|
|
121
|
+
userId: fromAid,
|
|
122
|
+
text,
|
|
123
|
+
chatType: 'private',
|
|
124
|
+
messageId,
|
|
125
|
+
seq,
|
|
126
|
+
taskId,
|
|
127
|
+
mentions,
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
async handleIncomingGroupMessage(data) {
|
|
131
|
+
if (!data || typeof data !== 'object')
|
|
132
|
+
return;
|
|
133
|
+
const msg = data;
|
|
134
|
+
const groupId = msg.group_id ?? '';
|
|
135
|
+
const senderAid = msg.sender_aid ?? msg.from ?? '';
|
|
136
|
+
const payload = msg.payload ?? '';
|
|
137
|
+
const text = typeof payload === 'string' ? payload : (payload ? JSON.stringify(payload) : '');
|
|
138
|
+
const taskId = msg.task_id;
|
|
139
|
+
const messageId = msg.message_id ?? '';
|
|
140
|
+
const seq = msg.seq;
|
|
141
|
+
// Detect @mentions
|
|
142
|
+
const mentions = [];
|
|
143
|
+
if (this._aid && text.includes(`@${this._aid}`)) {
|
|
144
|
+
mentions.push(this._aid);
|
|
145
|
+
}
|
|
146
|
+
this.dispatchMessage({
|
|
147
|
+
channelId: groupId,
|
|
148
|
+
userId: senderAid,
|
|
149
|
+
text,
|
|
150
|
+
chatType: 'group',
|
|
151
|
+
messageId,
|
|
152
|
+
seq,
|
|
153
|
+
taskId,
|
|
154
|
+
mentions,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
dispatchMessage(event) {
|
|
158
|
+
// Dedup
|
|
159
|
+
if (event.messageId) {
|
|
160
|
+
if (this.seenMessages.has(event.messageId))
|
|
161
|
+
return;
|
|
162
|
+
this.seenMessages.set(event.messageId, Date.now());
|
|
163
|
+
setTimeout(() => this.seenMessages.delete(event.messageId), 5 * 60 * 1000);
|
|
164
|
+
// Track seq for acknowledge
|
|
165
|
+
if (event.seq != null) {
|
|
166
|
+
this.messageSeqMap.set(event.messageId, event.seq);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
if (!this.messageHandler)
|
|
170
|
+
return;
|
|
171
|
+
const mentionObjects = event.mentions?.map(aid => ({ userId: aid }));
|
|
172
|
+
let replyContext;
|
|
173
|
+
if (event.taskId) {
|
|
174
|
+
replyContext = { threadId: event.taskId };
|
|
175
|
+
}
|
|
176
|
+
this.messageHandler({
|
|
177
|
+
channelId: event.channelId || '',
|
|
178
|
+
content: event.text || '',
|
|
179
|
+
chatType: event.chatType,
|
|
180
|
+
peerId: event.userId || event.channelId || '',
|
|
181
|
+
messageId: event.messageId,
|
|
182
|
+
threadId: event.taskId,
|
|
183
|
+
mentions: mentionObjects,
|
|
184
|
+
replyContext,
|
|
185
|
+
}).catch(err => {
|
|
186
|
+
logger.error('[AUN] Message handler error:', err);
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
handleConnectionState(data) {
|
|
190
|
+
if (!data || typeof data !== 'object')
|
|
191
|
+
return;
|
|
192
|
+
const state = data.state ?? '';
|
|
193
|
+
if (state === 'connected') {
|
|
194
|
+
this.connected = true;
|
|
195
|
+
this.reconnectAttempt = 0;
|
|
196
|
+
logger.info('[AUN] Connected');
|
|
197
|
+
}
|
|
198
|
+
else if (state === 'disconnected') {
|
|
199
|
+
this.connected = false;
|
|
200
|
+
logger.warn(`[AUN] Disconnected: ${data.error ?? 'unknown'}`);
|
|
201
|
+
}
|
|
202
|
+
else if (state === 'reconnecting') {
|
|
203
|
+
logger.info(`[AUN] SDK reconnecting (attempt ${data.attempt})`);
|
|
204
|
+
}
|
|
205
|
+
else if (state === 'terminal_failed') {
|
|
206
|
+
this.connected = false;
|
|
207
|
+
logger.error(`[AUN] Terminal failure: ${data.error ?? 'unknown'}`);
|
|
208
|
+
// SDK auto_reconnect exhausted; fall back to TS-layer reconnect
|
|
209
|
+
if (!this.intentionalDisconnect) {
|
|
210
|
+
this.scheduleReconnect();
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
// ── Public API (same interface as before) ───────────────────
|
|
15
215
|
onMessage(handler) {
|
|
16
216
|
this.messageHandler = handler;
|
|
17
217
|
}
|
|
18
|
-
async sendMessage(
|
|
19
|
-
if (!this.connected)
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
218
|
+
async sendMessage(channelId, text, context) {
|
|
219
|
+
if (!this.connected || !this.client) {
|
|
220
|
+
logger.warn('[AUN] Cannot send: not connected');
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
if (!text?.trim()) {
|
|
224
|
+
logger.warn('[AUN] Attempted to send empty message, skipping');
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
let finalText = text;
|
|
228
|
+
// 多轮工具调用后的最终回复:仅在已有中间消息时添加前缀
|
|
229
|
+
if (context?.title && (this.sentCount.get(channelId) || 0) > 0) {
|
|
230
|
+
finalText = '最终回复\n' + text;
|
|
231
|
+
}
|
|
232
|
+
this.sentCount.set(channelId, (this.sentCount.get(channelId) || 0) + 1);
|
|
233
|
+
const params = { payload: finalText, encrypt: true };
|
|
234
|
+
if (context?.threadId)
|
|
235
|
+
params.task_id = context.threadId;
|
|
236
|
+
try {
|
|
237
|
+
if (channelId.startsWith('grp_')) {
|
|
238
|
+
params.group_id = channelId;
|
|
239
|
+
await this.client.call('group.send', params);
|
|
240
|
+
}
|
|
241
|
+
else {
|
|
242
|
+
params.to = channelId;
|
|
243
|
+
await this.client.call('message.send', params);
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
catch (e) {
|
|
247
|
+
logger.error(`[AUN] Send failed to ${channelId}: ${e}`);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
acknowledge(messageId) {
|
|
251
|
+
const seq = this.messageSeqMap.get(messageId);
|
|
252
|
+
if (seq != null && this.client) {
|
|
253
|
+
this.client.call('message.ack', { seq }).catch(e => {
|
|
254
|
+
logger.debug(`[AUN] Ack failed: ${e}`);
|
|
255
|
+
});
|
|
256
|
+
this.messageSeqMap.delete(messageId);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
sendProcessingStatus(channelId, status, sessionId, context) {
|
|
260
|
+
if (status === 'start')
|
|
261
|
+
this.sentCount.delete(channelId); // 新任务开始,重置计数
|
|
262
|
+
if (!this.client || !this.connected)
|
|
263
|
+
return;
|
|
264
|
+
const payload = JSON.stringify({
|
|
265
|
+
type: 'processing',
|
|
266
|
+
status,
|
|
267
|
+
sessionId,
|
|
268
|
+
timestamp: Math.floor(Date.now() / 1000),
|
|
269
|
+
});
|
|
270
|
+
const params = {
|
|
271
|
+
to: channelId, payload,
|
|
272
|
+
encrypt: true, persist: false,
|
|
273
|
+
};
|
|
274
|
+
if (context?.threadId)
|
|
275
|
+
params.task_id = context.threadId;
|
|
276
|
+
this.client.call('message.send', params).catch(e => {
|
|
277
|
+
logger.debug(`[AUN] Processing status failed: ${e}`);
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
sendCustomPayload(channelId, payload) {
|
|
281
|
+
if (!this.client || !this.connected)
|
|
282
|
+
return;
|
|
283
|
+
this.client.call('message.send', {
|
|
284
|
+
to: channelId, payload,
|
|
285
|
+
encrypt: true, persist: false,
|
|
286
|
+
}).catch(e => {
|
|
287
|
+
logger.debug(`[AUN] Custom payload failed: ${e}`);
|
|
288
|
+
});
|
|
23
289
|
}
|
|
24
290
|
async disconnect() {
|
|
291
|
+
this.intentionalDisconnect = true;
|
|
292
|
+
if (this.reconnectTimer) {
|
|
293
|
+
clearTimeout(this.reconnectTimer);
|
|
294
|
+
this.reconnectTimer = null;
|
|
295
|
+
}
|
|
296
|
+
if (this.client) {
|
|
297
|
+
try {
|
|
298
|
+
await this.client.close();
|
|
299
|
+
}
|
|
300
|
+
catch { /* ignore */ }
|
|
301
|
+
this.client = null;
|
|
302
|
+
}
|
|
25
303
|
this.connected = false;
|
|
26
304
|
logger.info('[AUN] Disconnected');
|
|
27
305
|
}
|
|
306
|
+
// ── TS-layer reconnect (fallback when SDK auto_reconnect exhausted) ──
|
|
307
|
+
scheduleReconnect() {
|
|
308
|
+
if (this.intentionalDisconnect)
|
|
309
|
+
return;
|
|
310
|
+
if (this.reconnectTimer)
|
|
311
|
+
return;
|
|
312
|
+
const delays = AUNChannel.RECONNECT_DELAYS;
|
|
313
|
+
if (this.reconnectAttempt >= delays.length) {
|
|
314
|
+
logger.error(`[AUN] All ${delays.length} reconnect attempts exhausted, giving up`);
|
|
315
|
+
this.onChannelDown?.();
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
const delay = delays[this.reconnectAttempt];
|
|
319
|
+
this.reconnectAttempt++;
|
|
320
|
+
logger.info(`[AUN] Scheduling reconnect #${this.reconnectAttempt}/${delays.length} in ${delay}s`);
|
|
321
|
+
this.reconnectTimer = setTimeout(async () => {
|
|
322
|
+
this.reconnectTimer = null;
|
|
323
|
+
try {
|
|
324
|
+
logger.info(`[AUN] Reconnect #${this.reconnectAttempt} starting...`);
|
|
325
|
+
await this.initClient();
|
|
326
|
+
logger.info(`[AUN] Reconnect #${this.reconnectAttempt} succeeded`);
|
|
327
|
+
}
|
|
328
|
+
catch (err) {
|
|
329
|
+
logger.error(`[AUN] Reconnect #${this.reconnectAttempt} failed:`, err);
|
|
330
|
+
this.scheduleReconnect();
|
|
331
|
+
}
|
|
332
|
+
}, delay * 1000);
|
|
333
|
+
}
|
|
334
|
+
/** Manually trigger reconnect (e.g. from /check reconnect command) */
|
|
335
|
+
async reconnect() {
|
|
336
|
+
if (this.connected)
|
|
337
|
+
return '已连接,无需重连';
|
|
338
|
+
if (this.reconnectTimer) {
|
|
339
|
+
clearTimeout(this.reconnectTimer);
|
|
340
|
+
this.reconnectTimer = null;
|
|
341
|
+
}
|
|
342
|
+
this.reconnectAttempt = 0;
|
|
343
|
+
try {
|
|
344
|
+
await this.initClient();
|
|
345
|
+
return `重连成功 (${this._aid})`;
|
|
346
|
+
}
|
|
347
|
+
catch (err) {
|
|
348
|
+
this.scheduleReconnect();
|
|
349
|
+
return `重连失败: ${err},已安排自动重试`;
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
/** Set callback for when all reconnect attempts are exhausted */
|
|
353
|
+
setOnChannelDown(callback) {
|
|
354
|
+
this.onChannelDown = callback;
|
|
355
|
+
}
|
|
356
|
+
/** Get current connection status */
|
|
357
|
+
getStatus() {
|
|
358
|
+
return {
|
|
359
|
+
connected: this.connected,
|
|
360
|
+
aid: this._aid,
|
|
361
|
+
reconnectAttempt: this.reconnectAttempt,
|
|
362
|
+
maxAttempts: AUNChannel.RECONNECT_DELAYS.length,
|
|
363
|
+
};
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
// Plugin implementation
|
|
367
|
+
export class AUNChannelPlugin {
|
|
368
|
+
name = 'aun';
|
|
369
|
+
isEnabled(config) {
|
|
370
|
+
return config.channels?.aun?.enabled !== false && !!config.channels?.aun?.aid;
|
|
371
|
+
}
|
|
372
|
+
async createChannel(config) {
|
|
373
|
+
const aunConfig = config.channels?.aun;
|
|
374
|
+
if (!aunConfig?.aid) {
|
|
375
|
+
throw new Error('AUN config missing (aid required, e.g. "mybot.agentid.pub")');
|
|
376
|
+
}
|
|
377
|
+
const channel = new AUNChannel({
|
|
378
|
+
aid: aunConfig.aid,
|
|
379
|
+
keystorePath: aunConfig.keystorePath,
|
|
380
|
+
gatewayPort: aunConfig.gatewayPort,
|
|
381
|
+
gatewayUrl: aunConfig.gatewayUrl,
|
|
382
|
+
accessToken: aunConfig.accessToken,
|
|
383
|
+
flushDelay: aunConfig.flushDelay,
|
|
384
|
+
encryptionSeed: aunConfig.encryptionSeed,
|
|
385
|
+
});
|
|
386
|
+
const adapter = {
|
|
387
|
+
name: 'aun',
|
|
388
|
+
sendText: (id, text, context) => channel.sendMessage(id, text, context),
|
|
389
|
+
acknowledge: (messageId) => { channel.acknowledge(messageId); return Promise.resolve(); },
|
|
390
|
+
sendProcessingStatus: (id, status, sessionId, context) => channel.sendProcessingStatus(id, status, sessionId, context),
|
|
391
|
+
sendCustomPayload: (id, payload) => channel.sendCustomPayload(id, payload),
|
|
392
|
+
};
|
|
393
|
+
const policy = {
|
|
394
|
+
canSwitchProject: (chatType, identity) => identity === 'owner',
|
|
395
|
+
canListProjects: (chatType, identity) => identity === 'owner',
|
|
396
|
+
canCreateSession: (chatType, identity) => true,
|
|
397
|
+
canDeleteSession: (chatType, identity) => true,
|
|
398
|
+
canImportCliSession: (chatType, identity) => identity === 'owner',
|
|
399
|
+
messagePrefix: (chatType, peerName) => (chatType === 'group' && peerName) ? `[${peerName}] ` : '',
|
|
400
|
+
showMiddleResult: (chatType, identity) => {
|
|
401
|
+
const mode = aunConfig.showActivities ?? config.showActivities ?? 'all';
|
|
402
|
+
if (mode === 'none')
|
|
403
|
+
return false;
|
|
404
|
+
if (mode === 'dm-only')
|
|
405
|
+
return chatType === 'private';
|
|
406
|
+
if (mode === 'owner-dm-only')
|
|
407
|
+
return chatType === 'private' && identity === 'owner';
|
|
408
|
+
return true;
|
|
409
|
+
},
|
|
410
|
+
showIdleMonitor: (chatType, identity) => {
|
|
411
|
+
const mode = aunConfig.showActivities ?? config.showActivities ?? 'all';
|
|
412
|
+
if (mode === 'none')
|
|
413
|
+
return false;
|
|
414
|
+
if (mode === 'dm-only')
|
|
415
|
+
return chatType === 'private';
|
|
416
|
+
if (mode === 'owner-dm-only')
|
|
417
|
+
return chatType === 'private' && identity === 'owner';
|
|
418
|
+
return true;
|
|
419
|
+
},
|
|
420
|
+
accumulateErrors: (chatType, identity) => true,
|
|
421
|
+
};
|
|
422
|
+
const options = {
|
|
423
|
+
flushDelay: aunConfig.flushDelay ?? 3,
|
|
424
|
+
fileMarkerPattern: /\[SEND_FILE:(?:(\w+):)?([^\]]+)\]/g,
|
|
425
|
+
};
|
|
426
|
+
return {
|
|
427
|
+
adapter,
|
|
428
|
+
channel,
|
|
429
|
+
policy,
|
|
430
|
+
options,
|
|
431
|
+
connect: () => channel.connect(),
|
|
432
|
+
disconnect: () => channel.disconnect(),
|
|
433
|
+
};
|
|
434
|
+
}
|
|
28
435
|
}
|