refactor: share subagent delivery context test helpers

This commit is contained in:
Vincent Koc
2026-06-02 04:20:02 +02:00
parent 883c0f1254
commit baade28397

View File

@@ -81,6 +81,14 @@ type StoredEntry = {
lastAccountId?: string;
};
type StoreEntries = Parameters<typeof writeSessionStore>[0]["entries"];
async function prepareSessionStore(entries: StoreEntries = {}): Promise<void> {
setRegistry(defaultRegistry);
testState.sessionStorePath = sessionStorePath;
await writeSessionStore({ entries });
}
function readStoredEntry(stored: Record<string, StoredEntry>, key: string): StoredEntry {
const entry = stored[key];
if (!entry) {
@@ -96,34 +104,50 @@ function readDeliveryContext(entry: StoredEntry): NonNullable<StoredEntry["deliv
return entry.deliveryContext;
}
async function readStoredSessionEntry(key: string): Promise<StoredEntry> {
const stored = JSON.parse(await fs.readFile(sessionStorePath, "utf-8")) as Record<
string,
StoredEntry
>;
return readStoredEntry(stored, key);
}
async function sendAgentRequest(params: Record<string, unknown>): Promise<void> {
const res = await rpcReq(ws, "agent", {
deliver: false,
...params,
});
expect(res.ok).toBe(true);
}
function expectDeliveryContextFields(entry: StoredEntry, expected: Record<string, unknown>): void {
const deliveryContext = readDeliveryContext(entry);
for (const [key, value] of Object.entries(expected)) {
expect(deliveryContext[key as keyof typeof deliveryContext]).toBe(value);
}
}
describe("subagent session deliveryContext from spawn request params", () => {
test("new subagent session inherits deliveryContext from request channel/to/threadId", async () => {
setRegistry(defaultRegistry);
testState.sessionStorePath = sessionStorePath;
await writeSessionStore({ entries: {} });
await prepareSessionStore();
const res = await rpcReq(ws, "agent", {
await sendAgentRequest({
message: "[Subagent Task]: analyze data",
sessionKey: "agent:main:subagent:test-delivery-ctx",
channel: "slack",
to: "channel:C0AF8TW48UQ",
accountId: "default",
threadId: "1774374945.091819",
deliver: false,
idempotencyKey: "idem-subagent-delivery-ctx-1",
});
expect(res.ok).toBe(true);
const stored = JSON.parse(await fs.readFile(sessionStorePath, "utf-8")) as Record<
string,
StoredEntry
>;
const entry = readStoredEntry(stored, "agent:main:subagent:test-delivery-ctx");
const deliveryContext = readDeliveryContext(entry);
expect(deliveryContext.channel).toBe("slack");
expect(deliveryContext.to).toBe("channel:C0AF8TW48UQ");
expect(deliveryContext.threadId).toBe("1774374945.091819");
expect(deliveryContext.accountId).toBe("default");
const entry = await readStoredSessionEntry("agent:main:subagent:test-delivery-ctx");
expectDeliveryContextFields(entry, {
channel: "slack",
to: "channel:C0AF8TW48UQ",
threadId: "1774374945.091819",
accountId: "default",
});
expect(entry.route).toEqual({
channel: "slack",
accountId: "default",
@@ -135,103 +159,84 @@ describe("subagent session deliveryContext from spawn request params", () => {
});
test("existing session deliveryContext is NOT overwritten by request params", async () => {
setRegistry(defaultRegistry);
testState.sessionStorePath = sessionStorePath;
await writeSessionStore({
entries: {
"agent:main:subagent:existing-ctx": {
sessionId: "sess-existing",
updatedAt: Date.now(),
deliveryContext: {
channel: "slack",
to: "user:U09U1LV7JDN",
accountId: "default",
threadId: "1771242986.529939",
},
lastChannel: "slack",
lastTo: "user:U09U1LV7JDN",
lastAccountId: "default",
lastThreadId: "1771242986.529939",
await prepareSessionStore({
"agent:main:subagent:existing-ctx": {
sessionId: "sess-existing",
updatedAt: Date.now(),
deliveryContext: {
channel: "slack",
to: "user:U09U1LV7JDN",
accountId: "default",
threadId: "1771242986.529939",
},
lastChannel: "slack",
lastTo: "user:U09U1LV7JDN",
lastAccountId: "default",
lastThreadId: "1771242986.529939",
},
});
const res = await rpcReq(ws, "agent", {
await sendAgentRequest({
message: "follow-up",
sessionKey: "agent:main:subagent:existing-ctx",
channel: "slack",
to: "channel:C0AF8TW48UQ",
threadId: "9999999999.000000",
deliver: false,
idempotencyKey: "idem-subagent-delivery-ctx-2",
});
expect(res.ok).toBe(true);
const stored = JSON.parse(await fs.readFile(sessionStorePath, "utf-8")) as Record<
string,
StoredEntry
>;
const entry = readStoredEntry(stored, "agent:main:subagent:existing-ctx");
const deliveryContext = readDeliveryContext(entry);
const entry = await readStoredSessionEntry("agent:main:subagent:existing-ctx");
// The ORIGINAL deliveryContext should be preserved (primary wins in merge).
expect(deliveryContext.to).toBe("user:U09U1LV7JDN");
expect(deliveryContext.threadId).toBe("1771242986.529939");
expectDeliveryContextFields(entry, {
to: "user:U09U1LV7JDN",
threadId: "1771242986.529939",
});
expect(entry.lastTo).toBe("user:U09U1LV7JDN");
});
test("existing session route metadata survives agent request delivery normalization", async () => {
setRegistry(defaultRegistry);
testState.sessionStorePath = sessionStorePath;
await writeSessionStore({
entries: {
"agent:main:subagent:existing-route-metadata": {
sessionId: "sess-existing-route",
updatedAt: Date.now(),
route: {
channel: "slack",
accountId: "default",
target: {
to: "channel:C0AF8TW48UQ",
rawTo: "slack://C0AF8TW48UQ",
chatType: "channel",
},
thread: {
id: "1771242986.529939",
kind: "thread",
source: "target",
},
},
deliveryContext: {
channel: "slack",
await prepareSessionStore({
"agent:main:subagent:existing-route-metadata": {
sessionId: "sess-existing-route",
updatedAt: Date.now(),
route: {
channel: "slack",
accountId: "default",
target: {
to: "channel:C0AF8TW48UQ",
accountId: "default",
threadId: "1771242986.529939",
rawTo: "slack://C0AF8TW48UQ",
chatType: "channel",
},
thread: {
id: "1771242986.529939",
kind: "thread",
source: "target",
},
lastChannel: "slack",
lastTo: "channel:C0AF8TW48UQ",
lastAccountId: "default",
lastThreadId: "1771242986.529939",
},
deliveryContext: {
channel: "slack",
to: "channel:C0AF8TW48UQ",
accountId: "default",
threadId: "1771242986.529939",
},
lastChannel: "slack",
lastTo: "channel:C0AF8TW48UQ",
lastAccountId: "default",
lastThreadId: "1771242986.529939",
},
});
const res = await rpcReq(ws, "agent", {
await sendAgentRequest({
message: "follow-up",
sessionKey: "agent:main:subagent:existing-route-metadata",
channel: "slack",
to: "channel:C0AF8TW48UQ",
accountId: "default",
threadId: "1771242986.529939",
deliver: false,
idempotencyKey: "idem-subagent-delivery-route-metadata",
});
expect(res.ok).toBe(true);
const stored = JSON.parse(await fs.readFile(sessionStorePath, "utf-8")) as Record<
string,
StoredEntry
>;
const entry = readStoredEntry(stored, "agent:main:subagent:existing-route-metadata");
const entry = await readStoredSessionEntry("agent:main:subagent:existing-route-metadata");
expect(entry.route).toEqual({
channel: "slack",
accountId: "default",
@@ -253,41 +258,32 @@ describe("subagent session deliveryContext from spawn request params", () => {
// first (to set spawnDepth, spawnedBy, etc.), then calls callSubagentGateway({method: "agent"}).
// The sessions.patch creates a partial entry without deliveryContext.
// The agent handler must seed deliveryContext from the request params.
setRegistry(defaultRegistry);
testState.sessionStorePath = sessionStorePath;
await writeSessionStore({
entries: {
"agent:main:subagent:pre-patched": {
sessionId: "sess-pre-patched",
updatedAt: Date.now(),
spawnDepth: 1,
spawnedBy: "agent:main:slack:direct:u07fdr83w6n:thread:1775577152.364109",
},
await prepareSessionStore({
"agent:main:subagent:pre-patched": {
sessionId: "sess-pre-patched",
updatedAt: Date.now(),
spawnDepth: 1,
spawnedBy: "agent:main:slack:direct:u07fdr83w6n:thread:1775577152.364109",
},
});
const res = await rpcReq(ws, "agent", {
await sendAgentRequest({
message: "[Subagent Task]: investigate data",
sessionKey: "agent:main:subagent:pre-patched",
channel: "slack",
to: "user:U07FDR83W6N",
accountId: "default",
threadId: "1775577152.364109",
deliver: false,
idempotencyKey: "idem-subagent-delivery-ctx-prepatched",
});
expect(res.ok).toBe(true);
const stored = JSON.parse(await fs.readFile(sessionStorePath, "utf-8")) as Record<
string,
StoredEntry
>;
const entry = readStoredEntry(stored, "agent:main:subagent:pre-patched");
const deliveryContext = readDeliveryContext(entry);
expect(deliveryContext.channel).toBe("slack");
expect(deliveryContext.to).toBe("user:U07FDR83W6N");
expect(deliveryContext.threadId).toBe("1775577152.364109");
expect(deliveryContext.accountId).toBe("default");
const entry = await readStoredSessionEntry("agent:main:subagent:pre-patched");
expectDeliveryContextFields(entry, {
channel: "slack",
to: "user:U07FDR83W6N",
threadId: "1775577152.364109",
accountId: "default",
});
expect(entry.route).toEqual({
channel: "slack",
accountId: "default",
@@ -298,26 +294,18 @@ describe("subagent session deliveryContext from spawn request params", () => {
});
test("request without to/threadId does not inject empty values", async () => {
setRegistry(defaultRegistry);
testState.sessionStorePath = sessionStorePath;
await writeSessionStore({ entries: {} });
await prepareSessionStore();
const res = await rpcReq(ws, "agent", {
await sendAgentRequest({
message: "internal task",
sessionKey: "agent:main:subagent:no-routing",
channel: "slack",
deliver: false,
idempotencyKey: "idem-subagent-delivery-ctx-3",
});
expect(res.ok).toBe(true);
const stored = JSON.parse(await fs.readFile(sessionStorePath, "utf-8")) as Record<
string,
StoredEntry
>;
const entry = readStoredEntry(stored, "agent:main:subagent:no-routing");
const entry = await readStoredSessionEntry("agent:main:subagent:no-routing");
expectDeliveryContextFields(entry, { channel: "slack" });
const deliveryContext = readDeliveryContext(entry);
expect(deliveryContext.channel).toBe("slack");
expect(deliveryContext.to).toBeUndefined();
expect(deliveryContext.threadId).toBeUndefined();
});