@agent-wechat/wechat 0.3.0 → 0.4.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/dist/index.js +173 -169
- package/package.json +6 -2
package/dist/index.js
CHANGED
|
@@ -1106,6 +1106,21 @@ function resolveWeChatAccount(cfg, accountId) {
|
|
|
1106
1106
|
};
|
|
1107
1107
|
}
|
|
1108
1108
|
|
|
1109
|
+
// src/runtime.ts
|
|
1110
|
+
var runtime = null;
|
|
1111
|
+
function setWeChatRuntime(next) {
|
|
1112
|
+
runtime = next;
|
|
1113
|
+
}
|
|
1114
|
+
function getWeChatRuntime() {
|
|
1115
|
+
if (!runtime) {
|
|
1116
|
+
throw new Error("WeChat runtime not initialized");
|
|
1117
|
+
}
|
|
1118
|
+
return runtime;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1121
|
+
// src/monitor.ts
|
|
1122
|
+
import { execSync } from "node:child_process";
|
|
1123
|
+
|
|
1109
1124
|
// ../shared/dist/client.js
|
|
1110
1125
|
function normalizeUrl(base) {
|
|
1111
1126
|
const url = base.startsWith("http") ? base : `http://${base}`;
|
|
@@ -5486,20 +5501,6 @@ var agentConfigSchema = external_exports.object({
|
|
|
5486
5501
|
|
|
5487
5502
|
// src/monitor.ts
|
|
5488
5503
|
import { createReplyPrefixOptions } from "openclaw/plugin-sdk";
|
|
5489
|
-
|
|
5490
|
-
// src/runtime.ts
|
|
5491
|
-
var runtime = null;
|
|
5492
|
-
function setWeChatRuntime(next) {
|
|
5493
|
-
runtime = next;
|
|
5494
|
-
}
|
|
5495
|
-
function getWeChatRuntime() {
|
|
5496
|
-
if (!runtime) {
|
|
5497
|
-
throw new Error("WeChat runtime not initialized");
|
|
5498
|
-
}
|
|
5499
|
-
return runtime;
|
|
5500
|
-
}
|
|
5501
|
-
|
|
5502
|
-
// src/monitor.ts
|
|
5503
5504
|
var MEDIA_TYPES = /* @__PURE__ */ new Set([3, 34]);
|
|
5504
5505
|
var HISTORY_CONTEXT_MARKER = "[Chat messages since your last reply - for context]";
|
|
5505
5506
|
var CURRENT_MESSAGE_MARKER = "[Current message - respond to this]";
|
|
@@ -5552,8 +5553,16 @@ function enqueueWeChatSystemEvent(text, contextKey) {
|
|
|
5552
5553
|
} catch {
|
|
5553
5554
|
}
|
|
5554
5555
|
}
|
|
5556
|
+
function enqueueAndWakeSystemEvent(text, contextKey, log) {
|
|
5557
|
+
enqueueWeChatSystemEvent(text, contextKey);
|
|
5558
|
+
try {
|
|
5559
|
+
execSync("openclaw system event --mode now", { timeout: 5e3, stdio: "ignore" });
|
|
5560
|
+
} catch {
|
|
5561
|
+
log?.info?.("Failed to trigger heartbeat wake \u2014 agent will see event on next prompt");
|
|
5562
|
+
}
|
|
5563
|
+
}
|
|
5555
5564
|
async function startWeChatMonitor(opts) {
|
|
5556
|
-
const { account, abortSignal,
|
|
5565
|
+
const { account, abortSignal, setStatus, log } = opts;
|
|
5557
5566
|
const client = new WeChatClient({ baseUrl: account.serverUrl, token: account.token });
|
|
5558
5567
|
const lastSeenId = /* @__PURE__ */ new Map();
|
|
5559
5568
|
let lastAuthCheck = 0;
|
|
@@ -5581,12 +5590,13 @@ async function startWeChatMonitor(opts) {
|
|
|
5581
5590
|
authStatus: auth.status
|
|
5582
5591
|
});
|
|
5583
5592
|
if (prevStatus === "logged_in" && !isLinked) {
|
|
5584
|
-
const msg = auth.status === "app_not_running" ? "[WeChat] Application stopped. It will restart automatically \u2014
|
|
5585
|
-
|
|
5593
|
+
const msg = auth.status === "app_not_running" ? "[WeChat] Application stopped. It will restart automatically \u2014 credentials may be cached, so you can try reconnecting using the wechat_login tool." : "[WeChat] Session ended. You can try reconnecting using the wechat_login tool \u2014 if credentials are cached, login may complete automatically.";
|
|
5594
|
+
enqueueAndWakeSystemEvent(msg, "wechat:auth_lost", log);
|
|
5586
5595
|
} else if (prevStatus === void 0 && !isLinked) {
|
|
5587
|
-
|
|
5588
|
-
"[WeChat] Not logged in. Use the wechat_login tool to authenticate.",
|
|
5589
|
-
"wechat:auth_required"
|
|
5596
|
+
enqueueAndWakeSystemEvent(
|
|
5597
|
+
"[WeChat] Not logged in. Use the wechat_login tool to authenticate \u2014 if credentials are cached from a previous session, login may complete automatically.",
|
|
5598
|
+
"wechat:auth_required",
|
|
5599
|
+
log
|
|
5590
5600
|
);
|
|
5591
5601
|
}
|
|
5592
5602
|
prevStatus = auth.status;
|
|
@@ -5604,9 +5614,10 @@ async function startWeChatMonitor(opts) {
|
|
|
5604
5614
|
lastError: String(err)
|
|
5605
5615
|
});
|
|
5606
5616
|
if (prevStatus === "logged_in") {
|
|
5607
|
-
|
|
5617
|
+
enqueueAndWakeSystemEvent(
|
|
5608
5618
|
"[WeChat] Cannot reach agent-wechat server. The container may have stopped.",
|
|
5609
|
-
"wechat:server_unreachable"
|
|
5619
|
+
"wechat:server_unreachable",
|
|
5620
|
+
log
|
|
5610
5621
|
);
|
|
5611
5622
|
}
|
|
5612
5623
|
prevStatus = void 0;
|
|
@@ -5768,7 +5779,8 @@ ${replyBlock}` : replyBlock;
|
|
|
5768
5779
|
senderId,
|
|
5769
5780
|
isGroup,
|
|
5770
5781
|
timestamp,
|
|
5771
|
-
hasMedia
|
|
5782
|
+
hasMedia,
|
|
5783
|
+
isMentioned: isGroup && msg.isMentioned === true
|
|
5772
5784
|
};
|
|
5773
5785
|
}
|
|
5774
5786
|
function buildSegments(processed) {
|
|
@@ -5800,6 +5812,18 @@ async function dispatchSegment(segment, client, chatId, chat, liveAccount, cfg,
|
|
|
5800
5812
|
log?.info?.(
|
|
5801
5813
|
`[wechat:${liveAccount.accountId}] Dispatching segment: ${segment.length} msg(s), last=${msg.localId}${mediaPath ? ` media=${mediaPath}` : ""}`
|
|
5802
5814
|
);
|
|
5815
|
+
if (isGroup) {
|
|
5816
|
+
const wechatCfg = cfg?.channels?.wechat;
|
|
5817
|
+
const groupEntry = wechatCfg?.groups?.[chatId];
|
|
5818
|
+
const defaultEntry = wechatCfg?.groups?.["*"];
|
|
5819
|
+
const requireMention = groupEntry?.requireMention ?? defaultEntry?.requireMention ?? true;
|
|
5820
|
+
if (requireMention && !lastMsg.isMentioned) {
|
|
5821
|
+
log?.info?.(
|
|
5822
|
+
`[wechat:${liveAccount.accountId}] Skipping group message (mention required, not mentioned) in ${chatId}`
|
|
5823
|
+
);
|
|
5824
|
+
return;
|
|
5825
|
+
}
|
|
5826
|
+
}
|
|
5803
5827
|
try {
|
|
5804
5828
|
const route = core.channel.routing.resolveAgentRoute({
|
|
5805
5829
|
cfg,
|
|
@@ -5886,6 +5910,7 @@ async function dispatchSegment(segment, client, chatId, chat, liveAccount, cfg,
|
|
|
5886
5910
|
Provider: "wechat",
|
|
5887
5911
|
Surface: "wechat",
|
|
5888
5912
|
MessageSid: `wechat:${chatId}:${msg.localId}`,
|
|
5913
|
+
WasMentioned: isGroup ? lastMsg.isMentioned : void 0,
|
|
5889
5914
|
OriginatingChannel: "wechat",
|
|
5890
5915
|
OriginatingTo: `wechat:${chatId}`,
|
|
5891
5916
|
...mediaPath ? { MediaPath: mediaPath, MediaUrl: mediaPath, MediaType: mediaMime } : {},
|
|
@@ -6289,24 +6314,26 @@ function readOrGenerateToken() {
|
|
|
6289
6314
|
return token;
|
|
6290
6315
|
}
|
|
6291
6316
|
var wechatOnboardingAdapter = {
|
|
6292
|
-
|
|
6293
|
-
|
|
6294
|
-
|
|
6295
|
-
if (!account
|
|
6317
|
+
channel: "wechat",
|
|
6318
|
+
getStatus: async ({ cfg }) => {
|
|
6319
|
+
const account = resolveWeChatAccount(cfg);
|
|
6320
|
+
if (!account?.serverUrl) {
|
|
6296
6321
|
return {
|
|
6322
|
+
channel: "wechat",
|
|
6297
6323
|
configured: false,
|
|
6298
|
-
|
|
6324
|
+
statusLines: ["Not configured. Run: openclaw channels setup wechat"]
|
|
6299
6325
|
};
|
|
6300
6326
|
}
|
|
6301
6327
|
const client = new WeChatClient({ baseUrl: account.serverUrl, token: account.token });
|
|
6302
|
-
const
|
|
6328
|
+
const statusLines = [];
|
|
6303
6329
|
try {
|
|
6304
6330
|
await client.status();
|
|
6305
|
-
|
|
6331
|
+
statusLines.push(`Connected to ${account.serverUrl}`);
|
|
6306
6332
|
} catch {
|
|
6307
6333
|
return {
|
|
6334
|
+
channel: "wechat",
|
|
6308
6335
|
configured: true,
|
|
6309
|
-
|
|
6336
|
+
statusLines: [
|
|
6310
6337
|
`Server URL: ${account.serverUrl}`,
|
|
6311
6338
|
"Cannot reach server \u2014 is the agent-wechat container running?"
|
|
6312
6339
|
]
|
|
@@ -6315,45 +6342,44 @@ var wechatOnboardingAdapter = {
|
|
|
6315
6342
|
try {
|
|
6316
6343
|
const auth = await client.authStatus();
|
|
6317
6344
|
if (auth.status === "logged_in") {
|
|
6318
|
-
|
|
6345
|
+
statusLines.push(
|
|
6319
6346
|
`Logged in${auth.loggedInUser ? ` as ${auth.loggedInUser}` : ""}`
|
|
6320
6347
|
);
|
|
6321
6348
|
} else {
|
|
6322
|
-
|
|
6349
|
+
statusLines.push("Not logged in. Run: openclaw channels login --channel wechat");
|
|
6323
6350
|
}
|
|
6324
6351
|
} catch {
|
|
6325
|
-
|
|
6352
|
+
statusLines.push("Could not check auth status");
|
|
6326
6353
|
}
|
|
6327
|
-
|
|
6354
|
+
statusLines.push(`DM policy: ${account.dmPolicy}`);
|
|
6328
6355
|
if (account.allowFrom.length > 0) {
|
|
6329
|
-
|
|
6356
|
+
statusLines.push(`Allowed senders: ${account.allowFrom.join(", ")}`);
|
|
6330
6357
|
}
|
|
6331
|
-
|
|
6332
|
-
return { configured: true,
|
|
6358
|
+
statusLines.push(`Group policy: ${account.groupPolicy}`);
|
|
6359
|
+
return { channel: "wechat", configured: true, statusLines };
|
|
6333
6360
|
},
|
|
6334
|
-
configure: async ({
|
|
6335
|
-
|
|
6336
|
-
|
|
6337
|
-
|
|
6338
|
-
|
|
6339
|
-
const existingUrl = cfg?.channels?.wechat?.serverUrl ?? "http://localhost:6174";
|
|
6361
|
+
configure: async ({ prompter, cfg }) => {
|
|
6362
|
+
const wechatCfg = {
|
|
6363
|
+
...cfg?.channels?.wechat ?? {}
|
|
6364
|
+
};
|
|
6365
|
+
const existingUrl = wechatCfg.serverUrl ?? "http://localhost:6174";
|
|
6340
6366
|
const serverUrl = await prompter.text({
|
|
6341
6367
|
message: "Agent-wechat server URL",
|
|
6342
|
-
|
|
6368
|
+
initialValue: existingUrl
|
|
6343
6369
|
});
|
|
6344
|
-
|
|
6345
|
-
const existingToken =
|
|
6370
|
+
wechatCfg.serverUrl = serverUrl;
|
|
6371
|
+
const existingToken = wechatCfg.token ?? "";
|
|
6346
6372
|
const localDefault = existingToken || readOrGenerateToken();
|
|
6347
6373
|
const token = await prompter.text({
|
|
6348
6374
|
message: "Auth token (leave empty to use local token)",
|
|
6349
|
-
|
|
6375
|
+
initialValue: localDefault
|
|
6350
6376
|
});
|
|
6351
|
-
|
|
6377
|
+
wechatCfg.token = token || localDefault;
|
|
6352
6378
|
const client = new WeChatClient({ baseUrl: serverUrl, token: token || void 0 });
|
|
6353
6379
|
try {
|
|
6354
6380
|
await client.status();
|
|
6355
6381
|
} catch {
|
|
6356
|
-
|
|
6382
|
+
wechatCfg.enabled = false;
|
|
6357
6383
|
throw new Error(
|
|
6358
6384
|
`Cannot reach ${serverUrl}. Ensure the agent-wechat container is running.`
|
|
6359
6385
|
);
|
|
@@ -6363,10 +6389,10 @@ var wechatOnboardingAdapter = {
|
|
|
6363
6389
|
if (auth.status !== "logged_in") {
|
|
6364
6390
|
const wantsLink = await prompter.confirm({
|
|
6365
6391
|
message: "WeChat not logged in. Link now?",
|
|
6366
|
-
|
|
6392
|
+
initialValue: true
|
|
6367
6393
|
});
|
|
6368
6394
|
if (wantsLink) {
|
|
6369
|
-
await prompter.note
|
|
6395
|
+
await prompter.note(
|
|
6370
6396
|
"Starting login \u2014 watch for QR code or phone confirmation.",
|
|
6371
6397
|
"WeChat Login"
|
|
6372
6398
|
);
|
|
@@ -6375,52 +6401,37 @@ var wechatOnboardingAdapter = {
|
|
|
6375
6401
|
onEvent: (event) => {
|
|
6376
6402
|
switch (event.type) {
|
|
6377
6403
|
case "status":
|
|
6378
|
-
prompter.
|
|
6404
|
+
prompter.note?.(event.message, "Status");
|
|
6379
6405
|
break;
|
|
6380
6406
|
case "qr":
|
|
6381
|
-
prompter.
|
|
6382
|
-
if (event.qrData) {
|
|
6383
|
-
try {
|
|
6384
|
-
const qrTerminalMod = require_main();
|
|
6385
|
-
const qrInput = event.qrBinaryData ? Buffer.from(event.qrBinaryData).toString("utf-8") : event.qrData;
|
|
6386
|
-
qrTerminalMod.generate(qrInput, { small: true }, (qr) => {
|
|
6387
|
-
prompter.log?.(qr);
|
|
6388
|
-
});
|
|
6389
|
-
} catch {
|
|
6390
|
-
if (event.qrDataUrl) {
|
|
6391
|
-
prompter.log?.("(QR data URL available \u2014 open in browser to scan)");
|
|
6392
|
-
}
|
|
6393
|
-
}
|
|
6394
|
-
}
|
|
6395
|
-
prompter.log?.("\nWaiting for scan...\n");
|
|
6407
|
+
prompter.note?.("Scan QR code with WeChat", "Login");
|
|
6396
6408
|
break;
|
|
6397
6409
|
case "phone_confirm":
|
|
6398
|
-
prompter.
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
`
|
|
6410
|
+
prompter.note?.(
|
|
6411
|
+
event.message || "Please confirm login on your phone",
|
|
6412
|
+
"Confirm"
|
|
6402
6413
|
);
|
|
6403
6414
|
break;
|
|
6404
6415
|
case "login_success":
|
|
6405
|
-
prompter.
|
|
6416
|
+
prompter.note?.("Login successful!", "Done");
|
|
6406
6417
|
break;
|
|
6407
6418
|
case "login_timeout":
|
|
6408
|
-
prompter.
|
|
6419
|
+
prompter.note?.("Login timed out. Please try again.", "Timeout");
|
|
6409
6420
|
break;
|
|
6410
6421
|
case "error":
|
|
6411
|
-
prompter.
|
|
6412
|
-
Error: ${event.message}`);
|
|
6422
|
+
prompter.note?.(`Error: ${event.message}`, "Error");
|
|
6413
6423
|
break;
|
|
6414
6424
|
}
|
|
6415
6425
|
}
|
|
6416
6426
|
});
|
|
6417
6427
|
} catch (err) {
|
|
6418
|
-
prompter.
|
|
6419
|
-
`Login failed: ${err instanceof Error ? err.message : String(err)}
|
|
6428
|
+
prompter.note?.(
|
|
6429
|
+
`Login failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
6430
|
+
"Error"
|
|
6420
6431
|
);
|
|
6421
6432
|
}
|
|
6422
6433
|
} else {
|
|
6423
|
-
await prompter.note
|
|
6434
|
+
await prompter.note(
|
|
6424
6435
|
"Run `openclaw channels login --channel wechat` later to link.",
|
|
6425
6436
|
"WeChat"
|
|
6426
6437
|
);
|
|
@@ -6430,54 +6441,45 @@ Error: ${event.message}`);
|
|
|
6430
6441
|
}
|
|
6431
6442
|
const dmPolicy = await prompter.select({
|
|
6432
6443
|
message: "DM (direct message) policy",
|
|
6433
|
-
|
|
6444
|
+
options: [
|
|
6434
6445
|
{ label: "Disabled \u2014 ignore all DMs", value: "disabled" },
|
|
6435
|
-
{
|
|
6436
|
-
label: "Allowlist \u2014 only respond to specific senders",
|
|
6437
|
-
value: "allowlist"
|
|
6438
|
-
},
|
|
6446
|
+
{ label: "Allowlist \u2014 only respond to specific senders", value: "allowlist" },
|
|
6439
6447
|
{ label: "Open \u2014 respond to all DMs", value: "open" }
|
|
6440
6448
|
]
|
|
6441
6449
|
});
|
|
6442
|
-
|
|
6450
|
+
wechatCfg.dmPolicy = dmPolicy;
|
|
6443
6451
|
if (dmPolicy === "allowlist") {
|
|
6444
|
-
const
|
|
6445
|
-
message: "Allowed WeChat IDs (wxid_xxx)
|
|
6446
|
-
hint: "Enter wxid values, press Enter after each. Empty line to finish."
|
|
6452
|
+
const raw = await prompter.text({
|
|
6453
|
+
message: "Allowed WeChat IDs (comma-separated wxid_xxx values)"
|
|
6447
6454
|
});
|
|
6448
|
-
|
|
6455
|
+
wechatCfg.allowFrom = raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
6449
6456
|
}
|
|
6450
6457
|
const groupPolicy = await prompter.select({
|
|
6451
6458
|
message: "Group chat policy",
|
|
6452
|
-
|
|
6453
|
-
{
|
|
6454
|
-
|
|
6455
|
-
|
|
6456
|
-
},
|
|
6457
|
-
{
|
|
6458
|
-
label: "Allowlist \u2014 only respond in specific groups",
|
|
6459
|
-
value: "allowlist"
|
|
6460
|
-
},
|
|
6461
|
-
{
|
|
6462
|
-
label: "Open \u2014 respond in all groups (when mentioned)",
|
|
6463
|
-
value: "open"
|
|
6464
|
-
}
|
|
6459
|
+
options: [
|
|
6460
|
+
{ label: "Disabled \u2014 ignore all group messages", value: "disabled" },
|
|
6461
|
+
{ label: "Allowlist \u2014 only respond in specific groups", value: "allowlist" },
|
|
6462
|
+
{ label: "Open \u2014 respond in all groups (when mentioned)", value: "open" }
|
|
6465
6463
|
]
|
|
6466
6464
|
});
|
|
6467
|
-
|
|
6465
|
+
wechatCfg.groupPolicy = groupPolicy;
|
|
6468
6466
|
if (groupPolicy === "allowlist") {
|
|
6469
|
-
const
|
|
6470
|
-
message: "Allowed group IDs (xxx@chatroom)
|
|
6471
|
-
hint: "Enter chatroom IDs, press Enter after each. Empty line to finish."
|
|
6467
|
+
const raw = await prompter.text({
|
|
6468
|
+
message: "Allowed group IDs (comma-separated xxx@chatroom values)"
|
|
6472
6469
|
});
|
|
6473
|
-
|
|
6470
|
+
wechatCfg.groupAllowFrom = raw.split(",").map((s) => s.trim()).filter(Boolean);
|
|
6474
6471
|
}
|
|
6475
|
-
|
|
6472
|
+
wechatCfg.enabled = true;
|
|
6473
|
+
const newCfg = {
|
|
6474
|
+
...cfg,
|
|
6475
|
+
channels: { ...cfg.channels, wechat: wechatCfg }
|
|
6476
|
+
};
|
|
6477
|
+
return { cfg: newCfg };
|
|
6476
6478
|
}
|
|
6477
6479
|
};
|
|
6478
6480
|
|
|
6479
6481
|
// src/status.ts
|
|
6480
|
-
|
|
6482
|
+
function collectWeChatStatusIssues(accounts) {
|
|
6481
6483
|
const issues = [];
|
|
6482
6484
|
for (const snapshot of accounts) {
|
|
6483
6485
|
if (!snapshot.connected) {
|
|
@@ -6534,7 +6536,8 @@ function createWeChatLoginTool(account) {
|
|
|
6534
6536
|
},
|
|
6535
6537
|
required: ["action"]
|
|
6536
6538
|
},
|
|
6537
|
-
execute: async (_toolCallId,
|
|
6539
|
+
execute: async (_toolCallId, params) => {
|
|
6540
|
+
const args = params;
|
|
6538
6541
|
const action = args.action;
|
|
6539
6542
|
const force = args.force;
|
|
6540
6543
|
const timeoutMs = args.timeoutMs;
|
|
@@ -6657,6 +6660,7 @@ var meta = {
|
|
|
6657
6660
|
label: "WeChat",
|
|
6658
6661
|
selectionLabel: "WeChat (\u5FAE\u4FE1)",
|
|
6659
6662
|
blurb: "WeChat messaging via agent-wechat container.",
|
|
6663
|
+
docsPath: "wechat",
|
|
6660
6664
|
aliases: ["weixin"],
|
|
6661
6665
|
order: 80
|
|
6662
6666
|
};
|
|
@@ -6773,14 +6777,16 @@ var wechatPlugin = {
|
|
|
6773
6777
|
cfg
|
|
6774
6778
|
);
|
|
6775
6779
|
if (!account?.serverUrl) {
|
|
6776
|
-
|
|
6780
|
+
throw new Error("No serverUrl configured");
|
|
6777
6781
|
}
|
|
6778
6782
|
const client = new WeChatClient({ baseUrl: account.serverUrl, token: account.token });
|
|
6779
6783
|
const result = await client.sendMessage({ chatId: to, text });
|
|
6784
|
+
if (!result.success) {
|
|
6785
|
+
throw new Error(result.error ?? "Send failed");
|
|
6786
|
+
}
|
|
6780
6787
|
return {
|
|
6781
6788
|
channel: "wechat",
|
|
6782
|
-
|
|
6783
|
-
error: result.error ?? void 0
|
|
6789
|
+
messageId: `wechat:${to}:${Date.now()}`
|
|
6784
6790
|
};
|
|
6785
6791
|
},
|
|
6786
6792
|
sendMedia: async ({ cfg, to, text, mediaUrl }) => {
|
|
@@ -6788,68 +6794,64 @@ var wechatPlugin = {
|
|
|
6788
6794
|
cfg
|
|
6789
6795
|
);
|
|
6790
6796
|
if (!account?.serverUrl) {
|
|
6791
|
-
|
|
6797
|
+
throw new Error("No serverUrl configured");
|
|
6792
6798
|
}
|
|
6793
6799
|
const client = new WeChatClient({ baseUrl: account.serverUrl, token: account.token });
|
|
6794
6800
|
if (mediaUrl) {
|
|
6795
|
-
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
|
|
6799
|
-
|
|
6800
|
-
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
|
|
6806
|
-
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
6811
|
-
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
|
|
6818
|
-
webp: "image/webp"
|
|
6819
|
-
};
|
|
6820
|
-
mimeType = extMime[ext] ?? "application/octet-stream";
|
|
6821
|
-
}
|
|
6822
|
-
const isImage = mimeType.startsWith("image/");
|
|
6823
|
-
const result2 = isImage ? await client.sendMessage({
|
|
6824
|
-
chatId: to,
|
|
6825
|
-
text: text || void 0,
|
|
6826
|
-
image: { data: base64, mimeType }
|
|
6827
|
-
}) : await client.sendMessage({
|
|
6828
|
-
chatId: to,
|
|
6829
|
-
text: text || void 0,
|
|
6830
|
-
file: { data: base64, filename }
|
|
6831
|
-
});
|
|
6832
|
-
return {
|
|
6833
|
-
channel: "wechat",
|
|
6834
|
-
ok: result2.success,
|
|
6835
|
-
error: result2.error ?? void 0
|
|
6836
|
-
};
|
|
6837
|
-
} catch (err) {
|
|
6838
|
-
return {
|
|
6839
|
-
channel: "wechat",
|
|
6840
|
-
ok: false,
|
|
6841
|
-
error: `Failed to send media: ${err}`
|
|
6801
|
+
const fsmod = await import("fs/promises");
|
|
6802
|
+
const pathmod = await import("path");
|
|
6803
|
+
let base64;
|
|
6804
|
+
let mimeType;
|
|
6805
|
+
let filename;
|
|
6806
|
+
if (mediaUrl.startsWith("http://") || mediaUrl.startsWith("https://")) {
|
|
6807
|
+
const res = await fetch(mediaUrl);
|
|
6808
|
+
const buffer = await res.arrayBuffer();
|
|
6809
|
+
base64 = Buffer.from(buffer).toString("base64");
|
|
6810
|
+
mimeType = res.headers.get("content-type") ?? "application/octet-stream";
|
|
6811
|
+
const urlPath = new URL(mediaUrl).pathname;
|
|
6812
|
+
filename = pathmod.basename(urlPath) || "file";
|
|
6813
|
+
} else {
|
|
6814
|
+
const buf = await fsmod.readFile(mediaUrl);
|
|
6815
|
+
base64 = buf.toString("base64");
|
|
6816
|
+
filename = pathmod.basename(mediaUrl);
|
|
6817
|
+
const ext = pathmod.extname(mediaUrl).toLowerCase().replace(".", "");
|
|
6818
|
+
const extMime = {
|
|
6819
|
+
png: "image/png",
|
|
6820
|
+
jpg: "image/jpeg",
|
|
6821
|
+
jpeg: "image/jpeg",
|
|
6822
|
+
gif: "image/gif",
|
|
6823
|
+
webp: "image/webp"
|
|
6842
6824
|
};
|
|
6825
|
+
mimeType = extMime[ext] ?? "application/octet-stream";
|
|
6826
|
+
}
|
|
6827
|
+
const isImage = mimeType.startsWith("image/");
|
|
6828
|
+
const result2 = isImage ? await client.sendMessage({
|
|
6829
|
+
chatId: to,
|
|
6830
|
+
text: text || void 0,
|
|
6831
|
+
image: { data: base64, mimeType }
|
|
6832
|
+
}) : await client.sendMessage({
|
|
6833
|
+
chatId: to,
|
|
6834
|
+
text: text || void 0,
|
|
6835
|
+
file: { data: base64, filename }
|
|
6836
|
+
});
|
|
6837
|
+
if (!result2.success) {
|
|
6838
|
+
throw new Error(result2.error ?? "Send media failed");
|
|
6843
6839
|
}
|
|
6840
|
+
return {
|
|
6841
|
+
channel: "wechat",
|
|
6842
|
+
messageId: `wechat:${to}:${Date.now()}`
|
|
6843
|
+
};
|
|
6844
6844
|
}
|
|
6845
6845
|
const result = await client.sendMessage({
|
|
6846
6846
|
chatId: to,
|
|
6847
6847
|
text: text || void 0
|
|
6848
6848
|
});
|
|
6849
|
+
if (!result.success) {
|
|
6850
|
+
throw new Error(result.error ?? "Send failed");
|
|
6851
|
+
}
|
|
6849
6852
|
return {
|
|
6850
6853
|
channel: "wechat",
|
|
6851
|
-
|
|
6852
|
-
error: result.error ?? void 0
|
|
6854
|
+
messageId: `wechat:${to}:${Date.now()}`
|
|
6853
6855
|
};
|
|
6854
6856
|
}
|
|
6855
6857
|
},
|
|
@@ -6868,7 +6870,8 @@ var wechatPlugin = {
|
|
|
6868
6870
|
cfg: ctx.cfg
|
|
6869
6871
|
});
|
|
6870
6872
|
},
|
|
6871
|
-
loginWithQrStart: async ({
|
|
6873
|
+
loginWithQrStart: async ({ accountId, force, timeoutMs }) => {
|
|
6874
|
+
const cfg = getWeChatRuntime().config.loadConfig();
|
|
6872
6875
|
const account = resolveWeChatAccount(
|
|
6873
6876
|
cfg,
|
|
6874
6877
|
accountId ?? void 0
|
|
@@ -6878,7 +6881,7 @@ var wechatPlugin = {
|
|
|
6878
6881
|
}
|
|
6879
6882
|
const client = new WeChatClient({ baseUrl: account.serverUrl, token: account.token });
|
|
6880
6883
|
try {
|
|
6881
|
-
const result = await loginStart(client, accountId, { timeoutMs, force });
|
|
6884
|
+
const result = await loginStart(client, accountId ?? DEFAULT_ACCOUNT_ID2, { timeoutMs, force });
|
|
6882
6885
|
return result;
|
|
6883
6886
|
} catch (err) {
|
|
6884
6887
|
return {
|
|
@@ -6886,7 +6889,8 @@ var wechatPlugin = {
|
|
|
6886
6889
|
};
|
|
6887
6890
|
}
|
|
6888
6891
|
},
|
|
6889
|
-
logoutAccount: async ({
|
|
6892
|
+
logoutAccount: async ({ accountId }) => {
|
|
6893
|
+
const cfg = getWeChatRuntime().config.loadConfig();
|
|
6890
6894
|
const account = resolveWeChatAccount(
|
|
6891
6895
|
cfg,
|
|
6892
6896
|
accountId ?? void 0
|
|
@@ -6901,7 +6905,7 @@ var wechatPlugin = {
|
|
|
6901
6905
|
}
|
|
6902
6906
|
},
|
|
6903
6907
|
loginWithQrWait: async ({ accountId, timeoutMs }) => {
|
|
6904
|
-
const result = await loginWait(accountId, { timeoutMs });
|
|
6908
|
+
const result = await loginWait(accountId ?? DEFAULT_ACCOUNT_ID2, { timeoutMs });
|
|
6905
6909
|
return result;
|
|
6906
6910
|
}
|
|
6907
6911
|
},
|
|
@@ -6985,11 +6989,11 @@ Error: ${event.message}`);
|
|
|
6985
6989
|
collectStatusIssues: collectWeChatStatusIssues
|
|
6986
6990
|
},
|
|
6987
6991
|
// ---- Agent tools adapter ----
|
|
6988
|
-
agentTools: ({ cfg }) => {
|
|
6992
|
+
agentTools: (({ cfg }) => {
|
|
6989
6993
|
const account = resolveWeChatAccount(cfg);
|
|
6990
6994
|
if (!account?.serverUrl) return [];
|
|
6991
6995
|
return [createWeChatLoginTool(account)];
|
|
6992
|
-
},
|
|
6996
|
+
}),
|
|
6993
6997
|
// ---- Directory adapter ----
|
|
6994
6998
|
directory: {
|
|
6995
6999
|
self: async ({ cfg }) => {
|
package/package.json
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agent-wechat/wechat",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
7
7
|
"openclaw.plugin.json"
|
|
8
8
|
],
|
|
9
9
|
"devDependencies": {
|
|
10
|
+
"@types/node": "^22",
|
|
10
11
|
"esbuild": "^0.25.0",
|
|
12
|
+
"openclaw": "^2026.2.22",
|
|
13
|
+
"typescript": "^5.4.5",
|
|
11
14
|
"@agent-wechat/shared": "0.1.0"
|
|
12
15
|
},
|
|
13
16
|
"openclaw": {
|
|
@@ -37,6 +40,7 @@
|
|
|
37
40
|
"directory": "packages/openclaw-extension"
|
|
38
41
|
},
|
|
39
42
|
"scripts": {
|
|
40
|
-
"build": "esbuild index.ts --bundle --format=esm --platform=node --outfile=dist/index.js --external:openclaw"
|
|
43
|
+
"build": "esbuild index.ts --bundle --format=esm --platform=node --outfile=dist/index.js --external:openclaw",
|
|
44
|
+
"typecheck": "tsc --noEmit"
|
|
41
45
|
}
|
|
42
46
|
}
|