























@@ -49,6 +49,48 @@ describe("sessions_spawn context modes", () => {
4949});
5050}
515152+function requireAcceptedResult(result: Awaited<ReturnType<typeof spawnSubagentDirect>>) {
53+expect(result.status).toBe("accepted");
54+if (result.status !== "accepted") {
55+throw new Error(`expected accepted result, got ${result.status}`);
56+}
57+return result;
58+}
59+60+function requireStoreEntry(store: SessionStore, key: string): Record<string, unknown> {
61+const entry = store[key];
62+if (!entry) {
63+throw new Error(`expected session store entry ${key}`);
64+}
65+return entry;
66+}
67+68+function requireChildSessionKey(result: Awaited<ReturnType<typeof spawnSubagentDirect>>): string {
69+const key = result.childSessionKey;
70+if (!key) {
71+throw new Error("expected child session key");
72+}
73+return key;
74+}
75+76+function requireFirstMockArg(mock: ReturnType<typeof vi.fn>): Record<string, unknown> {
77+const arg = mock.mock.calls.at(0)?.[0];
78+if (!arg || typeof arg !== "object") {
79+throw new Error("expected first mock argument object");
80+}
81+return arg as Record<string, unknown>;
82+}
83+84+function requireGatewayRequest(method: string): GatewayRequest {
85+const request = callGatewayMock.mock.calls
86+.map(([arg]) => arg as GatewayRequest)
87+.find((candidate) => candidate.method === method);
88+if (!request) {
89+throw new Error(`expected gateway request ${method}`);
90+}
91+return request;
92+}
93+5294it("forks the requester transcript when context=fork", async () => {
5395const store: SessionStore = {
5496main: {
@@ -71,27 +113,26 @@ describe("sessions_spawn context modes", () => {
71113{ agentSessionKey: "main" },
72114);
7311574-expect(result).toMatchObject({ status: "accepted", runId: "run-1" });
116+const accepted = requireAcceptedResult(result);
117+expect(accepted.runId).toBe("run-1");
75118expect(forkSessionFromParentMock).toHaveBeenCalledWith({
76119parentEntry: store.main,
77120agentId: "main",
78121sessionsDir: path.dirname(storePath),
79122});
80-expect(store[result.childSessionKey ?? ""]).toMatchObject({
81-sessionId: "forked-session-id",
82-sessionFile: "/tmp/forked-session.jsonl",
83-forkedFromParent: true,
84-});
85-expect(prepareSubagentSpawn).toHaveBeenCalledWith(
86-expect.objectContaining({
87-parentSessionKey: "main",
88-childSessionKey: result.childSessionKey,
89-contextMode: "fork",
90-parentSessionId: "parent-session-id",
91-childSessionId: "forked-session-id",
92-childSessionFile: "/tmp/forked-session.jsonl",
93-}),
94-);
123+const childSessionKey = requireChildSessionKey(accepted);
124+const childEntry = requireStoreEntry(store, childSessionKey);
125+expect(childEntry.sessionId).toBe("forked-session-id");
126+expect(childEntry.sessionFile).toBe("/tmp/forked-session.jsonl");
127+expect(childEntry.forkedFromParent).toBe(true);
128+129+const prepareContext = requireFirstMockArg(prepareSubagentSpawn);
130+expect(prepareContext.parentSessionKey).toBe("main");
131+expect(prepareContext.childSessionKey).toBe(childSessionKey);
132+expect(prepareContext.contextMode).toBe("fork");
133+expect(prepareContext.parentSessionId).toBe("parent-session-id");
134+expect(prepareContext.childSessionId).toBe("forked-session-id");
135+expect(prepareContext.childSessionFile).toBe("/tmp/forked-session.jsonl");
95136});
9613797138it("keeps the default spawn context isolated", async () => {
@@ -106,13 +147,10 @@ describe("sessions_spawn context modes", () => {
106147107148expect(result.status).toBe("accepted");
108149expect(forkSessionFromParentMock).not.toHaveBeenCalled();
109-expect(prepareSubagentSpawn).toHaveBeenCalledWith(
110-expect.objectContaining({
111-parentSessionKey: "main",
112-childSessionKey: result.childSessionKey,
113-contextMode: "isolated",
114-}),
115-);
150+const prepareContext = requireFirstMockArg(prepareSubagentSpawn);
151+expect(prepareContext.parentSessionKey).toBe("main");
152+expect(prepareContext.childSessionKey).toBe(requireChildSessionKey(result));
153+expect(prepareContext.contextMode).toBe("isolated");
116154});
117155118156it("falls back to isolated context when requested fork is too large", async () => {
@@ -133,17 +171,15 @@ describe("sessions_spawn context modes", () => {
133171{ agentSessionKey: "main" },
134172);
135173136-expect(result).toMatchObject({ status: "accepted", runId: "run-1" });
137-expect(result.note).toContain("Parent context is too large to fork");
174+const accepted = requireAcceptedResult(result);
175+expect(accepted.runId).toBe("run-1");
176+expect(accepted.note).toContain("Parent context is too large to fork");
138177expect(forkSessionFromParentMock).not.toHaveBeenCalled();
139-expect(prepareSubagentSpawn).toHaveBeenCalledWith(
140-expect.objectContaining({
141-parentSessionKey: "main",
142-childSessionKey: result.childSessionKey,
143-contextMode: "isolated",
144-parentSessionId: "parent-session-id",
145-}),
146-);
178+const prepareContext = requireFirstMockArg(prepareSubagentSpawn);
179+expect(prepareContext.parentSessionKey).toBe("main");
180+expect(prepareContext.childSessionKey).toBe(requireChildSessionKey(accepted));
181+expect(prepareContext.contextMode).toBe("isolated");
182+expect(prepareContext.parentSessionId).toBe("parent-session-id");
147183});
148184149185it("forks by default for thread-bound subagent sessions", async () => {
@@ -179,16 +215,10 @@ describe("sessions_spawn context modes", () => {
179215agentId: "main",
180216sessionsDir: path.dirname(storePath),
181217});
182-expect(callGatewayMock).toHaveBeenCalledWith(
183-expect.objectContaining({
184-method: "sessions.delete",
185-params: expect.objectContaining({
186-key: result.childSessionKey,
187-deleteTranscript: true,
188-emitLifecycleHooks: false,
189-}),
190-}),
191-);
218+const cleanupRequest = requireGatewayRequest("sessions.delete");
219+expect(cleanupRequest.params?.key).toBe(result.childSessionKey);
220+expect(cleanupRequest.params?.deleteTranscript).toBe(true);
221+expect(cleanupRequest.params?.emitLifecycleHooks).toBe(false);
192222expect(prepareSubagentSpawn).not.toHaveBeenCalled();
193223});
194224@@ -234,7 +264,8 @@ describe("sessions_spawn context modes", () => {
234264235265const result = await spawnSubagentDirect({ task: "clean worker" }, { agentSessionKey: "main" });
236266237-expect(result).toMatchObject({ status: "error", error: "agent start failed" });
267+expect(result.status).toBe("error");
268+expect(result.error).toBe("agent start failed");
238269expect(rollback).toHaveBeenCalledTimes(1);
239270expect(callGatewayMock.mock.calls.map((call) => (call[0] as GatewayRequest).method)).toContain(
240271"sessions.delete",
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。