clawgram 2.4.0 → 2.4.2
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/channel.js +35 -14
- package/dist/helpers.js +19 -1
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/dist/channel.js
CHANGED
|
@@ -536,6 +536,10 @@ const createChannelPlugin = (runtimes) => {
|
|
|
536
536
|
channel: "clawgram",
|
|
537
537
|
accountId: route.accountId ?? accountId,
|
|
538
538
|
});
|
|
539
|
+
// Boundary for the transcript fallback below: only replies
|
|
540
|
+
// written after this instant may be salvaged. Same clock as
|
|
541
|
+
// the transcript writer — both live in this process.
|
|
542
|
+
const dispatchStartedAt = Date.now();
|
|
539
543
|
const dispatchResult = await dispatchBase.dispatchReplyWithBufferedBlockDispatcher({
|
|
540
544
|
ctx: ctxPayload,
|
|
541
545
|
cfg,
|
|
@@ -604,7 +608,7 @@ const createChannelPlugin = (runtimes) => {
|
|
|
604
608
|
(dispatchCounts.block ?? 0) === 0 &&
|
|
605
609
|
(dispatchCounts.final ?? 0) === 0;
|
|
606
610
|
if (nothingDelivered) {
|
|
607
|
-
const fallbackText = (0, helpers_1.readLatestAssistantFallbackFromTranscript)(route.sessionKey, storePath);
|
|
611
|
+
const fallbackText = (0, helpers_1.readLatestAssistantFallbackFromTranscript)(route.sessionKey, storePath, dispatchStartedAt);
|
|
608
612
|
// A suppressed silent reply legitimately delivers nothing, so
|
|
609
613
|
// this fallback fires right after it. Without the same check
|
|
610
614
|
// the token would be read back from the transcript and sent.
|
|
@@ -1288,21 +1292,38 @@ const createChannelPlugin = (runtimes) => {
|
|
|
1288
1292
|
},
|
|
1289
1293
|
},
|
|
1290
1294
|
outbound: {
|
|
1295
|
+
// Core's agent-delivery path (`--deliver`, subagent announces) calls this
|
|
1296
|
+
// with `to: undefined` whenever a delivery has no explicit target and the
|
|
1297
|
+
// session route yielded none — and it does not catch a rejection from
|
|
1298
|
+
// here. A throw is therefore an unhandled rejection that takes down the
|
|
1299
|
+
// entire gateway process, which is exactly what happened on 2026-08-06
|
|
1300
|
+
// (systemd: Main process exited, status=1). The contract, read from
|
|
1301
|
+
// core's resolveOutboundTargetWithPlugin: answer { ok: false, error } for
|
|
1302
|
+
// anything unresolvable. Never throw.
|
|
1291
1303
|
async resolveTarget(ctx) {
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1304
|
+
try {
|
|
1305
|
+
const raw = typeof ctx.to === "string" ? ctx.to.trim() : "";
|
|
1306
|
+
actionLog.info("clawgram outbound resolveTarget", {
|
|
1307
|
+
accountId: ctx.accountId,
|
|
1308
|
+
rawTo: raw || null,
|
|
1309
|
+
});
|
|
1310
|
+
if (!raw) {
|
|
1311
|
+
return { ok: false, error: "clawgram: no delivery target — pass `to` or use a session with a bound chat" };
|
|
1312
|
+
}
|
|
1313
|
+
const gram = runtimes.get(ctx.accountId);
|
|
1314
|
+
if (!gram) {
|
|
1315
|
+
return { ok: false, error: `clawgram: runtime not found for account ${ctx.accountId}` };
|
|
1316
|
+
}
|
|
1317
|
+
const targetKind = (0, helpers_1.inferOutboundTargetKind)(raw);
|
|
1318
|
+
const target = (0, helpers_1.normalizeOutboundTarget)(raw);
|
|
1319
|
+
return {
|
|
1320
|
+
ok: true,
|
|
1321
|
+
to: (await gram.resolvePeer(target, { kind: targetKind })).chatId ?? target,
|
|
1322
|
+
};
|
|
1323
|
+
}
|
|
1324
|
+
catch (err) {
|
|
1325
|
+
return { ok: false, error: `clawgram: target resolution failed: ${String(err)}` };
|
|
1299
1326
|
}
|
|
1300
|
-
const targetKind = (0, helpers_1.inferOutboundTargetKind)(ctx.to);
|
|
1301
|
-
const target = (0, helpers_1.normalizeOutboundTarget)(ctx.to);
|
|
1302
|
-
return {
|
|
1303
|
-
ok: true,
|
|
1304
|
-
to: (await gram.resolvePeer(target, { kind: targetKind })).chatId ?? target,
|
|
1305
|
-
};
|
|
1306
1327
|
},
|
|
1307
1328
|
async sendText(ctx) {
|
|
1308
1329
|
// Never log `text`: outbound bodies are private correspondence and the
|
package/dist/helpers.js
CHANGED
|
@@ -110,7 +110,17 @@ function resolveTranscriptPathFromStoreEntry(input) {
|
|
|
110
110
|
return undefined;
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
|
-
|
|
113
|
+
/**
|
|
114
|
+
* Salvages a reply that reached the transcript but not stdout.
|
|
115
|
+
*
|
|
116
|
+
* `notBeforeMs` is the start of the current dispatch. Only entries stamped at
|
|
117
|
+
* or after it count: on a turn that aborted with zero output, the newest
|
|
118
|
+
* assistant entry is by definition from an earlier turn, and re-sending it
|
|
119
|
+
* addresses an old answer to a new question (the 2026-08-06 duplicates,
|
|
120
|
+
* note 0054 in the control repo). An entry with no parseable timestamp cannot
|
|
121
|
+
* prove it is fresh, so it does not count either.
|
|
122
|
+
*/
|
|
123
|
+
function readLatestAssistantFallbackFromTranscript(sessionKey, storePath, notBeforeMs) {
|
|
114
124
|
if (!storePath?.trim()) {
|
|
115
125
|
return undefined;
|
|
116
126
|
}
|
|
@@ -135,6 +145,14 @@ function readLatestAssistantFallbackFromTranscript(sessionKey, storePath) {
|
|
|
135
145
|
if (entry?.type !== "message" || entry?.message?.role !== "assistant" || !Array.isArray(entry.message.content)) {
|
|
136
146
|
continue;
|
|
137
147
|
}
|
|
148
|
+
if (notBeforeMs !== undefined) {
|
|
149
|
+
const stamped = typeof entry.timestamp === "string" ? Date.parse(entry.timestamp) : NaN;
|
|
150
|
+
if (!Number.isFinite(stamped) || stamped < notBeforeMs) {
|
|
151
|
+
// Entries are appended in order; everything below this one is
|
|
152
|
+
// older still. Stop instead of walking further into the past.
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
138
156
|
const textPart = entry.message.content.find((part) => part?.type === "text" && typeof part.text === "string" && part.text.trim());
|
|
139
157
|
if (!textPart?.text) {
|
|
140
158
|
continue;
|
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "clawgram",
|
|
3
3
|
"name": "Clawgram",
|
|
4
4
|
"description": "Clawgram — personal Telegram (MTProto userbot) channel for OpenClaw. Your AI assistant reads and responds as you.",
|
|
5
|
-
"version": "2.4.
|
|
5
|
+
"version": "2.4.2",
|
|
6
6
|
"configSchema": {
|
|
7
7
|
"type": "object",
|
|
8
8
|
"additionalProperties": false,
|
package/package.json
CHANGED