imtoagent 0.3.3 → 0.3.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.
- package/README.md +97 -97
- package/bin/imtoagent-real +96 -96
- package/bin/imtoagent.cjs +1 -1
- package/index.ts +106 -106
- package/modules/agent/claude-adapter.ts +6 -6
- package/modules/agent/claude.ts +6 -6
- package/modules/agent/codex-adapter.ts +13 -13
- package/modules/agent/codex-exec-server.ts +11 -11
- package/modules/agent/codex.ts +29 -29
- package/modules/agent/opencode-adapter.ts +17 -17
- package/modules/agent/opencode.ts +10 -10
- package/modules/capabilities.ts +33 -33
- package/modules/cli/setup.ts +171 -163
- package/modules/core/config.ts +5 -5
- package/modules/core/error.ts +8 -8
- package/modules/core/runtime.ts +10 -10
- package/modules/core/session.ts +4 -4
- package/modules/core/stats.ts +14 -14
- package/modules/core/types.ts +7 -7
- package/modules/im/feishu.ts +56 -56
- package/modules/im/telegram.ts +23 -23
- package/modules/im/wechat.ts +54 -54
- package/modules/im/wecom.ts +50 -50
- package/modules/media/feishu-inbound-adapter.ts +4 -4
- package/modules/media/resolver.ts +11 -11
- package/modules/media/telegram-inbound-adapter.ts +8 -8
- package/modules/prompt-builder.ts +12 -12
- package/modules/proxy/anthropic-proxy.ts +39 -28
- package/modules/proxy/codex-proxy.ts +18 -18
- package/modules/utils/backend-check.ts +12 -12
- package/modules/utils/paths.ts +8 -8
- package/package.json +1 -1
- package/scripts/postinstall.cjs +10 -10
- package/scripts/postinstall.ts +13 -13
- package/templates/soul.template/identity.md +5 -5
- package/templates/soul.template/profile.md +7 -7
- package/templates/soul.template/rules.md +5 -5
- package/templates/soul.template/skills.md +2 -2
- package/templates/soul.template/workspace.md +3 -3
package/modules/im/feishu.ts
CHANGED
|
@@ -89,9 +89,9 @@ export class FeishuIMModule implements IMModule {
|
|
|
89
89
|
};
|
|
90
90
|
return this._tenantAccessToken.token;
|
|
91
91
|
}
|
|
92
|
-
throw new Error(
|
|
92
|
+
throw new Error(`Failed to get token: ${res.code} ${res.msg}`);
|
|
93
93
|
} catch (e: any) {
|
|
94
|
-
throw new Error(
|
|
94
|
+
throw new Error(`Failed to get token: ${e.message}`);
|
|
95
95
|
}
|
|
96
96
|
}
|
|
97
97
|
|
|
@@ -108,16 +108,16 @@ export class FeishuIMModule implements IMModule {
|
|
|
108
108
|
data: { app_id: this.appId, app_secret: this.appSecret },
|
|
109
109
|
});
|
|
110
110
|
if (res.code === 0 && res.app_access_token) {
|
|
111
|
-
//
|
|
111
|
+
// Feishu app_token valid for ~2 hours
|
|
112
112
|
this._appAccessToken = {
|
|
113
113
|
token: res.app_access_token,
|
|
114
114
|
expiresAt: now + 2 * 60 * 60 * 1000,
|
|
115
115
|
};
|
|
116
116
|
return this._appAccessToken.token;
|
|
117
117
|
}
|
|
118
|
-
throw new Error(
|
|
118
|
+
throw new Error(`Failed to get app token: ${res.code} ${res.msg}`);
|
|
119
119
|
} catch (e: any) {
|
|
120
|
-
throw new Error(
|
|
120
|
+
throw new Error(`Failed to get app token: ${e.message}`);
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
123
|
|
|
@@ -126,14 +126,14 @@ export class FeishuIMModule implements IMModule {
|
|
|
126
126
|
// ================================================================
|
|
127
127
|
|
|
128
128
|
async reply(chatId: string, text: string, maxLen = 140000) {
|
|
129
|
-
const safe = text.length > maxLen ? text.slice(0, maxLen) + '\n\n...(
|
|
129
|
+
const safe = text.length > maxLen ? text.slice(0, maxLen) + '\n\n...(truncated)' : text;
|
|
130
130
|
try {
|
|
131
131
|
await this.client.im.message.create({
|
|
132
132
|
params: { receive_id_type: 'chat_id' },
|
|
133
133
|
data: { receive_id: chatId, msg_type: 'text', content: JSON.stringify({ text: safe }) },
|
|
134
134
|
});
|
|
135
135
|
} catch (e: any) {
|
|
136
|
-
console.error(`[Feishu]
|
|
136
|
+
console.error(`[Feishu] Reply failed: ${e.message}`);
|
|
137
137
|
}
|
|
138
138
|
}
|
|
139
139
|
|
|
@@ -144,7 +144,7 @@ export class FeishuIMModule implements IMModule {
|
|
|
144
144
|
data: { receive_id: chatId, msg_type: 'text', content: JSON.stringify({ text }) },
|
|
145
145
|
});
|
|
146
146
|
} catch (e: any) {
|
|
147
|
-
console.error(`[Feishu]
|
|
147
|
+
console.error(`[Feishu] Progress notification failed: ${e.message}`);
|
|
148
148
|
}
|
|
149
149
|
}
|
|
150
150
|
|
|
@@ -169,14 +169,14 @@ export class FeishuIMModule implements IMModule {
|
|
|
169
169
|
}
|
|
170
170
|
if (fileKey) {
|
|
171
171
|
await this.sendFile(chatId, fileKey, fb.filename);
|
|
172
|
-
console.log(`[Feishu]
|
|
172
|
+
console.log(`[Feishu] File sent: ${fb.filename}`);
|
|
173
173
|
}
|
|
174
174
|
} catch (e: any) {
|
|
175
|
-
console.error(`[Feishu]
|
|
175
|
+
console.error(`[Feishu] File send failed: ${fb.filename} - ${e.message}`);
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
|
|
179
|
-
//
|
|
179
|
+
// If only one text block remains, send as plain text
|
|
180
180
|
if (cardBlocks.length === 1 && cardBlocks[0].type === 'text') {
|
|
181
181
|
if (fileBlocks.length === 0) return this.reply(chatId, cardBlocks[0].content);
|
|
182
182
|
// 有文件在前,文本块附后
|
|
@@ -216,8 +216,8 @@ ${this.escapeCodeBlock(block.code)}
|
|
|
216
216
|
cardElements.push({ tag: 'img', img_key: imageKey, alt: { tag: 'plain_text', content: block.alt || '' } });
|
|
217
217
|
}
|
|
218
218
|
} catch (e: any) {
|
|
219
|
-
console.error(`[Feishu]
|
|
220
|
-
cardElements.push({ tag: 'markdown', content: `⚠️
|
|
219
|
+
console.error(`[Feishu] Image upload failed: ${e.message}`);
|
|
220
|
+
cardElements.push({ tag: 'markdown', content: `⚠️ Image load failed` });
|
|
221
221
|
}
|
|
222
222
|
}
|
|
223
223
|
break;
|
|
@@ -268,9 +268,9 @@ ${this.escapeCardMarkdown(block.content || '')}`,
|
|
|
268
268
|
content: JSON.stringify(card),
|
|
269
269
|
},
|
|
270
270
|
});
|
|
271
|
-
console.log(`[Feishu]
|
|
271
|
+
console.log(`[Feishu] Card message sent (${cardBlocks.length} blocks)`);
|
|
272
272
|
} catch (e: any) {
|
|
273
|
-
console.error(`[Feishu]
|
|
273
|
+
console.error(`[Feishu] Card send failed: ${e.message}`);
|
|
274
274
|
// 降级:拼接为纯文本发送
|
|
275
275
|
const fallback = cardBlocks.map(b => {
|
|
276
276
|
switch (b.type) {
|
|
@@ -305,11 +305,11 @@ ${b.content || ''}`;
|
|
|
305
305
|
},
|
|
306
306
|
});
|
|
307
307
|
} catch (e: any) {
|
|
308
|
-
console.error(`[Feishu]
|
|
308
|
+
console.error(`[Feishu] Image send failed: ${e.message}`);
|
|
309
309
|
}
|
|
310
310
|
}
|
|
311
311
|
|
|
312
|
-
//
|
|
312
|
+
// Upload image from URL to Feishu, returns image_key
|
|
313
313
|
async uploadImageFromUrl(url: string): Promise<string | null> {
|
|
314
314
|
try {
|
|
315
315
|
let buffer: Buffer | null = null;
|
|
@@ -335,15 +335,15 @@ ${b.content || ''}`;
|
|
|
335
335
|
});
|
|
336
336
|
const key = r?.image_key || r?.data?.image_key;
|
|
337
337
|
if (key) return key;
|
|
338
|
-
console.error(`[Feishu]
|
|
338
|
+
console.error(`[Feishu] Image upload failed: image_key missing`);
|
|
339
339
|
return null;
|
|
340
340
|
} catch (e: any) {
|
|
341
|
-
console.error(`[Feishu]
|
|
341
|
+
console.error(`[Feishu] Image upload error: ${e.message}`);
|
|
342
342
|
return null;
|
|
343
343
|
}
|
|
344
344
|
}
|
|
345
345
|
|
|
346
|
-
//
|
|
346
|
+
// Upload image from local file to Feishu, returns image_key
|
|
347
347
|
async uploadImageFromFile(filePath: string): Promise<string | null> {
|
|
348
348
|
try {
|
|
349
349
|
const buffer = fs.readFileSync(filePath);
|
|
@@ -353,42 +353,42 @@ ${b.content || ''}`;
|
|
|
353
353
|
});
|
|
354
354
|
const key = r?.image_key || r?.data?.image_key;
|
|
355
355
|
if (key) return key;
|
|
356
|
-
console.error(`[Feishu]
|
|
356
|
+
console.error(`[Feishu] Image upload failed: image_key missing`);
|
|
357
357
|
return null;
|
|
358
358
|
} catch (e: any) {
|
|
359
|
-
console.error(`[Feishu]
|
|
359
|
+
console.error(`[Feishu] Image upload failed: ${e.message}`);
|
|
360
360
|
return null;
|
|
361
361
|
}
|
|
362
362
|
}
|
|
363
363
|
|
|
364
364
|
// ================================================================
|
|
365
|
-
//
|
|
365
|
+
// File Upload
|
|
366
366
|
// ================================================================
|
|
367
367
|
|
|
368
|
-
//
|
|
368
|
+
// Download from URL and upload to Feishu, returns file_key
|
|
369
369
|
async uploadFileFromUrl(url: string, filename: string): Promise<string | null> {
|
|
370
370
|
try {
|
|
371
371
|
const buffer = await this.downloadFile(url);
|
|
372
372
|
if (!buffer) return null;
|
|
373
373
|
return this.uploadFileFromBuffer(buffer, filename || path.basename(new URL(url).pathname) || 'file');
|
|
374
374
|
} catch (e: any) {
|
|
375
|
-
console.error(`[Feishu]
|
|
375
|
+
console.error(`[Feishu] File upload error: ${e.message}`);
|
|
376
376
|
return null;
|
|
377
377
|
}
|
|
378
378
|
}
|
|
379
379
|
|
|
380
|
-
//
|
|
380
|
+
// Upload file from local path to Feishu, returns file_key
|
|
381
381
|
async uploadFileFromPath(filePath: string): Promise<string | null> {
|
|
382
382
|
try {
|
|
383
383
|
const buffer = fs.readFileSync(filePath);
|
|
384
384
|
return this.uploadFileFromBuffer(buffer, path.basename(filePath));
|
|
385
385
|
} catch (e: any) {
|
|
386
|
-
console.error(`[Feishu]
|
|
386
|
+
console.error(`[Feishu] File upload failed: ${e.message}`);
|
|
387
387
|
return null;
|
|
388
388
|
}
|
|
389
389
|
}
|
|
390
390
|
|
|
391
|
-
//
|
|
391
|
+
// Upload file from Buffer to Feishu, returns file_key
|
|
392
392
|
private async uploadFileFromBuffer(buffer: Buffer, filename: string): Promise<string | null> {
|
|
393
393
|
try {
|
|
394
394
|
const token = await this.getAppToken();
|
|
@@ -406,10 +406,10 @@ ${b.content || ''}`;
|
|
|
406
406
|
if (data.code === 0 && data.data?.file_key) {
|
|
407
407
|
return data.data.file_key;
|
|
408
408
|
}
|
|
409
|
-
console.error(`[Feishu]
|
|
409
|
+
console.error(`[Feishu] File upload failed: ${data.code} ${data.msg}`);
|
|
410
410
|
return null;
|
|
411
411
|
} catch (e: any) {
|
|
412
|
-
console.error(`[Feishu]
|
|
412
|
+
console.error(`[Feishu] File upload error: ${e.message}`);
|
|
413
413
|
return null;
|
|
414
414
|
}
|
|
415
415
|
}
|
|
@@ -426,18 +426,18 @@ ${b.content || ''}`;
|
|
|
426
426
|
},
|
|
427
427
|
});
|
|
428
428
|
} catch (e: any) {
|
|
429
|
-
console.error(`[Feishu]
|
|
429
|
+
console.error(`[Feishu] File send failed: ${e.message}`);
|
|
430
430
|
}
|
|
431
431
|
}
|
|
432
432
|
|
|
433
433
|
// ================================================================
|
|
434
|
-
//
|
|
434
|
+
// Capabilities
|
|
435
435
|
// ================================================================
|
|
436
436
|
|
|
437
437
|
getCapabilities(): IMCapabilities {
|
|
438
438
|
return {
|
|
439
439
|
text: true,
|
|
440
|
-
codeBlock: true, //
|
|
440
|
+
codeBlock: true, // Card markdown supports ``` syntax
|
|
441
441
|
cardMessage: true,
|
|
442
442
|
fileSend: true,
|
|
443
443
|
imageSend: true,
|
|
@@ -461,7 +461,7 @@ ${b.content || ''}`;
|
|
|
461
461
|
this.running = false;
|
|
462
462
|
if (this.reconnectTimer) { clearTimeout(this.reconnectTimer); this.reconnectTimer = null; }
|
|
463
463
|
try { this.wsClient?.stop?.(); } catch {}
|
|
464
|
-
console.log(`[Feishu] WS
|
|
464
|
+
console.log(`[Feishu] WS stopped (appId=${this.appId.slice(-8)})`);
|
|
465
465
|
}
|
|
466
466
|
|
|
467
467
|
private _connect() {
|
|
@@ -495,7 +495,7 @@ ${b.content || ''}`;
|
|
|
495
495
|
});
|
|
496
496
|
if (resolved) {
|
|
497
497
|
attachments.push(resolved.attachment);
|
|
498
|
-
text = '[
|
|
498
|
+
text = '[User sent an image]';
|
|
499
499
|
}
|
|
500
500
|
break;
|
|
501
501
|
}
|
|
@@ -510,7 +510,7 @@ ${b.content || ''}`;
|
|
|
510
510
|
});
|
|
511
511
|
if (resolved) {
|
|
512
512
|
attachments.push(resolved.attachment);
|
|
513
|
-
text = `[
|
|
513
|
+
text = `[User sent a file: ${content.file_name || 'unknown'}]`;
|
|
514
514
|
}
|
|
515
515
|
break;
|
|
516
516
|
}
|
|
@@ -520,13 +520,13 @@ ${b.content || ''}`;
|
|
|
520
520
|
const resolved = await this._mediaResolver.resolveOne({
|
|
521
521
|
messageId: message.message_id,
|
|
522
522
|
resourceKey: content.file_key,
|
|
523
|
-
type: 'file', //
|
|
523
|
+
type: 'file', // Feishu audio also uses file type for download
|
|
524
524
|
});
|
|
525
525
|
if (resolved) {
|
|
526
526
|
// 补充音频时长(resolver 无法从飞书 API 获取 duration)
|
|
527
527
|
resolved.attachment.durationMs = content.duration;
|
|
528
528
|
attachments.push(resolved.attachment);
|
|
529
|
-
text = `[
|
|
529
|
+
text = `[User sent a voice message (${(content.duration || 0) / 1000}s)]`;
|
|
530
530
|
}
|
|
531
531
|
break;
|
|
532
532
|
}
|
|
@@ -536,11 +536,11 @@ ${b.content || ''}`;
|
|
|
536
536
|
break;
|
|
537
537
|
|
|
538
538
|
case 'media':
|
|
539
|
-
text = '[
|
|
539
|
+
text = '[User sent a video message]';
|
|
540
540
|
break;
|
|
541
541
|
|
|
542
542
|
case 'sticker':
|
|
543
|
-
text = '[
|
|
543
|
+
text = '[User sent a sticker]';
|
|
544
544
|
break;
|
|
545
545
|
|
|
546
546
|
case 'system':
|
|
@@ -551,11 +551,11 @@ ${b.content || ''}`;
|
|
|
551
551
|
break;
|
|
552
552
|
|
|
553
553
|
case 'merge_forward':
|
|
554
|
-
text = '[
|
|
554
|
+
text = '[User forwarded a merged message]';
|
|
555
555
|
break;
|
|
556
556
|
|
|
557
557
|
default:
|
|
558
|
-
console.log(`[Feishu]
|
|
558
|
+
console.log(`[Feishu] Unhandled message type: ${msgType}`);
|
|
559
559
|
return;
|
|
560
560
|
}
|
|
561
561
|
|
|
@@ -563,23 +563,23 @@ ${b.content || ''}`;
|
|
|
563
563
|
|
|
564
564
|
await this.messageHandler!(chatId, text, userId, attachments.length > 0 ? attachments : undefined);
|
|
565
565
|
} catch (e: any) {
|
|
566
|
-
console.error(`[Feishu]
|
|
567
|
-
//
|
|
566
|
+
console.error(`[Feishu] Message processing error: ${e.message}`);
|
|
567
|
+
// Don't throw to prevent SDK dispatcher unhandled rejection from crashing the process
|
|
568
568
|
}
|
|
569
569
|
},
|
|
570
570
|
});
|
|
571
571
|
|
|
572
572
|
// 自定义 Logger — 过滤 SDK 内部 WS 重连噪音
|
|
573
573
|
const quietLogger = {
|
|
574
|
-
info: (...args: any[]) => { /*
|
|
575
|
-
warn: (...args: any[]) => { /*
|
|
574
|
+
info: (...args: any[]) => { /* silent info */ },
|
|
575
|
+
warn: (...args: any[]) => { /* silent warn */ },
|
|
576
576
|
error: (...args: any[]) => {
|
|
577
577
|
const msg = args.join(' ');
|
|
578
578
|
// 过滤已知的 SDK 内部 WS 重连噪音(不影响功能,SDK 自带自动重连)
|
|
579
579
|
if (msg.includes('[ws]') && (msg.includes('ECONNREFUSED') || msg.includes('connect failed') || msg.includes('system busy') || msg.includes('repeat connection'))) return;
|
|
580
580
|
console.error(`[Feishu-SDK] ${msg}`);
|
|
581
581
|
},
|
|
582
|
-
debug: (...args: any[]) => { /*
|
|
582
|
+
debug: (...args: any[]) => { /* silent debug */ },
|
|
583
583
|
};
|
|
584
584
|
|
|
585
585
|
this.wsClient = new Lark.WSClient({
|
|
@@ -592,19 +592,19 @@ ${b.content || ''}`;
|
|
|
592
592
|
this.wsClient.start({ eventDispatcher: dispatcher })
|
|
593
593
|
.then(() => {
|
|
594
594
|
this.reconnectAttempts = 0;
|
|
595
|
-
console.log(`[Feishu] WS
|
|
595
|
+
console.log(`[Feishu] WS connected`);
|
|
596
596
|
})
|
|
597
597
|
.catch((e: any) => {
|
|
598
|
-
console.error(`[Feishu] WS
|
|
598
|
+
console.error(`[Feishu] WS connection failed: ${e.message}`);
|
|
599
599
|
this._scheduleReconnect();
|
|
600
600
|
});
|
|
601
601
|
|
|
602
602
|
this.wsClient.on?.('close', () => {
|
|
603
|
-
console.log('[Feishu] WS
|
|
603
|
+
console.log('[Feishu] WS disconnected');
|
|
604
604
|
this._scheduleReconnect();
|
|
605
605
|
});
|
|
606
606
|
this.wsClient.on?.('error', (e: any) => {
|
|
607
|
-
console.error(`[Feishu] WS
|
|
607
|
+
console.error(`[Feishu] WS error: ${e.message || e}`);
|
|
608
608
|
});
|
|
609
609
|
}
|
|
610
610
|
|
|
@@ -614,7 +614,7 @@ ${b.content || ''}`;
|
|
|
614
614
|
|
|
615
615
|
const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);
|
|
616
616
|
this.reconnectAttempts++;
|
|
617
|
-
console.log(`[Feishu] ${delay/1000}s
|
|
617
|
+
console.log(`[Feishu] Reconnecting in ${delay/1000}s (attempt ${this.reconnectAttempts})`);
|
|
618
618
|
|
|
619
619
|
this.reconnectTimer = setTimeout(() => {
|
|
620
620
|
this.reconnectTimer = null;
|
|
@@ -662,13 +662,13 @@ ${b.content || ''}`;
|
|
|
662
662
|
try {
|
|
663
663
|
const resp = await fetch(url, { signal: AbortSignal.timeout(30000) });
|
|
664
664
|
if (!resp.ok) {
|
|
665
|
-
console.error(`[Feishu]
|
|
665
|
+
console.error(`[Feishu] Download failed: HTTP ${resp.status}, url=${url.slice(0, 80)}`);
|
|
666
666
|
return null;
|
|
667
667
|
}
|
|
668
668
|
const buf = await resp.arrayBuffer();
|
|
669
669
|
return Buffer.from(buf);
|
|
670
670
|
} catch (e) {
|
|
671
|
-
console.error(`[Feishu]
|
|
671
|
+
console.error(`[Feishu] Download error: ${(e as Error).message}, url=${url.slice(0, 80)}`);
|
|
672
672
|
return null;
|
|
673
673
|
}
|
|
674
674
|
}
|
|
@@ -691,8 +691,8 @@ ${b.content || ''}`;
|
|
|
691
691
|
case 'text': return elem.text || '';
|
|
692
692
|
case 'a': return `[${elem.text}](${elem.href})`;
|
|
693
693
|
case 'at': return `@${elem.user_name || elem.user_id || 'unknown'}`;
|
|
694
|
-
case 'img': return `[
|
|
695
|
-
case 'emotion': return `[
|
|
694
|
+
case 'img': return `[Image]`;
|
|
695
|
+
case 'emotion': return `[Sticker]`;
|
|
696
696
|
default: return `[${elem.tag}]`;
|
|
697
697
|
}
|
|
698
698
|
}).join('');
|
package/modules/im/telegram.ts
CHANGED
|
@@ -120,7 +120,7 @@ export class TelegramAdapter implements IMModule {
|
|
|
120
120
|
this.apiUrl = `https://api.telegram.org/bot${this.token}`;
|
|
121
121
|
|
|
122
122
|
if (cfg.proxy) {
|
|
123
|
-
console.log(`[Telegram]
|
|
123
|
+
console.log(`[Telegram] Proxy configured: ${cfg.proxy} (local only, does not affect other modules)`);
|
|
124
124
|
}
|
|
125
125
|
}
|
|
126
126
|
|
|
@@ -164,7 +164,7 @@ export class TelegramAdapter implements IMModule {
|
|
|
164
164
|
// 降级:设置环境变量(影响全局,但总比没有好)
|
|
165
165
|
if (!process.env.HTTPS_PROXY && !process.env.https_proxy) {
|
|
166
166
|
process.env.HTTPS_PROXY = this.proxy;
|
|
167
|
-
console.log(`[Telegram]
|
|
167
|
+
console.log(`[Telegram] Set HTTPS_PROXY=${this.proxy}`);
|
|
168
168
|
}
|
|
169
169
|
}
|
|
170
170
|
}
|
|
@@ -178,12 +178,12 @@ export class TelegramAdapter implements IMModule {
|
|
|
178
178
|
getCapabilities(): IMCapabilities {
|
|
179
179
|
return {
|
|
180
180
|
text: true,
|
|
181
|
-
codeBlock: true, // MarkdownV2
|
|
182
|
-
cardMessage: false, // Telegram
|
|
181
|
+
codeBlock: true, // MarkdownV2 supports ``` code blocks
|
|
182
|
+
cardMessage: false, // Telegram has no native cards, sendBlocks falls back to text
|
|
183
183
|
fileSend: true,
|
|
184
184
|
imageSend: true,
|
|
185
185
|
audioSend: true,
|
|
186
|
-
buttonAction: true, //
|
|
186
|
+
buttonAction: true, // Inline keyboard
|
|
187
187
|
maxTextLength: 4096,
|
|
188
188
|
};
|
|
189
189
|
}
|
|
@@ -196,13 +196,13 @@ export class TelegramAdapter implements IMModule {
|
|
|
196
196
|
this.handler = handler;
|
|
197
197
|
this.running = true;
|
|
198
198
|
this._poll();
|
|
199
|
-
console.log('[Telegram]
|
|
199
|
+
console.log('[Telegram] Long polling started');
|
|
200
200
|
}
|
|
201
201
|
|
|
202
202
|
stop(): void {
|
|
203
203
|
this.running = false;
|
|
204
204
|
if (this.pollTimer) { clearTimeout(this.pollTimer); this.pollTimer = null; }
|
|
205
|
-
console.log('[Telegram]
|
|
205
|
+
console.log('[Telegram] Stopped');
|
|
206
206
|
}
|
|
207
207
|
|
|
208
208
|
// ================================================================
|
|
@@ -234,7 +234,7 @@ export class TelegramAdapter implements IMModule {
|
|
|
234
234
|
|
|
235
235
|
if (this.handler) {
|
|
236
236
|
this.handler(chatId, text, userId, attachments.length > 0 ? attachments : undefined).catch(e =>
|
|
237
|
-
console.error('[Telegram]
|
|
237
|
+
console.error('[Telegram] Message processing error:', e.message)
|
|
238
238
|
);
|
|
239
239
|
}
|
|
240
240
|
}
|
|
@@ -242,7 +242,7 @@ export class TelegramAdapter implements IMModule {
|
|
|
242
242
|
}
|
|
243
243
|
} catch (e: any) {
|
|
244
244
|
if (!this.warnedPollError) {
|
|
245
|
-
console.error('[Telegram]
|
|
245
|
+
console.error('[Telegram] Long poll error:', e.message);
|
|
246
246
|
this.warnedPollError = true;
|
|
247
247
|
}
|
|
248
248
|
}
|
|
@@ -342,7 +342,7 @@ export class TelegramAdapter implements IMModule {
|
|
|
342
342
|
if (voiceAtt) voiceAtt.durationMs = msg.voice.duration * 1000;
|
|
343
343
|
}
|
|
344
344
|
} catch (e: any) {
|
|
345
|
-
console.error('[Telegram]
|
|
345
|
+
console.error('[Telegram] Media resolution error:', e.message);
|
|
346
346
|
}
|
|
347
347
|
}
|
|
348
348
|
|
|
@@ -354,11 +354,11 @@ export class TelegramAdapter implements IMModule {
|
|
|
354
354
|
// 纯媒体消息(无文本无caption),生成占位文本
|
|
355
355
|
if (!text && attachments.length > 0) {
|
|
356
356
|
const types = attachments.map(a => {
|
|
357
|
-
if (a.type === 'image') return '
|
|
358
|
-
if (a.type === 'audio') return '
|
|
359
|
-
return '
|
|
357
|
+
if (a.type === 'image') return 'image';
|
|
358
|
+
if (a.type === 'audio') return 'voice';
|
|
359
|
+
return 'file';
|
|
360
360
|
});
|
|
361
|
-
text = `[
|
|
361
|
+
text = `[User sent ${types.join(', ')}]`;
|
|
362
362
|
}
|
|
363
363
|
|
|
364
364
|
return { text: text.trim(), attachments };
|
|
@@ -371,7 +371,7 @@ export class TelegramAdapter implements IMModule {
|
|
|
371
371
|
/** 成功后重置所有状态 */
|
|
372
372
|
private _onSuccess(): void {
|
|
373
373
|
if (this.circuitOpen) {
|
|
374
|
-
console.log('[Telegram]
|
|
374
|
+
console.log('[Telegram] Network recovered, long polling restored');
|
|
375
375
|
}
|
|
376
376
|
this.circuitOpen = false;
|
|
377
377
|
this.consecutiveFailures = 0;
|
|
@@ -388,7 +388,7 @@ export class TelegramAdapter implements IMModule {
|
|
|
388
388
|
this.circuitOpen = true;
|
|
389
389
|
this.backoffMs = this.recoveryInterval;
|
|
390
390
|
if (!this.warnedCircuitOpen) {
|
|
391
|
-
console.error('[Telegram] ⚠️
|
|
391
|
+
console.error('[Telegram] ⚠️ Consecutive failures, circuit breaker activated (probing recovery every 30s)');
|
|
392
392
|
this.warnedCircuitOpen = true;
|
|
393
393
|
}
|
|
394
394
|
} else if (!this.circuitOpen) {
|
|
@@ -403,7 +403,7 @@ export class TelegramAdapter implements IMModule {
|
|
|
403
403
|
// ================================================================
|
|
404
404
|
|
|
405
405
|
async reply(chatId: string, text: string, maxLen = 4096): Promise<void> {
|
|
406
|
-
const safe = text.length > maxLen ? text.slice(0, maxLen) + '\n\n…(
|
|
406
|
+
const safe = text.length > maxLen ? text.slice(0, maxLen) + '\n\n…(truncated)' : text;
|
|
407
407
|
await this._api('sendMessage', {
|
|
408
408
|
chat_id: chatId,
|
|
409
409
|
text: safe,
|
|
@@ -449,7 +449,7 @@ export class TelegramAdapter implements IMModule {
|
|
|
449
449
|
try {
|
|
450
450
|
await this.sendImageByUrl(chatId, block.url, block.alt);
|
|
451
451
|
} catch (e: any) {
|
|
452
|
-
lines.push(`⚠️
|
|
452
|
+
lines.push(`⚠️ Image load failed`);
|
|
453
453
|
}
|
|
454
454
|
}
|
|
455
455
|
break;
|
|
@@ -459,7 +459,7 @@ export class TelegramAdapter implements IMModule {
|
|
|
459
459
|
try {
|
|
460
460
|
await this.sendFileByUrl(chatId, block.url, block.filename);
|
|
461
461
|
} catch (e: any) {
|
|
462
|
-
lines.push(`⚠️
|
|
462
|
+
lines.push(`⚠️ File send failed: ${block.filename}`);
|
|
463
463
|
}
|
|
464
464
|
}
|
|
465
465
|
break;
|
|
@@ -469,7 +469,7 @@ export class TelegramAdapter implements IMModule {
|
|
|
469
469
|
if (block.content) lines.push(block.content);
|
|
470
470
|
if (block.buttons?.length) {
|
|
471
471
|
await this._sendInlineButtons(chatId, lines.join('\n'), block.buttons);
|
|
472
|
-
return; //
|
|
472
|
+
return; // Button message already sent, don't continue concatenating
|
|
473
473
|
}
|
|
474
474
|
break;
|
|
475
475
|
|
|
@@ -490,7 +490,7 @@ export class TelegramAdapter implements IMModule {
|
|
|
490
490
|
try {
|
|
491
491
|
await this._sendAudio(chatId, block.url, block.filename);
|
|
492
492
|
} catch (e: any) {
|
|
493
|
-
lines.push(`⚠️
|
|
493
|
+
lines.push(`⚠️ Audio send failed`);
|
|
494
494
|
}
|
|
495
495
|
}
|
|
496
496
|
break;
|
|
@@ -516,7 +516,7 @@ export class TelegramAdapter implements IMModule {
|
|
|
516
516
|
photo: imageKey,
|
|
517
517
|
caption: alt || '',
|
|
518
518
|
}).catch(async () => {
|
|
519
|
-
console.error(`[Telegram]
|
|
519
|
+
console.error(`[Telegram] Image send failed`);
|
|
520
520
|
});
|
|
521
521
|
}
|
|
522
522
|
|
|
@@ -550,7 +550,7 @@ export class TelegramAdapter implements IMModule {
|
|
|
550
550
|
document: fileKey,
|
|
551
551
|
caption: fileName,
|
|
552
552
|
}).catch(() => {
|
|
553
|
-
console.error(`[Telegram]
|
|
553
|
+
console.error(`[Telegram] File send failed: ${fileName}`);
|
|
554
554
|
});
|
|
555
555
|
}
|
|
556
556
|
|