@ardennguyen/zalo-agent-cli 2.5.0 → 2.5.1
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/mcp/mcp-tools.js +71 -11
package/package.json
CHANGED
package/src/mcp/mcp-tools.js
CHANGED
|
@@ -460,8 +460,8 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
460
460
|
{
|
|
461
461
|
title: "Send Zalo Message",
|
|
462
462
|
description:
|
|
463
|
-
"Send a text message,
|
|
464
|
-
"(DM or group). threadType: 0=DM(User), 1=Group. " +
|
|
463
|
+
"Send a text message, file/image attachment (`filePath` or `files`), link preview card (`link`), or " +
|
|
464
|
+
"contact card (`cardUserId`) to a Zalo thread (DM or group). threadType: 0=DM(User), 1=Group. " +
|
|
465
465
|
"To @-mention someone in a group, put `@[uid]` in the text where the tag belongs — " +
|
|
466
466
|
"`@[123456]` becomes `@Their Name` and notifies them, and `@[-1]` is @All. " +
|
|
467
467
|
"Use the `senderId` from zalo_get_messages or zalo_get_history as the uid; the display name " +
|
|
@@ -481,8 +481,22 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
481
481
|
.min(1)
|
|
482
482
|
.optional()
|
|
483
483
|
.describe(
|
|
484
|
-
"Message text to send (required unless `
|
|
485
|
-
"`@[uid]` tokens expand to @-mentions; `@[-1]` is @All.",
|
|
484
|
+
"Message text to send (required unless `filePath`, `files`, `link`, or `cardUserId` is set; " +
|
|
485
|
+
"optional caption when `filePath`, `files`, or `link` is set). `@[uid]` tokens expand to @-mentions; `@[-1]` is @All.",
|
|
486
|
+
),
|
|
487
|
+
filePath: z
|
|
488
|
+
.string()
|
|
489
|
+
.min(1)
|
|
490
|
+
.optional()
|
|
491
|
+
.describe(
|
|
492
|
+
"Optional local file or image path to send as an attachment (uses `text` as optional caption)",
|
|
493
|
+
),
|
|
494
|
+
files: z
|
|
495
|
+
.array(z.string().min(1))
|
|
496
|
+
.min(1)
|
|
497
|
+
.optional()
|
|
498
|
+
.describe(
|
|
499
|
+
"Optional list of local file or image paths to send as attachments in one call (uses `text` as optional caption)",
|
|
486
500
|
),
|
|
487
501
|
link: z
|
|
488
502
|
.string()
|
|
@@ -520,17 +534,27 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
520
534
|
),
|
|
521
535
|
})
|
|
522
536
|
.refine(
|
|
523
|
-
(val) =>
|
|
524
|
-
|
|
537
|
+
(val) =>
|
|
538
|
+
Boolean(
|
|
539
|
+
val.text ||
|
|
540
|
+
val.link ||
|
|
541
|
+
val.cardUserId ||
|
|
542
|
+
val.filePath ||
|
|
543
|
+
(Array.isArray(val.files) && val.files.length > 0),
|
|
544
|
+
),
|
|
545
|
+
"Provide at least one of text, filePath, files, link, or cardUserId",
|
|
525
546
|
)
|
|
526
|
-
.refine(
|
|
527
|
-
(val
|
|
528
|
-
|
|
529
|
-
|
|
547
|
+
.refine((val) => {
|
|
548
|
+
const hasFile = Boolean(val.filePath || (Array.isArray(val.files) && val.files.length > 0));
|
|
549
|
+
const modes = [Boolean(val.link), Boolean(val.cardUserId), hasFile].filter(Boolean).length;
|
|
550
|
+
return modes <= 1;
|
|
551
|
+
}, "Cannot combine link, cardUserId, and file attachments in a single call"),
|
|
530
552
|
},
|
|
531
553
|
async ({
|
|
532
554
|
threadId: threadIdIn,
|
|
533
555
|
text,
|
|
556
|
+
filePath,
|
|
557
|
+
files,
|
|
534
558
|
link,
|
|
535
559
|
cardUserId,
|
|
536
560
|
threadType: threadTypeIn,
|
|
@@ -577,8 +601,44 @@ export function registerTools(server, api, buffer, filter, config, nameCache, ac
|
|
|
577
601
|
});
|
|
578
602
|
}
|
|
579
603
|
|
|
604
|
+
const rawFiles = [...(filePath ? [filePath] : []), ...(Array.isArray(files) ? files : [])];
|
|
605
|
+
if (rawFiles.length > 0) {
|
|
606
|
+
const absPaths = rawFiles.map((p) => resolve(String(p).trim()));
|
|
607
|
+
const missing = absPaths.filter((p) => !existsSync(p));
|
|
608
|
+
if (missing.length > 0) {
|
|
609
|
+
return err(`File not found: ${missing.join(", ")}`);
|
|
610
|
+
}
|
|
611
|
+
const result = await api.sendMessage(
|
|
612
|
+
{ msg: text || "", attachments: absPaths },
|
|
613
|
+
threadId,
|
|
614
|
+
Number(threadType),
|
|
615
|
+
);
|
|
616
|
+
const rawAtt = result?.attachment;
|
|
617
|
+
const attRows = rawAtt ? (Array.isArray(rawAtt) ? rawAtt : [rawAtt]) : [];
|
|
618
|
+
const sent = attRows
|
|
619
|
+
.filter((r) => (r?.msgId ?? null) !== null)
|
|
620
|
+
.map((r) => ({
|
|
621
|
+
msgId: String(r.msgId),
|
|
622
|
+
cliMsgId: (r.cliMsgId ?? null) === null ? null : String(r.cliMsgId),
|
|
623
|
+
}));
|
|
624
|
+
const messageId =
|
|
625
|
+
result?.message?.msgId ?? result?.msgId ?? (sent.length > 0 ? sent[0].msgId : null);
|
|
626
|
+
const cliMsgId =
|
|
627
|
+
result?.message?.cliMsgId ?? result?.cliMsgId ?? (sent.length > 0 ? sent[0].cliMsgId : null);
|
|
628
|
+
return ok({
|
|
629
|
+
success: true,
|
|
630
|
+
kind: "attachment",
|
|
631
|
+
files: absPaths,
|
|
632
|
+
sent,
|
|
633
|
+
messageId,
|
|
634
|
+
...(cliMsgId !== null && { cliMsgId: String(cliMsgId) }),
|
|
635
|
+
threadType,
|
|
636
|
+
...(thread.notice && { threadId, notice: thread.notice }),
|
|
637
|
+
});
|
|
638
|
+
}
|
|
639
|
+
|
|
580
640
|
if (!text) {
|
|
581
|
-
return err("Provide text, link, or cardUserId.");
|
|
641
|
+
return err("Provide text, filePath, files, link, or cardUserId.");
|
|
582
642
|
}
|
|
583
643
|
|
|
584
644
|
const warnings = [];
|