Skip to content

Commit 17eab1e

Browse files
committed
fix(channels): preserve route metadata on agent updates
1 parent 02f8fb7 commit 17eab1e

2 files changed

Lines changed: 72 additions & 2 deletions

File tree

src/gateway/server-methods/agent.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,6 +1192,7 @@ export const agentHandlers: GatewayRequestHandlers = {
11921192
requestDeliveryHint,
11931193
);
11941194
const effectiveDeliveryFields = normalizeSessionDeliveryFields({
1195+
route: deliveryFields.route,
11951196
deliveryContext: effectiveDelivery,
11961197
});
11971198
const nextEntryPatch: SessionEntry = {

src/gateway/server.agent.subagent-delivery-context.test.ts

Lines changed: 71 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,8 +71,8 @@ type StoredEntry = {
7171
route?: {
7272
channel?: string;
7373
accountId?: string;
74-
target?: { to?: string };
75-
thread?: { id?: string | number };
74+
target?: { to?: string; rawTo?: string; chatType?: string };
75+
thread?: { id?: string | number; kind?: string; source?: string };
7676
};
7777
deliveryContext?: { channel?: string; to?: string; threadId?: string; accountId?: string };
7878
lastChannel?: string;
@@ -179,6 +179,75 @@ describe("subagent session deliveryContext from spawn request params", () => {
179179
expect(entry.lastTo).toBe("user:U09U1LV7JDN");
180180
});
181181

182+
test("existing session route metadata survives agent request delivery normalization", async () => {
183+
setRegistry(defaultRegistry);
184+
testState.sessionStorePath = sessionStorePath;
185+
await writeSessionStore({
186+
entries: {
187+
"agent:main:subagent:existing-route-metadata": {
188+
sessionId: "sess-existing-route",
189+
updatedAt: Date.now(),
190+
route: {
191+
channel: "slack",
192+
accountId: "default",
193+
target: {
194+
to: "channel:C0AF8TW48UQ",
195+
rawTo: "slack://C0AF8TW48UQ",
196+
chatType: "channel",
197+
},
198+
thread: {
199+
id: "1771242986.529939",
200+
kind: "thread",
201+
source: "target",
202+
},
203+
},
204+
deliveryContext: {
205+
channel: "slack",
206+
to: "channel:C0AF8TW48UQ",
207+
accountId: "default",
208+
threadId: "1771242986.529939",
209+
},
210+
lastChannel: "slack",
211+
lastTo: "channel:C0AF8TW48UQ",
212+
lastAccountId: "default",
213+
lastThreadId: "1771242986.529939",
214+
},
215+
},
216+
});
217+
218+
const res = await rpcReq(ws, "agent", {
219+
message: "follow-up",
220+
sessionKey: "agent:main:subagent:existing-route-metadata",
221+
channel: "slack",
222+
to: "channel:C0AF8TW48UQ",
223+
accountId: "default",
224+
threadId: "1771242986.529939",
225+
deliver: false,
226+
idempotencyKey: "idem-subagent-delivery-route-metadata",
227+
});
228+
expect(res.ok).toBe(true);
229+
230+
const stored = JSON.parse(await fs.readFile(sessionStorePath, "utf-8")) as Record<
231+
string,
232+
StoredEntry
233+
>;
234+
const entry = readStoredEntry(stored, "agent:main:subagent:existing-route-metadata");
235+
expect(entry.route).toEqual({
236+
channel: "slack",
237+
accountId: "default",
238+
target: {
239+
to: "channel:C0AF8TW48UQ",
240+
rawTo: "slack://C0AF8TW48UQ",
241+
chatType: "channel",
242+
},
243+
thread: {
244+
id: "1771242986.529939",
245+
kind: "thread",
246+
source: "target",
247+
},
248+
});
249+
});
250+
182251
test("pre-patched subagent session (via sessions.patch) inherits deliveryContext from agent request", async () => {
183252
// Simulates the real subagent spawn flow: spawnSubagentDirect calls sessions.patch
184253
// first (to set spawnDepth, spawnedBy, etc.), then calls callSubagentGateway({method: "agent"}).

0 commit comments

Comments
 (0)