@laburen/openclaw-plugin-whatsapp-api 0.5.0 → 0.6.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/index.js +99 -7
- package/openclaw.plugin.json +8 -0
- package/package.json +1 -1
package/index.js
CHANGED
|
@@ -1126,7 +1126,7 @@ async function handleWhatsAppApiWebhook(params) {
|
|
|
1126
1126
|
//#endregion
|
|
1127
1127
|
//#region src/channel/plugin.ts
|
|
1128
1128
|
const CHANNEL_ID = "whatsapp-api";
|
|
1129
|
-
const log$
|
|
1129
|
+
const log$4 = waLogger("channel");
|
|
1130
1130
|
const DEFAULT_ACCOUNT_ID = "default";
|
|
1131
1131
|
/**
|
|
1132
1132
|
* Resolves when `signal` aborts, or never if `signal` is undefined.
|
|
@@ -1195,7 +1195,7 @@ async function dispatchInboundToAgent(params) {
|
|
|
1195
1195
|
const mediaAttachment = await downloadInboundMediaAttachment({
|
|
1196
1196
|
account,
|
|
1197
1197
|
message,
|
|
1198
|
-
log: { warn: (msg) => log$
|
|
1198
|
+
log: { warn: (msg) => log$4.warn(msg) }
|
|
1199
1199
|
});
|
|
1200
1200
|
const replyApi = rt.channel.reply;
|
|
1201
1201
|
const ctxPayload = replyApi.finalizeInboundContext({
|
|
@@ -1226,7 +1226,7 @@ async function dispatchInboundToAgent(params) {
|
|
|
1226
1226
|
sendWhatsAppApiReadMark({
|
|
1227
1227
|
messageId: message.messageId,
|
|
1228
1228
|
account
|
|
1229
|
-
}).catch((err) => log$
|
|
1229
|
+
}).catch((err) => log$4.warn("failed to mark read", {
|
|
1230
1230
|
error: String(err),
|
|
1231
1231
|
messageId: message.messageId
|
|
1232
1232
|
}));
|
|
@@ -1248,7 +1248,7 @@ async function dispatchInboundToAgent(params) {
|
|
|
1248
1248
|
account
|
|
1249
1249
|
});
|
|
1250
1250
|
},
|
|
1251
|
-
onStartError: (err) => log$
|
|
1251
|
+
onStartError: (err) => log$4.warn("failed to start typing", { error: String(err) })
|
|
1252
1252
|
},
|
|
1253
1253
|
dispatcherOptions: {
|
|
1254
1254
|
deliver: async (payload) => {
|
|
@@ -1259,17 +1259,17 @@ async function dispatchInboundToAgent(params) {
|
|
|
1259
1259
|
account
|
|
1260
1260
|
});
|
|
1261
1261
|
if (sent.length === 0) {
|
|
1262
|
-
log$
|
|
1262
|
+
log$4.info("skipping outbound: reply payload empty", { messageId: message.messageId });
|
|
1263
1263
|
return;
|
|
1264
1264
|
}
|
|
1265
|
-
log$
|
|
1265
|
+
log$4.info(`sent ${sent.length} outbound message(s)`, {
|
|
1266
1266
|
to: message.from,
|
|
1267
1267
|
messageId: message.messageId
|
|
1268
1268
|
});
|
|
1269
1269
|
onOutbound?.();
|
|
1270
1270
|
},
|
|
1271
1271
|
onError: (err, info) => {
|
|
1272
|
-
log$
|
|
1272
|
+
log$4.error(`${info?.kind ?? "reply"} dispatch failed`, {
|
|
1273
1273
|
accountId,
|
|
1274
1274
|
messageId: message.messageId,
|
|
1275
1275
|
error: String(err)
|
|
@@ -1419,6 +1419,97 @@ function createWhatsAppApiChannel(api) {
|
|
|
1419
1419
|
};
|
|
1420
1420
|
}
|
|
1421
1421
|
//#endregion
|
|
1422
|
+
//#region src/hooks/llm-output/handlers/forward-usage.ts
|
|
1423
|
+
/**
|
|
1424
|
+
* SPDX-License-Identifier: MIT
|
|
1425
|
+
*
|
|
1426
|
+
* Forwards LLM token usage from the `llm_output` hook to a configured HTTP endpoint.
|
|
1427
|
+
*/
|
|
1428
|
+
const log$3 = waLogger("llm-output/forward-usage");
|
|
1429
|
+
/** Plugin extension config keys (see `openclaw.plugin.json`). */
|
|
1430
|
+
const LABUREN_WEB_APP_CONFIG_KEY = "LABUREN_WEB_APP_URL";
|
|
1431
|
+
const USER_PHONE_CONFIG_KEY = "userPhoneNumber";
|
|
1432
|
+
const USAGE_PATH = "/api/usage";
|
|
1433
|
+
const USAGE_FEATURE = "openclaw_run";
|
|
1434
|
+
const POST_TIMEOUT_MS = 3e3;
|
|
1435
|
+
function resolveUsageIngestUrl() {
|
|
1436
|
+
let baseRaw;
|
|
1437
|
+
try {
|
|
1438
|
+
baseRaw = getPluginApi().pluginConfig?.[LABUREN_WEB_APP_CONFIG_KEY];
|
|
1439
|
+
} catch {
|
|
1440
|
+
return null;
|
|
1441
|
+
}
|
|
1442
|
+
if (typeof baseRaw !== "string") return null;
|
|
1443
|
+
const base = baseRaw.trim().replace(/\/+$/, "");
|
|
1444
|
+
if (!base) return null;
|
|
1445
|
+
try {
|
|
1446
|
+
return new URL(USAGE_PATH, base).href;
|
|
1447
|
+
} catch {
|
|
1448
|
+
log$3.warn(`usage-forwarder: invalid ${LABUREN_WEB_APP_CONFIG_KEY} base URL`);
|
|
1449
|
+
return null;
|
|
1450
|
+
}
|
|
1451
|
+
}
|
|
1452
|
+
function resolveUserPhoneNumber() {
|
|
1453
|
+
let raw;
|
|
1454
|
+
try {
|
|
1455
|
+
raw = getPluginApi().pluginConfig?.[USER_PHONE_CONFIG_KEY];
|
|
1456
|
+
} catch {
|
|
1457
|
+
return null;
|
|
1458
|
+
}
|
|
1459
|
+
if (typeof raw !== "string") return null;
|
|
1460
|
+
const phone = raw.trim();
|
|
1461
|
+
return phone.length > 0 ? phone : null;
|
|
1462
|
+
}
|
|
1463
|
+
async function handleForwardLlmUsage(event, ctx) {
|
|
1464
|
+
const usage = event.usage;
|
|
1465
|
+
if (!usage) return;
|
|
1466
|
+
const endpoint = resolveUsageIngestUrl();
|
|
1467
|
+
if (!endpoint) return;
|
|
1468
|
+
const userPhoneNumber = resolveUserPhoneNumber();
|
|
1469
|
+
if (!userPhoneNumber) return;
|
|
1470
|
+
const input = usage.input ?? 0;
|
|
1471
|
+
const output = usage.output ?? 0;
|
|
1472
|
+
const cacheRead = usage.cacheRead ?? 0;
|
|
1473
|
+
const cacheWrite = usage.cacheWrite ?? 0;
|
|
1474
|
+
const total = usage.total ?? input + output + cacheRead + cacheWrite;
|
|
1475
|
+
const body = {
|
|
1476
|
+
feature: USAGE_FEATURE,
|
|
1477
|
+
runId: event.runId,
|
|
1478
|
+
sessionId: event.sessionId,
|
|
1479
|
+
userPhoneNumber,
|
|
1480
|
+
sessionKey: ctx.sessionKey,
|
|
1481
|
+
agentId: ctx.agentId,
|
|
1482
|
+
provider: event.provider,
|
|
1483
|
+
model: event.model,
|
|
1484
|
+
usage: {
|
|
1485
|
+
input,
|
|
1486
|
+
output,
|
|
1487
|
+
cacheRead,
|
|
1488
|
+
cacheWrite,
|
|
1489
|
+
total
|
|
1490
|
+
},
|
|
1491
|
+
capturedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1492
|
+
};
|
|
1493
|
+
try {
|
|
1494
|
+
const res = await fetch(endpoint, {
|
|
1495
|
+
method: "POST",
|
|
1496
|
+
headers: { "Content-Type": "application/json" },
|
|
1497
|
+
body: JSON.stringify(body),
|
|
1498
|
+
signal: AbortSignal.timeout(POST_TIMEOUT_MS)
|
|
1499
|
+
});
|
|
1500
|
+
if (!res.ok) log$3.warn(`usage-forwarder: HTTP ${res.status}`);
|
|
1501
|
+
} catch (err) {
|
|
1502
|
+
log$3.warn(`usage-forwarder: request failed (${String(err)})`);
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
//#endregion
|
|
1506
|
+
//#region src/hooks/llm-output/register.ts
|
|
1507
|
+
function registerLlmOutputHook(api) {
|
|
1508
|
+
api.on("llm_output", async (event, ctx) => {
|
|
1509
|
+
await handleForwardLlmUsage(event, ctx);
|
|
1510
|
+
});
|
|
1511
|
+
}
|
|
1512
|
+
//#endregion
|
|
1422
1513
|
//#region src/plugin/plugin-state-dir.ts
|
|
1423
1514
|
/**
|
|
1424
1515
|
* SPDX-License-Identifier: MIT
|
|
@@ -1510,6 +1601,7 @@ function registerMessageReceivedHook(api) {
|
|
|
1510
1601
|
*/
|
|
1511
1602
|
function registerAllPluginHooks(api) {
|
|
1512
1603
|
registerMessageReceivedHook(api);
|
|
1604
|
+
registerLlmOutputHook(api);
|
|
1513
1605
|
}
|
|
1514
1606
|
//#endregion
|
|
1515
1607
|
//#region src/services/context-window-check/register.ts
|
package/openclaw.plugin.json
CHANGED
|
@@ -9,6 +9,14 @@
|
|
|
9
9
|
"type": "object",
|
|
10
10
|
"additionalProperties": false,
|
|
11
11
|
"properties": {
|
|
12
|
+
"LABUREN_WEB_APP_URL": {
|
|
13
|
+
"type": "string",
|
|
14
|
+
"description": "Laburen web app base URL (no trailing slash). LLM usage is POSTed to {base}/api/usage."
|
|
15
|
+
},
|
|
16
|
+
"userPhoneNumber": {
|
|
17
|
+
"type": "string",
|
|
18
|
+
"description": "WhatsApp user phone (E.164 or your normalised form). Sent on each usage POST so the backend can resolve the user."
|
|
19
|
+
},
|
|
12
20
|
"defaults": {
|
|
13
21
|
"type": "object",
|
|
14
22
|
"additionalProperties": false,
|