























@@ -1,7 +1,8 @@
11import { beforeEach, describe, expect, it, vi } from "vitest";
223-const { callGatewayMock } = vi.hoisted(() => ({
3+const { callGatewayMock, extractDeliveryInfoMock } = vi.hoisted(() => ({
44callGatewayMock: vi.fn(),
5+extractDeliveryInfoMock: vi.fn(),
56}));
6778vi.mock("../agent-scope.js", async () => {
@@ -12,6 +13,10 @@ vi.mock("../agent-scope.js", async () => {
1213};
1314});
141516+vi.mock("../../config/sessions/delivery-info.js", () => ({
17+extractDeliveryInfo: extractDeliveryInfoMock,
18+}));
19+1520import { buildAgentPeerSessionKey } from "../../routing/session-key.js";
1621import { createCronTool } from "./cron-tool.js";
1722@@ -164,6 +169,8 @@ describe("cron tool", () => {
164169beforeEach(() => {
165170callGatewayMock.mockClear();
166171callGatewayMock.mockResolvedValue({ ok: true });
172+extractDeliveryInfoMock.mockReset();
173+extractDeliveryInfoMock.mockReturnValue({ deliveryContext: undefined, threadId: undefined });
167174});
168175169176it("marks cron as owner-only", () => {
@@ -721,89 +728,56 @@ describe("cron tool", () => {
721728expect(call.params?.agentId).toBeNull();
722729});
723730724-it("infers delivery from threaded session keys", async () => {
725-expect(
726-await executeAddAndReadDelivery({
727-callId: "call-thread",
728-agentSessionKey: "agent:main:slack:channel:general:thread:1699999999.0001",
729-}),
730-).toEqual({
731-mode: "announce",
732-channel: "slack",
733-to: "general",
731+it("does not infer delivery from raw session-key fragments without delivery context", async () => {
732+const slackDelivery = await executeAddAndReadDelivery({
733+callId: "call-thread",
734+agentSessionKey: "agent:main:slack:channel:general:thread:1699999999.0001",
734735});
735-});
736-737-it("preserves telegram forum topics when inferring delivery", async () => {
738-expect(
739-await executeAddAndReadDelivery({
740-callId: "call-telegram-topic",
741-agentSessionKey: "agent:main:telegram:group:-1001234567890:topic:99",
742-}),
743-).toEqual({
744-mode: "announce",
745-channel: "telegram",
746-to: "-1001234567890:topic:99",
736+const telegramDelivery = await executeAddAndReadDelivery({
737+callId: "call-telegram-topic",
738+agentSessionKey: "agent:main:telegram:group:-1001234567890:topic:99",
747739});
748-});
749740750-it("preserves telegram direct-chat thread ids when inferring delivery", async () => {
751-expect(
752-await executeAddAndReadDelivery({
753-callId: "call-telegram-direct-thread",
754-agentSessionKey: "agent:main:telegram:direct:123456789:thread:123456789:99",
755-}),
756-).toEqual({
757-mode: "announce",
758-channel: "telegram",
759-to: "123456789",
760-threadId: "99",
761-});
741+expect(slackDelivery?.channel).toBeUndefined();
742+expect(slackDelivery?.to).toBeUndefined();
743+expect(telegramDelivery?.channel).toBeUndefined();
744+expect(telegramDelivery?.to).toBeUndefined();
762745});
763746764-it("preserves telegram account ids with direct-chat thread inference", async () => {
765-expect(
766-await executeAddAndReadDelivery({
767-callId: "call-telegram-account-direct-thread",
768-agentSessionKey: "agent:main:telegram:bot-a:direct:123456789:thread:123456789:99",
769-}),
770-).toEqual({
771-mode: "announce",
772-channel: "telegram",
773-to: "123456789",
774-accountId: "bot-a",
775-threadId: "99",
747+it("uses stored delivery context when current context is unavailable", async () => {
748+extractDeliveryInfoMock.mockReturnValueOnce({
749+deliveryContext: {
750+channel: "matrix",
751+to: "room:!AbCdEf1234567890:example.org",
752+accountId: "bot-a",
753+threadId: "$RootEvent:Example.Org",
754+},
755+threadId: undefined,
776756});
777-});
778757779-it("preserves legacy telegram dm thread ids when inferring delivery", async () => {
780758expect(
781759await executeAddAndReadDelivery({
782-callId: "call-telegram-dm-thread",
783-agentSessionKey: "agent:main:telegram:dm:123456789:thread:123456789:99",
760+callId: "call-stored-context",
761+agentSessionKey: "agent:main:matrix:channel:!abcdef1234567890:example.org",
784762}),
785763).toEqual({
786764mode: "announce",
787-channel: "telegram",
788-to: "123456789",
789-threadId: "99",
765+channel: "matrix",
766+to: "room:!AbCdEf1234567890:example.org",
767+accountId: "bot-a",
768+threadId: "$RootEvent:Example.Org",
790769});
791770});
792771793-it("drops mismatched telegram direct-chat thread ids when inferring delivery", async () => {
794-expect(
795-await executeAddAndReadDelivery({
796-callId: "call-telegram-mismatched-direct-thread",
797-agentSessionKey: "agent:main:telegram:direct:123456789:thread:987654321:99",
798-}),
799-).toEqual({
800-mode: "announce",
801-channel: "telegram",
802-to: "123456789",
772+it("prefers current delivery context over stored session context", async () => {
773+extractDeliveryInfoMock.mockReturnValueOnce({
774+deliveryContext: {
775+channel: "matrix",
776+to: "!stored:example.org",
777+},
778+threadId: undefined,
803779});
804-});
805780806-it("prefers current delivery context over lowercased session-key targets", async () => {
807781expect(
808782await executeAddAndReadDelivery({
809783callId: "call-current-context",
@@ -825,12 +799,8 @@ describe("cron tool", () => {
825799});
826800827801it("does not surface lowercased LINE recipients when current delivery context is unavailable (#81628)", async () => {
828-// Reproduces openclaw/openclaw#81628. LINE chat IDs are case-sensitive — push
829-// requires capital C/U/R; lowercased recipients return HTTP 400. The runtime
830-// already lowercases LINE peer IDs when canonicalizing the session key, and
831-// when the delivery-recovery / post-reply-token-expiry push path is missing
832-// currentDeliveryContext, inferDeliveryFromSessionKey lifts the lowercased
833-// fragment straight into delivery.to.
802+// LINE chat IDs are case-sensitive; without current/persisted deliveryContext,
803+// cron must not rebuild delivery.to from the lowercased session-key fragment.
834804const sessionKey = buildAgentPeerSessionKey({
835805agentId: "main",
836806channel: "line",
@@ -842,9 +812,7 @@ describe("cron tool", () => {
842812const delivery = await executeAddAndReadDelivery({
843813callId: "call-line-group-no-context-81628",
844814agentSessionKey: sessionKey,
845-// Intentionally no currentDeliveryContext — emulates the delivery-recovery
846-// boundary that reloads queued entries from disk after the reply token has
847-// expired.
815+// Intentionally no currentDeliveryContext.
848816});
849817850818expect(delivery?.to).toBeUndefined();
@@ -990,7 +958,15 @@ describe("cron tool", () => {
990958});
991959});
992960993-it("falls back to session-key inference when current context has no target", async () => {
961+it("falls back to stored delivery context when current context has no target", async () => {
962+extractDeliveryInfoMock.mockReturnValueOnce({
963+deliveryContext: {
964+channel: "telegram",
965+to: "-1001234567890",
966+},
967+threadId: "99",
968+});
969+994970expect(
995971await executeAddAndReadDelivery({
996972callId: "call-empty-current-context",
@@ -1003,7 +979,8 @@ describe("cron tool", () => {
1003979).toEqual({
1004980mode: "announce",
1005981channel: "telegram",
1006-to: "-1001234567890:topic:99",
982+to: "-1001234567890",
983+threadId: "99",
1007984});
1008985});
1009986@@ -1022,6 +999,13 @@ describe("cron tool", () => {
1022999});
1023100010241001it("infers delivery when delivery is null", async () => {
1002+extractDeliveryInfoMock.mockReturnValueOnce({
1003+deliveryContext: {
1004+to: "alice",
1005+},
1006+threadId: undefined,
1007+});
1008+10251009expect(
10261010await executeAddAndReadDelivery({
10271011callId: "call-null-delivery",
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。