@jackle.dev/zalox-plugin 1.0.11 → 1.0.14
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 +1 -1
- package/src/listener.ts +4 -16
- package/src/send.ts +53 -15
package/package.json
CHANGED
package/src/listener.ts
CHANGED
|
@@ -373,10 +373,10 @@ export async function startInProcessListener(
|
|
|
373
373
|
? mentions.some((m: any) => String(m.uid || m.id || m) === ownId)
|
|
374
374
|
: false;
|
|
375
375
|
const name = account.name || 'Bot';
|
|
376
|
-
const textMention = content.includes(`@${name}`);
|
|
376
|
+
const textMention = content.includes(`@${name}`) || content.includes('@Tiệp Lê');
|
|
377
377
|
|
|
378
378
|
// DEBUG Group logic
|
|
379
|
-
|
|
379
|
+
console.log(`[ZaloX] Group msg: mentioned=${isMentioned} textMention=${textMention} name=${name} content="${content}"`);
|
|
380
380
|
|
|
381
381
|
if (!isMentioned && !textMention && !content.startsWith('/')) {
|
|
382
382
|
return;
|
|
@@ -411,20 +411,8 @@ export async function startInProcessListener(
|
|
|
411
411
|
|
|
412
412
|
if (!normalized.content?.trim() && !normalized.mediaUrl) return;
|
|
413
413
|
|
|
414
|
-
// React
|
|
415
|
-
|
|
416
|
-
const reactThreadType = isGroup ? ThreadType.Group : ThreadType.User;
|
|
417
|
-
api.addReaction(Reactions.HEART, {
|
|
418
|
-
threadId: normalized.threadId,
|
|
419
|
-
type: reactThreadType,
|
|
420
|
-
data: {
|
|
421
|
-
msgId: String(data.msgId || ''),
|
|
422
|
-
cliMsgId: String(data.cliMsgId || ''),
|
|
423
|
-
},
|
|
424
|
-
}).catch((err: any) => {
|
|
425
|
-
runtime.error?.(`[${account.accountId}] ZaloX reaction failed: ${String(err)}`);
|
|
426
|
-
});
|
|
427
|
-
} catch {}
|
|
414
|
+
// React logic removed.
|
|
415
|
+
// Agent should decide when to react.
|
|
428
416
|
|
|
429
417
|
processMessage(normalized, account, config, runtime, profile, statusSink).catch((err) => {
|
|
430
418
|
runtime.error?.(`[${account.accountId}] ZaloX process error: ${String(err)}`);
|
package/src/send.ts
CHANGED
|
@@ -16,6 +16,26 @@ export type SendResult = {
|
|
|
16
16
|
error?: string;
|
|
17
17
|
};
|
|
18
18
|
|
|
19
|
+
function cleanText(input: string): string {
|
|
20
|
+
if (!input) return '';
|
|
21
|
+
// Remove <ctrl...> artifacts
|
|
22
|
+
return input.replace(/<ctrl\d+>/gi, '').trim();
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
async function withRetry<T>(fn: () => Promise<T>, retries = 3, delay = 1000): Promise<T> {
|
|
26
|
+
let lastErr;
|
|
27
|
+
for (let i = 0; i < retries; i++) {
|
|
28
|
+
try {
|
|
29
|
+
return await fn();
|
|
30
|
+
} catch (err) {
|
|
31
|
+
lastErr = err;
|
|
32
|
+
console.warn(`[ZaloX] Send failed (attempt ${i+1}/${retries}): ${err}`);
|
|
33
|
+
await new Promise(r => setTimeout(r, delay * (i + 1)));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
throw lastErr;
|
|
37
|
+
}
|
|
38
|
+
|
|
19
39
|
export async function sendText(
|
|
20
40
|
threadId: string,
|
|
21
41
|
text: string,
|
|
@@ -24,8 +44,10 @@ export async function sendText(
|
|
|
24
44
|
if (!threadId?.trim()) {
|
|
25
45
|
return { ok: false, error: 'No threadId provided' };
|
|
26
46
|
}
|
|
27
|
-
|
|
28
|
-
|
|
47
|
+
|
|
48
|
+
const cleaned = cleanText(text);
|
|
49
|
+
if (!cleaned) {
|
|
50
|
+
return { ok: false, error: 'No text provided (or empty after cleanup)' };
|
|
29
51
|
}
|
|
30
52
|
|
|
31
53
|
const cached = getCachedApi(options.profile);
|
|
@@ -35,10 +57,19 @@ export async function sendText(
|
|
|
35
57
|
|
|
36
58
|
try {
|
|
37
59
|
const type = options.isGroup ? ThreadType.Group : ThreadType.User;
|
|
38
|
-
|
|
60
|
+
|
|
61
|
+
console.log(`[ZaloX] Sending text to ${threadId} (type=${type}): "${cleaned.slice(0, 50)}..."`);
|
|
62
|
+
|
|
63
|
+
// Add retry logic
|
|
64
|
+
const result = await withRetry(() =>
|
|
65
|
+
cached.api.sendMessage(cleaned.slice(0, 2000), threadId.trim(), type)
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
console.log(`[ZaloX] Send result:`, JSON.stringify(result));
|
|
39
69
|
const msgId = result?.message?.msgId ? String(result.message.msgId) : undefined;
|
|
40
70
|
return { ok: true, messageId: msgId };
|
|
41
71
|
} catch (err: any) {
|
|
72
|
+
console.error(`[ZaloX] Final send error: ${err}`);
|
|
42
73
|
return { ok: false, error: err.message || String(err) };
|
|
43
74
|
}
|
|
44
75
|
}
|
|
@@ -57,6 +88,8 @@ export async function sendMedia(
|
|
|
57
88
|
if (!cached) {
|
|
58
89
|
return { ok: false, error: `No active API session for profile "${options.profile}". Listener may not be running.` };
|
|
59
90
|
}
|
|
91
|
+
|
|
92
|
+
const cleaned = cleanText(text);
|
|
60
93
|
|
|
61
94
|
try {
|
|
62
95
|
const type = options.isGroup ? ThreadType.Group : ThreadType.User;
|
|
@@ -71,11 +104,13 @@ export async function sendMedia(
|
|
|
71
104
|
}
|
|
72
105
|
|
|
73
106
|
if (filePath) {
|
|
74
|
-
// Send with local file attachment
|
|
75
|
-
const result = await
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
107
|
+
// Send with local file attachment (with retry)
|
|
108
|
+
const result = await withRetry(() =>
|
|
109
|
+
cached.api.sendMessage(
|
|
110
|
+
{ msg: cleaned || '', attachments: [filePath!] },
|
|
111
|
+
threadId.trim(),
|
|
112
|
+
type,
|
|
113
|
+
)
|
|
79
114
|
);
|
|
80
115
|
const msgId = result?.message?.msgId ? String(result.message.msgId) : undefined;
|
|
81
116
|
return { ok: true, messageId: msgId };
|
|
@@ -96,10 +131,13 @@ export async function sendMedia(
|
|
|
96
131
|
writeFileSync(tmpPath, buffer);
|
|
97
132
|
|
|
98
133
|
try {
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
134
|
+
// Send attachment with retry
|
|
135
|
+
const result = await withRetry(() =>
|
|
136
|
+
cached.api.sendMessage(
|
|
137
|
+
{ msg: cleaned || '', attachments: [tmpPath!] },
|
|
138
|
+
threadId.trim(),
|
|
139
|
+
type,
|
|
140
|
+
)
|
|
103
141
|
);
|
|
104
142
|
|
|
105
143
|
const msgId = result?.message?.msgId ? String(result.message.msgId) : undefined;
|
|
@@ -107,12 +145,12 @@ export async function sendMedia(
|
|
|
107
145
|
} catch (sendErr) {
|
|
108
146
|
console.error(`[ZaloX] Send attachment failed: ${sendErr}`);
|
|
109
147
|
// Fallback: send text with URL as link
|
|
110
|
-
const fullText =
|
|
148
|
+
const fullText = cleaned ? `${cleaned}\n${mediaUrl}` : mediaUrl;
|
|
111
149
|
return sendText(threadId, fullText, options);
|
|
112
150
|
}
|
|
113
151
|
} catch (dlErr: any) {
|
|
114
152
|
// Fallback: send text with URL as link
|
|
115
|
-
const fullText =
|
|
153
|
+
const fullText = cleaned ? `${cleaned}\n${mediaUrl}` : mediaUrl;
|
|
116
154
|
return sendText(threadId, fullText, options);
|
|
117
155
|
} finally {
|
|
118
156
|
if (tmpPath) try { unlinkSync(tmpPath); } catch {}
|
|
@@ -120,7 +158,7 @@ export async function sendMedia(
|
|
|
120
158
|
}
|
|
121
159
|
|
|
122
160
|
// Fallback: send text only
|
|
123
|
-
const fullText =
|
|
161
|
+
const fullText = cleaned ? `${cleaned}\n${mediaUrl}` : mediaUrl;
|
|
124
162
|
return sendText(threadId, fullText, options);
|
|
125
163
|
} catch (err: any) {
|
|
126
164
|
return { ok: false, error: err.message || String(err) };
|