




















@@ -14,6 +14,7 @@ const hoisted = vi.hoisted(() => ({
1414pruneLegacyStoreKeysMock: vi.fn(),
1515registerSubagentRunMock: vi.fn(),
1616emitSessionLifecycleEventMock: vi.fn(),
17+resolveAgentConfigMock: vi.fn(),
1718configOverride: {} as Record<string, unknown>,
1819}));
1920@@ -46,7 +47,7 @@ describe("spawnSubagentDirect seam flow", () => {
4647pruneLegacyStoreKeysMock: hoisted.pruneLegacyStoreKeysMock,
4748registerSubagentRunMock: hoisted.registerSubagentRunMock,
4849emitSessionLifecycleEventMock: hoisted.emitSessionLifecycleEventMock,
49-resolveAgentConfig: () => undefined,
50+resolveAgentConfig: hoisted.resolveAgentConfigMock,
5051resolveSubagentSpawnModelSelection: () => "openai-codex/gpt-5.4",
5152resolveSandboxRuntimeStatus: () => ({ sandboxed: false }),
5253sessionStorePath: "/tmp/subagent-spawn-session-store.json",
@@ -61,6 +62,11 @@ describe("spawnSubagentDirect seam flow", () => {
6162hoisted.pruneLegacyStoreKeysMock.mockReset();
6263hoisted.registerSubagentRunMock.mockReset();
6364hoisted.emitSessionLifecycleEventMock.mockReset();
65+hoisted.resolveAgentConfigMock.mockReset();
66+hoisted.resolveAgentConfigMock.mockImplementation(
67+(cfg: { agents?: { list?: Array<{ id?: string }> } }, agentId: string) =>
68+cfg.agents?.list?.find((agent) => agent.id === agentId),
69+);
6470hoisted.configOverride = createConfigOverride();
6571installAcceptedSubagentGatewayMock(hoisted.callGatewayMock);
6672@@ -76,6 +82,84 @@ describe("spawnSubagentDirect seam flow", () => {
7682);
7783});
788485+it("rejects explicit same-agent targets when allowAgents excludes the requester", async () => {
86+hoisted.configOverride = createConfigOverride({
87+agents: {
88+defaults: {
89+workspace: os.tmpdir(),
90+},
91+list: [
92+{
93+id: "task-manager",
94+workspace: "/tmp/workspace-task-manager",
95+subagents: {
96+allowAgents: ["planner"],
97+},
98+},
99+{
100+id: "planner",
101+workspace: "/tmp/workspace-planner",
102+},
103+],
104+},
105+});
106+107+const result = await spawnSubagentDirect(
108+{
109+task: "spawn myself explicitly",
110+agentId: "task-manager",
111+},
112+{
113+agentSessionKey: "agent:task-manager:main",
114+},
115+);
116+117+expect(result).toMatchObject({
118+status: "forbidden",
119+error: "agentId is not allowed for sessions_spawn (allowed: planner)",
120+});
121+expect(hoisted.callGatewayMock).not.toHaveBeenCalledWith(
122+expect.objectContaining({ method: "agent" }),
123+);
124+});
125+126+it("allows omitted agentId to default to requester even when allowAgents excludes requester", async () => {
127+hoisted.configOverride = createConfigOverride({
128+agents: {
129+defaults: {
130+workspace: os.tmpdir(),
131+},
132+list: [
133+{
134+id: "task-manager",
135+workspace: "/tmp/workspace-task-manager",
136+subagents: {
137+allowAgents: ["planner"],
138+},
139+},
140+{
141+id: "planner",
142+workspace: "/tmp/workspace-planner",
143+},
144+],
145+},
146+});
147+148+const result = await spawnSubagentDirect(
149+{
150+task: "spawn default target",
151+},
152+{
153+agentSessionKey: "agent:task-manager:main",
154+},
155+);
156+157+expect(result).toMatchObject({
158+status: "accepted",
159+childSessionKey: expect.stringMatching(/^agent:task-manager:subagent:/),
160+});
161+});
162+79163it("accepts a spawned run across session patching, runtime-model persistence, registry registration, and lifecycle emission", async () => {
80164const operations: string[] = [];
81165let persistedStore: Record<string, Record<string, unknown>> | undefined;
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。