test: expand accountId delivery coverage
Co-authored-by: Adam Holt <adam91holt@users.noreply.github.com>
This commit is contained in:
@@ -191,4 +191,85 @@ describe("subagent announce formatting", () => {
|
|||||||
expect(call?.params?.to).toBe("+1555");
|
expect(call?.params?.to).toBe("+1555");
|
||||||
expect(call?.params?.accountId).toBe("kev");
|
expect(call?.params?.accountId).toBe("kev");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("uses requester accountId for direct announce when not queued", async () => {
|
||||||
|
const { runSubagentAnnounceFlow } = await import("./subagent-announce.js");
|
||||||
|
embeddedRunMock.isEmbeddedPiRunActive.mockReturnValue(false);
|
||||||
|
embeddedRunMock.isEmbeddedPiRunStreaming.mockReturnValue(false);
|
||||||
|
|
||||||
|
const didAnnounce = await runSubagentAnnounceFlow({
|
||||||
|
childSessionKey: "agent:main:subagent:test",
|
||||||
|
childRunId: "run-direct",
|
||||||
|
requesterSessionKey: "agent:main:main",
|
||||||
|
requesterChannel: "whatsapp",
|
||||||
|
requesterAccountId: "acct-123",
|
||||||
|
requesterDisplayKey: "main",
|
||||||
|
task: "do thing",
|
||||||
|
timeoutMs: 1000,
|
||||||
|
cleanup: "keep",
|
||||||
|
waitForCompletion: false,
|
||||||
|
startedAt: 10,
|
||||||
|
endedAt: 20,
|
||||||
|
outcome: { status: "ok" },
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(didAnnounce).toBe(true);
|
||||||
|
const call = agentSpy.mock.calls[0]?.[0] as { params?: Record<string, unknown> };
|
||||||
|
expect(call?.params?.channel).toBe("whatsapp");
|
||||||
|
expect(call?.params?.accountId).toBe("acct-123");
|
||||||
|
});
|
||||||
|
|
||||||
|
it("splits collect-mode announces when accountId differs", async () => {
|
||||||
|
const { runSubagentAnnounceFlow } = await import("./subagent-announce.js");
|
||||||
|
embeddedRunMock.isEmbeddedPiRunActive.mockReturnValue(true);
|
||||||
|
embeddedRunMock.isEmbeddedPiRunStreaming.mockReturnValue(false);
|
||||||
|
sessionStore = {
|
||||||
|
"agent:main:main": {
|
||||||
|
sessionId: "session-789",
|
||||||
|
lastChannel: "whatsapp",
|
||||||
|
lastTo: "+1555",
|
||||||
|
queueMode: "collect",
|
||||||
|
queueDebounceMs: 0,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
await runSubagentAnnounceFlow({
|
||||||
|
childSessionKey: "agent:main:subagent:test",
|
||||||
|
childRunId: "run-a",
|
||||||
|
requesterSessionKey: "main",
|
||||||
|
requesterAccountId: "acct-a",
|
||||||
|
requesterDisplayKey: "main",
|
||||||
|
task: "do thing",
|
||||||
|
timeoutMs: 1000,
|
||||||
|
cleanup: "keep",
|
||||||
|
waitForCompletion: false,
|
||||||
|
startedAt: 10,
|
||||||
|
endedAt: 20,
|
||||||
|
outcome: { status: "ok" },
|
||||||
|
});
|
||||||
|
|
||||||
|
await runSubagentAnnounceFlow({
|
||||||
|
childSessionKey: "agent:main:subagent:test",
|
||||||
|
childRunId: "run-b",
|
||||||
|
requesterSessionKey: "main",
|
||||||
|
requesterAccountId: "acct-b",
|
||||||
|
requesterDisplayKey: "main",
|
||||||
|
task: "do thing",
|
||||||
|
timeoutMs: 1000,
|
||||||
|
cleanup: "keep",
|
||||||
|
waitForCompletion: false,
|
||||||
|
startedAt: 10,
|
||||||
|
endedAt: 20,
|
||||||
|
outcome: { status: "ok" },
|
||||||
|
});
|
||||||
|
|
||||||
|
await new Promise((r) => setTimeout(r, 5));
|
||||||
|
|
||||||
|
const accountIds = agentSpy.mock.calls.map(
|
||||||
|
(call) => (call[0] as { params?: Record<string, unknown> }).params?.accountId,
|
||||||
|
);
|
||||||
|
expect(accountIds).toContain("acct-a");
|
||||||
|
expect(accountIds).toContain("acct-b");
|
||||||
|
expect(agentSpy).toHaveBeenCalledTimes(2);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -351,6 +351,19 @@ function loadRequesterSessionEntry(requesterSessionKey: string) {
|
|||||||
return { cfg, entry, canonicalKey };
|
return { cfg, entry, canonicalKey };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function resolveAnnounceOrigin(params: {
|
||||||
|
channel?: string;
|
||||||
|
to?: string;
|
||||||
|
accountId?: string;
|
||||||
|
fallbackAccountId?: string;
|
||||||
|
}) {
|
||||||
|
return normalizeDeliveryContext({
|
||||||
|
channel: params.channel,
|
||||||
|
to: params.to,
|
||||||
|
accountId: params.accountId ?? params.fallbackAccountId,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function maybeQueueSubagentAnnounce(params: {
|
async function maybeQueueSubagentAnnounce(params: {
|
||||||
requesterSessionKey: string;
|
requesterSessionKey: string;
|
||||||
triggerMessage: string;
|
triggerMessage: string;
|
||||||
@@ -381,10 +394,11 @@ async function maybeQueueSubagentAnnounce(params: {
|
|||||||
queueSettings.mode === "steer-backlog" ||
|
queueSettings.mode === "steer-backlog" ||
|
||||||
queueSettings.mode === "interrupt";
|
queueSettings.mode === "interrupt";
|
||||||
if (isActive && (shouldFollowup || queueSettings.mode === "steer")) {
|
if (isActive && (shouldFollowup || queueSettings.mode === "steer")) {
|
||||||
const origin = normalizeDeliveryContext({
|
const origin = resolveAnnounceOrigin({
|
||||||
channel: entry?.lastChannel,
|
channel: entry?.lastChannel,
|
||||||
to: entry?.lastTo,
|
to: entry?.lastTo,
|
||||||
accountId: entry?.lastAccountId ?? params.requesterAccountId,
|
accountId: entry?.lastAccountId,
|
||||||
|
fallbackAccountId: params.requesterAccountId,
|
||||||
});
|
});
|
||||||
enqueueAnnounce(
|
enqueueAnnounce(
|
||||||
canonicalKey,
|
canonicalKey,
|
||||||
@@ -624,7 +638,7 @@ export async function runSubagentAnnounceFlow(params: {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Send to main agent - it will respond in its own voice
|
// Send to main agent - it will respond in its own voice
|
||||||
const directOrigin = normalizeDeliveryContext({
|
const directOrigin = resolveAnnounceOrigin({
|
||||||
channel: params.requesterChannel,
|
channel: params.requesterChannel,
|
||||||
accountId: params.requesterAccountId,
|
accountId: params.requesterAccountId,
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { describe, expect, it, vi } from "vitest";
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
import type { CliDeps } from "../cli/deps.js";
|
import type { CliDeps } from "../cli/deps.js";
|
||||||
import type { ClawdbotConfig } from "../config/config.js";
|
import type { ClawdbotConfig } from "../config/config.js";
|
||||||
@@ -25,6 +25,11 @@ vi.mock("../infra/outbound/targets.js", () => ({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
describe("deliverAgentCommandResult", () => {
|
describe("deliverAgentCommandResult", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
mocks.deliverOutboundPayloads.mockClear();
|
||||||
|
mocks.resolveOutboundTarget.mockClear();
|
||||||
|
});
|
||||||
|
|
||||||
it("prefers explicit accountId for outbound delivery", async () => {
|
it("prefers explicit accountId for outbound delivery", async () => {
|
||||||
const cfg = {} as ClawdbotConfig;
|
const cfg = {} as ClawdbotConfig;
|
||||||
const deps = {} as CliDeps;
|
const deps = {} as CliDeps;
|
||||||
@@ -61,4 +66,39 @@ describe("deliverAgentCommandResult", () => {
|
|||||||
expect.objectContaining({ accountId: "kev" }),
|
expect.objectContaining({ accountId: "kev" }),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("falls back to session accountId for implicit delivery", async () => {
|
||||||
|
const cfg = {} as ClawdbotConfig;
|
||||||
|
const deps = {} as CliDeps;
|
||||||
|
const runtime = {
|
||||||
|
log: vi.fn(),
|
||||||
|
error: vi.fn(),
|
||||||
|
} as unknown as RuntimeEnv;
|
||||||
|
const sessionEntry = {
|
||||||
|
lastAccountId: "legacy",
|
||||||
|
} as SessionEntry;
|
||||||
|
const result = {
|
||||||
|
payloads: [{ text: "hi" }],
|
||||||
|
meta: {},
|
||||||
|
};
|
||||||
|
|
||||||
|
const { deliverAgentCommandResult } = await import("./agent/delivery.js");
|
||||||
|
await deliverAgentCommandResult({
|
||||||
|
cfg,
|
||||||
|
deps,
|
||||||
|
runtime,
|
||||||
|
opts: {
|
||||||
|
message: "hello",
|
||||||
|
deliver: true,
|
||||||
|
channel: "whatsapp",
|
||||||
|
},
|
||||||
|
sessionEntry,
|
||||||
|
result,
|
||||||
|
payloads: result.payloads,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mocks.deliverOutboundPayloads).toHaveBeenCalledWith(
|
||||||
|
expect.objectContaining({ accountId: "legacy" }),
|
||||||
|
);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user