
























@@ -30,6 +30,13 @@ vi.mock("../../auto-reply/reply/reply-media-paths.runtime.js", () => ({
3030type NormalizeParams = Parameters<typeof normalizeAgentCommandReplyPayloads>[0];
3131type RunResult = NormalizeParams["result"];
3232type DeliverParams = Parameters<typeof deliverAgentCommandResult>[0];
33+type TextPayloadLike = { text?: unknown };
34+type MediaNormalizerOptions = {
35+sessionKey?: unknown;
36+agentId?: unknown;
37+workspaceDir?: unknown;
38+messageProvider?: unknown;
39+};
33403441const slackOutboundForTest: ChannelOutboundAdapter = {
3542deliveryMode: "direct",
@@ -66,6 +73,38 @@ function createResult(overrides: Partial<RunResult> = {}): RunResult {
6673} as RunResult;
6774}
687576+function expectTextPayload(payload: TextPayloadLike | undefined, text: string): void {
77+expect(payload?.text).toBe(text);
78+}
79+80+function requirePayload(payloads: readonly ReplyPayload[], index: number): ReplyPayload {
81+const payload = payloads.at(index);
82+if (!payload) {
83+throw new Error(`expected payload at index ${index}`);
84+}
85+return payload;
86+}
87+88+function latestNormalizerOptions(): MediaNormalizerOptions {
89+const options = createReplyMediaPathNormalizerMock.mock.calls.at(-1)?.[0];
90+if (!options || typeof options !== "object") {
91+throw new Error("expected media normalizer options");
92+}
93+return options as MediaNormalizerOptions;
94+}
95+96+function latestOutboundDeliveryArgs(): {
97+payloads: ReplyPayload[];
98+bestEffort?: boolean;
99+queuePolicy?: string;
100+} {
101+const args = deliverOutboundPayloadsMock.mock.calls.at(-1)?.[0];
102+if (!args || typeof args !== "object") {
103+throw new Error("expected outbound delivery arguments");
104+}
105+return args as { payloads: ReplyPayload[]; bestEffort?: boolean; queuePolicy?: string };
106+}
107+69108async function deliverMediaReplyForTest(outboundSession: DeliverParams["outboundSession"]) {
70109const runtime = { log: vi.fn(), error: vi.fn() };
71110return await deliverAgentCommandResult({
@@ -114,11 +153,8 @@ describe("normalizeAgentCommandReplyPayloads", () => {
114153result: createResult(),
115154});
116155117-expect(normalized).toMatchObject([
118-{
119-text: "Choose [[slack_buttons: Retry:retry]]",
120-},
121-]);
156+expect(normalized).toHaveLength(1);
157+expectTextPayload(normalized[0], "Choose [[slack_buttons: Retry:retry]]");
122158});
123159124160it("renders response prefix templates with the selected runtime model", () => {
@@ -144,11 +180,8 @@ describe("normalizeAgentCommandReplyPayloads", () => {
144180}),
145181});
146182147-expect(normalized).toMatchObject([
148-{
149-text: "[openai-codex/gpt-5.4] Ready.",
150-},
151-]);
183+expect(normalized).toHaveLength(1);
184+expectTextPayload(normalized[0], "[openai-codex/gpt-5.4] Ready.");
152185});
153186154187it("keeps Slack options text intact for local preview when delivery is disabled", async () => {
@@ -178,7 +211,8 @@ describe("normalizeAgentCommandReplyPayloads", () => {
178211179212expect(runtime.log).toHaveBeenCalledTimes(1);
180213expect(runtime.log).toHaveBeenCalledWith("Options: on, off.");
181-expect(delivered.payloads).toMatchObject([{ text: "Options: on, off." }]);
214+expect(delivered.payloads).toHaveLength(1);
215+expectTextPayload(delivered.payloads[0], "Options: on, off.");
182216});
183217184218it("normalizes reply-media paths before outbound delivery", async () => {
@@ -197,23 +231,19 @@ describe("normalizeAgentCommandReplyPayloads", () => {
197231agentId: "tester",
198232} as never);
199233200-expect(createReplyMediaPathNormalizerMock).toHaveBeenCalledWith(
201-expect.objectContaining({
202-sessionKey: "agent:tester:slack:direct:alice",
203-agentId: "tester",
204-workspaceDir: "/tmp/agent-workspace",
205-messageProvider: "slack",
206-}),
207-);
208-expect(normalizerFn).toHaveBeenCalledWith(
209-expect.objectContaining({ mediaUrls: ["./out/photo.png"] }),
210-);
234+const normalizerOptions = latestNormalizerOptions();
235+expect(normalizerOptions.sessionKey).toBe("agent:tester:slack:direct:alice");
236+expect(normalizerOptions.agentId).toBe("tester");
237+expect(normalizerOptions.workspaceDir).toBe("/tmp/agent-workspace");
238+expect(normalizerOptions.messageProvider).toBe("slack");
239+240+const normalizedInput = normalizerFn.mock.calls.at(0)?.[0];
241+expect(normalizedInput?.mediaUrls).toStrictEqual(["./out/photo.png"]);
211242expect(deliverOutboundPayloadsMock).toHaveBeenCalledTimes(1);
212-const [firstCallArg] = deliverOutboundPayloadsMock.mock.calls[0] ?? [];
213-const deliverArgs = firstCallArg as { payloads: ReplyPayload[] } | undefined;
214-expect(deliverArgs?.payloads[0]).toMatchObject({
215-mediaUrls: ["/tmp/agent-workspace/out/photo.png"],
216-});
243+const deliverArgs = latestOutboundDeliveryArgs();
244+expect(requirePayload(deliverArgs.payloads, 0).mediaUrls).toStrictEqual([
245+"/tmp/agent-workspace/out/photo.png",
246+]);
217247});
218248219249it("reports successful requested delivery", async () => {
@@ -288,12 +318,9 @@ describe("normalizeAgentCommandReplyPayloads", () => {
288318289319expect(delivered.deliverySucceeded).toBe(false);
290320expect(runtime.error).toHaveBeenCalledWith(expect.stringContaining("send failed"));
291-expect(deliverOutboundPayloadsMock).toHaveBeenCalledWith(
292-expect.objectContaining({
293-bestEffort: true,
294-queuePolicy: "best_effort",
295-}),
296-);
321+const deliverArgs = latestOutboundDeliveryArgs();
322+expect(deliverArgs.bestEffort).toBe(true);
323+expect(deliverArgs.queuePolicy).toBe("best_effort");
297324});
298325299326it("threads agentId into the normalizer when sessionKey is unresolved", async () => {
@@ -302,13 +329,10 @@ describe("normalizeAgentCommandReplyPayloads", () => {
302329303330await deliverMediaReplyForTest({ agentId: "tester" } as never);
304331305-expect(createReplyMediaPathNormalizerMock).toHaveBeenCalledWith(
306-expect.objectContaining({
307-agentId: "tester",
308-sessionKey: undefined,
309-workspaceDir: "/tmp/agent-workspace",
310-}),
311-);
332+const normalizerOptions = latestNormalizerOptions();
333+expect(normalizerOptions.agentId).toBe("tester");
334+expect(normalizerOptions.sessionKey).toBeUndefined();
335+expect(normalizerOptions.workspaceDir).toBe("/tmp/agent-workspace");
312336});
313337314338it("keeps LINE directive-only replies intact for local preview when delivery is disabled", async () => {
@@ -338,11 +362,11 @@ describe("normalizeAgentCommandReplyPayloads", () => {
338362expect(runtime.log).toHaveBeenCalledWith(
339363"[[buttons: Release menu | Choose an action | Retry:retry, Ignore:ignore]]",
340364);
341-expect(delivered.payloads).toMatchObject([
342- {
343- text: "[[buttons: Release menu | Choose an action | Retry:retry, Ignore:ignore]]",
344-},
345-]);
365+expect(delivered.payloads).toHaveLength(1);
366+expectTextPayload(
367+delivered.payloads[0],
368+"[[buttons: Release menu | Choose an action | Retry:retry, Ignore:ignore]]",
369+);
346370});
347371348372it("merges result metadata overrides into JSON output and returned results", async () => {
@@ -382,10 +406,8 @@ describe("normalizeAgentCommandReplyPayloads", () => {
382406},
3834072,
384408);
385-expect(delivered.meta).toMatchObject({
386-durationMs: 1,
387-transport: "embedded",
388-fallbackFrom: "gateway",
389-});
409+expect(delivered.meta.durationMs).toBe(1);
410+expect(delivered.meta.transport).toBe("embedded");
411+expect(delivered.meta.fallbackFrom).toBe("gateway");
390412});
391413});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。