mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-18 12:14:46 +00:00
fix(cron): refuse LINE session-key recipient fallback (#81628)
LINE chat ids are case-sensitive (push requires capital C/U/R) but the session key holds the peer id lowercased for canonical routing. When cron-tool runs without currentDeliveryContext (delivery-recovery, queue replay after reply-token expiry), inferDeliveryFromSessionKey was lifting the lowercased fragment straight into delivery.to, producing a value LINE rejects with HTTP 400 — the job retried five times silently and the dashboard reported "delivered" while the LINE group received nothing. Refuse the session-key fallback for channel === "line" so the missing target surfaces explicitly instead of scheduling an undeliverable job.
This commit is contained in:
@@ -12,6 +12,7 @@ vi.mock("../agent-scope.js", async () => {
|
||||
};
|
||||
});
|
||||
|
||||
import { buildAgentPeerSessionKey } from "../../routing/session-key.js";
|
||||
import { createCronTool } from "./cron-tool.js";
|
||||
|
||||
describe("cron tool", () => {
|
||||
@@ -823,6 +824,53 @@ describe("cron tool", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("does not surface lowercased LINE recipients when current delivery context is unavailable (#81628)", async () => {
|
||||
// Reproduces openclaw/openclaw#81628. LINE chat IDs are case-sensitive — push
|
||||
// requires capital C/U/R; lowercased recipients return HTTP 400. The runtime
|
||||
// already lowercases LINE peer IDs when canonicalizing the session key, and
|
||||
// when the delivery-recovery / post-reply-token-expiry push path is missing
|
||||
// currentDeliveryContext, inferDeliveryFromSessionKey lifts the lowercased
|
||||
// fragment straight into delivery.to.
|
||||
const sessionKey = buildAgentPeerSessionKey({
|
||||
agentId: "main",
|
||||
channel: "line",
|
||||
peerKind: "group",
|
||||
peerId: "Cabcdef0123456789abcdef0123456789",
|
||||
});
|
||||
expect(sessionKey).toBe("agent:main:line:group:cabcdef0123456789abcdef0123456789");
|
||||
|
||||
const delivery = await executeAddAndReadDelivery({
|
||||
callId: "call-line-group-no-context-81628",
|
||||
agentSessionKey: sessionKey,
|
||||
// Intentionally no currentDeliveryContext — emulates the delivery-recovery
|
||||
// boundary that reloads queued entries from disk after the reply token has
|
||||
// expired.
|
||||
});
|
||||
|
||||
expect(delivery?.to).toBeUndefined();
|
||||
});
|
||||
|
||||
it("does not surface lowercased LINE DM recipients with per-account-channel-peer scope (#81628)", async () => {
|
||||
const sessionKey = buildAgentPeerSessionKey({
|
||||
agentId: "main",
|
||||
channel: "line",
|
||||
peerKind: "direct",
|
||||
accountId: "primary",
|
||||
dmScope: "per-account-channel-peer",
|
||||
peerId: "Uabcdef0123456789abcdef0123456789",
|
||||
});
|
||||
expect(sessionKey).toBe(
|
||||
"agent:main:line:primary:direct:uabcdef0123456789abcdef0123456789",
|
||||
);
|
||||
|
||||
const delivery = await executeAddAndReadDelivery({
|
||||
callId: "call-line-direct-no-context-81628",
|
||||
agentSessionKey: sessionKey,
|
||||
});
|
||||
|
||||
expect(delivery?.to).toBeUndefined();
|
||||
});
|
||||
|
||||
it("does not let current delivery context override explicit delivery targets", async () => {
|
||||
expect(
|
||||
await executeAddAndReadDelivery({
|
||||
|
||||
@@ -581,6 +581,16 @@ function inferDeliveryFromSessionKey(agentSessionKey?: string): CronDelivery | n
|
||||
channel = normalizeOptionalLowercaseString(parts[0]) as CronMessageChannel | undefined;
|
||||
}
|
||||
|
||||
// LINE chat ids are case-sensitive (push requires capital C/U/R) but the
|
||||
// session key holds the peer id lowercased for canonical routing. Rebuilding
|
||||
// `to` from the session-key fragment would yield a value LINE rejects with
|
||||
// HTTP 400, so refuse the fallback for LINE and let the caller surface the
|
||||
// missing target instead of silently scheduling an undeliverable job.
|
||||
// openclaw/openclaw#81628
|
||||
if (channel === "line") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const marker = parts[markerIndex];
|
||||
const delivery: CronDelivery = { mode: "announce", to: peerId };
|
||||
if (channel) {
|
||||
|
||||
Reference in New Issue
Block a user