@ian2018cs/agenthub 0.1.91 → 0.1.93

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ian2018cs/agenthub",
3
- "version": "0.1.91",
3
+ "version": "0.1.93",
4
4
  "description": "A web-based UI for AI Agents",
5
5
  "type": "module",
6
6
  "main": "server/index.js",
@@ -104,7 +104,7 @@ router.get('/:userUuid/:sessionId', async (req, res) => {
104
104
  return res.json({
105
105
  mode: 'static',
106
106
  title: share.session_title || snapshot.title || '对话分享',
107
- projectName: share.project_name,
107
+ projectName: projectDisplayName,
108
108
  messages,
109
109
  generatedAt: snapshot.generatedAt,
110
110
  sharerName,
@@ -43,19 +43,34 @@ export class FeishuWriter {
43
43
  getSessionId() { return this.sessionId; }
44
44
 
45
45
  async _sendToFeishu() {
46
- try {
47
- const text = this.textBuffer.trim();
48
- if (!text) {
49
- console.log(`[CronFeishu] Task ${this.cronId} completed with empty response, skipping send`);
50
- return;
46
+ const text = this.textBuffer.trim();
47
+ if (!text) {
48
+ console.log(`[CronFeishu] Task ${this.cronId} completed with empty response, skipping send`);
49
+ return;
50
+ }
51
+ const chunks = splitMessage(text, 4000);
52
+ const MAX_RETRIES = 3;
53
+ for (let i = 0; i < chunks.length; i++) {
54
+ const chunk = chunks[i];
55
+ let lastErr;
56
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
57
+ try {
58
+ await this.larkClient.sendTextToTarget(this._target, chunk);
59
+ lastErr = null;
60
+ break;
61
+ } catch (err) {
62
+ lastErr = err;
63
+ if (attempt < MAX_RETRIES) {
64
+ const delay = attempt * 2000; // 2s, 4s
65
+ console.warn(`[CronFeishu] Task ${this.cronId} chunk ${i + 1}/${chunks.length} send failed (attempt ${attempt}/${MAX_RETRIES}), retrying in ${delay}ms: ${err.message}`);
66
+ await new Promise(r => setTimeout(r, delay));
67
+ }
68
+ }
51
69
  }
52
- const chunks = splitMessage(text, 4000);
53
- for (const chunk of chunks) {
54
- await this.larkClient.sendTextToTarget(this._target, chunk);
70
+ if (lastErr) {
71
+ console.error(`[CronFeishu] Send failed for task ${this.cronId} chunk ${i + 1}/${chunks.length} after ${MAX_RETRIES} attempts:`, lastErr.message);
55
72
  }
56
- console.log(`[CronFeishu] Task ${this.cronId} sent ${chunks.length} chunk(s) to ${this._target}`);
57
- } catch (err) {
58
- console.error(`[CronFeishu] Send failed for task ${this.cronId}:`, err.message);
59
73
  }
74
+ console.log(`[CronFeishu] Task ${this.cronId} sent ${chunks.length} chunk(s) to ${this._target}`);
60
75
  }
61
76
  }
@@ -41,30 +41,42 @@ export class WebhookWriter {
41
41
  getSessionId() { return this.sessionId; }
42
42
 
43
43
  async _postWebhook() {
44
- try {
45
- const feishu = buildTextOrMarkdownMessage(this.textBuffer);
46
- const parsedContent = JSON.parse(feishu.content);
47
- // 飞书 webhook: text content 字段,interactive 用 card 字段
48
- const feishuPayload = feishu.msgType === 'interactive'
49
- ? { msg_type: feishu.msgType, card: parsedContent }
50
- : { msg_type: feishu.msgType, content: parsedContent };
51
- const body = {
52
- cron_id: this.meta.cronId,
53
- cron_expr: this.meta.cronExpr,
54
- prompt: this.meta.prompt,
55
- fired_at: Date.now(),
56
- response: this.textBuffer,
57
- ...feishuPayload,
58
- };
59
- console.log(`[CronWebhook] POST body:`, JSON.stringify(body));
60
- await fetch(this.webhookUrl, {
61
- method: 'POST',
62
- headers: { 'Content-Type': 'application/json' },
63
- body: JSON.stringify(body),
64
- });
65
- console.log(`[CronWebhook] POST succeeded for task ${this.meta.cronId}, response length=${this.textBuffer.length}`);
66
- } catch (err) {
67
- console.error(`[CronWebhook] POST failed for task ${this.meta.cronId}:`, err.message);
44
+ const feishu = buildTextOrMarkdownMessage(this.textBuffer);
45
+ const parsedContent = JSON.parse(feishu.content);
46
+ const feishuPayload = feishu.msgType === 'interactive'
47
+ ? { msg_type: feishu.msgType, card: parsedContent }
48
+ : { msg_type: feishu.msgType, content: parsedContent };
49
+ const body = {
50
+ cron_id: this.meta.cronId,
51
+ cron_expr: this.meta.cronExpr,
52
+ prompt: this.meta.prompt,
53
+ fired_at: Date.now(),
54
+ response: this.textBuffer,
55
+ ...feishuPayload,
56
+ };
57
+ console.log(`[CronWebhook] POST body:`, JSON.stringify(body));
58
+
59
+ const MAX_RETRIES = 3;
60
+ let lastErr;
61
+ for (let attempt = 1; attempt <= MAX_RETRIES; attempt++) {
62
+ try {
63
+ const res = await fetch(this.webhookUrl, {
64
+ method: 'POST',
65
+ headers: { 'Content-Type': 'application/json' },
66
+ body: JSON.stringify(body),
67
+ });
68
+ if (!res.ok) throw new Error(`HTTP ${res.status}`);
69
+ console.log(`[CronWebhook] POST succeeded for task ${this.meta.cronId}, response length=${this.textBuffer.length}`);
70
+ return;
71
+ } catch (err) {
72
+ lastErr = err;
73
+ if (attempt < MAX_RETRIES) {
74
+ const delay = attempt * 2000; // 2s, 4s
75
+ console.warn(`[CronWebhook] POST failed for task ${this.meta.cronId} (attempt ${attempt}/${MAX_RETRIES}), retrying in ${delay}ms: ${err.message}`);
76
+ await new Promise(r => setTimeout(r, delay));
77
+ }
78
+ }
68
79
  }
80
+ console.error(`[CronWebhook] POST failed for task ${this.meta.cronId} after ${MAX_RETRIES} attempts:`, lastErr.message);
69
81
  }
70
82
  }