mirror of https://github.com/openclaw/openclaw.git
test: simplify ACP spawn scenarios
This commit is contained in:
parent
a81e671509
commit
030e950e5f
|
|
@ -92,6 +92,14 @@ const resolveAcpSpawnStreamLogPathSpy = vi.spyOn(
|
|||
);
|
||||
|
||||
const { spawnAcpDirect } = await import("./acp-spawn.js");
|
||||
type SpawnRequest = Parameters<typeof spawnAcpDirect>[0];
|
||||
type SpawnContext = Parameters<typeof spawnAcpDirect>[1];
|
||||
type AgentCallParams = {
|
||||
deliver?: boolean;
|
||||
channel?: string;
|
||||
to?: string;
|
||||
threadId?: string;
|
||||
};
|
||||
|
||||
function replaceSpawnConfig(next: OpenClawConfig): void {
|
||||
const current = hoisted.state.cfg as Record<string, unknown>;
|
||||
|
|
@ -153,6 +161,64 @@ function expectResolvedIntroTextInBindMetadata(): void {
|
|||
expect(introText.includes("session ids: pending (available after the first reply)")).toBe(false);
|
||||
}
|
||||
|
||||
function createSpawnRequest(overrides?: Partial<SpawnRequest>): SpawnRequest {
|
||||
return {
|
||||
task: "Investigate flaky tests",
|
||||
agentId: "codex",
|
||||
mode: "run",
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function createRequesterContext(overrides?: Partial<SpawnContext>): SpawnContext {
|
||||
return {
|
||||
agentSessionKey: "agent:main:telegram:direct:6098642967",
|
||||
agentChannel: "telegram",
|
||||
agentAccountId: "default",
|
||||
agentTo: "telegram:6098642967",
|
||||
agentThreadId: "1",
|
||||
...overrides,
|
||||
};
|
||||
}
|
||||
|
||||
function findAgentGatewayCall(): { method?: string; params?: Record<string, unknown> } | undefined {
|
||||
return hoisted.callGatewayMock.mock.calls
|
||||
.map((call: unknown[]) => call[0] as { method?: string; params?: Record<string, unknown> })
|
||||
.find((request) => request.method === "agent");
|
||||
}
|
||||
|
||||
function expectAgentGatewayCall(overrides: AgentCallParams): void {
|
||||
const agentCall = findAgentGatewayCall();
|
||||
expect(agentCall?.params?.deliver).toBe(overrides.deliver);
|
||||
expect(agentCall?.params?.channel).toBe(overrides.channel);
|
||||
expect(agentCall?.params?.to).toBe(overrides.to);
|
||||
expect(agentCall?.params?.threadId).toBe(overrides.threadId);
|
||||
}
|
||||
|
||||
function enableMatrixAcpThreadBindings(): void {
|
||||
replaceSpawnConfig({
|
||||
...hoisted.state.cfg,
|
||||
channels: {
|
||||
...hoisted.state.cfg.channels,
|
||||
matrix: {
|
||||
threadBindings: {
|
||||
enabled: true,
|
||||
spawnAcpSessions: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
registerSessionBindingAdapter({
|
||||
channel: "matrix",
|
||||
accountId: "default",
|
||||
capabilities: createSessionBindingCapabilities(),
|
||||
bind: async (input) => await hoisted.sessionBindingBindMock(input),
|
||||
listBySession: (targetSessionKey) => hoisted.sessionBindingListBySessionMock(targetSessionKey),
|
||||
resolveByConversation: (ref) => hoisted.sessionBindingResolveByConversationMock(ref),
|
||||
unbind: async (input) => await hoisted.sessionBindingUnbindMock(input),
|
||||
});
|
||||
}
|
||||
|
||||
describe("spawnAcpDirect", () => {
|
||||
beforeEach(() => {
|
||||
replaceSpawnConfig(createDefaultSpawnConfig());
|
||||
|
|
@ -383,28 +449,7 @@ describe("spawnAcpDirect", () => {
|
|||
});
|
||||
|
||||
it("spawns Matrix thread-bound ACP sessions from top-level room targets", async () => {
|
||||
replaceSpawnConfig({
|
||||
...hoisted.state.cfg,
|
||||
channels: {
|
||||
...hoisted.state.cfg.channels,
|
||||
matrix: {
|
||||
threadBindings: {
|
||||
enabled: true,
|
||||
spawnAcpSessions: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
registerSessionBindingAdapter({
|
||||
channel: "matrix",
|
||||
accountId: "default",
|
||||
capabilities: createSessionBindingCapabilities(),
|
||||
bind: async (input) => await hoisted.sessionBindingBindMock(input),
|
||||
listBySession: (targetSessionKey) =>
|
||||
hoisted.sessionBindingListBySessionMock(targetSessionKey),
|
||||
resolveByConversation: (ref) => hoisted.sessionBindingResolveByConversationMock(ref),
|
||||
unbind: async (input) => await hoisted.sessionBindingUnbindMock(input),
|
||||
});
|
||||
enableMatrixAcpThreadBindings();
|
||||
hoisted.sessionBindingBindMock.mockImplementationOnce(
|
||||
async (input: {
|
||||
targetSessionKey: string;
|
||||
|
|
@ -453,74 +498,57 @@ describe("spawnAcpDirect", () => {
|
|||
}),
|
||||
}),
|
||||
);
|
||||
const agentCall = hoisted.callGatewayMock.mock.calls
|
||||
.map((call: unknown[]) => call[0] as { method?: string; params?: Record<string, unknown> })
|
||||
.find((request) => request.method === "agent");
|
||||
expect(agentCall?.params?.channel).toBe("matrix");
|
||||
expect(agentCall?.params?.to).toBe("room:!room:example");
|
||||
expect(agentCall?.params?.threadId).toBe("child-thread");
|
||||
expectAgentGatewayCall({
|
||||
deliver: true,
|
||||
channel: "matrix",
|
||||
to: "room:!room:example",
|
||||
threadId: "child-thread",
|
||||
});
|
||||
});
|
||||
|
||||
it("inlines delivery for run-mode spawns from non-subagent requester sessions", async () => {
|
||||
const result = await spawnAcpDirect(
|
||||
{
|
||||
task: "Investigate flaky tests",
|
||||
agentId: "codex",
|
||||
mode: "run",
|
||||
},
|
||||
{
|
||||
agentSessionKey: "agent:main:telegram:direct:6098642967",
|
||||
agentChannel: "telegram",
|
||||
agentAccountId: "default",
|
||||
agentTo: "telegram:6098642967",
|
||||
agentThreadId: "1",
|
||||
},
|
||||
);
|
||||
|
||||
expect(result.status).toBe("accepted");
|
||||
expect(result.mode).toBe("run");
|
||||
expect(result.streamLogPath).toBeUndefined();
|
||||
expect(hoisted.startAcpSpawnParentStreamRelayMock).not.toHaveBeenCalled();
|
||||
expect(hoisted.resolveSessionTranscriptFileMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
sessionId: "sess-123",
|
||||
storePath: "/tmp/codex-sessions.json",
|
||||
agentId: "codex",
|
||||
}),
|
||||
);
|
||||
const agentCall = hoisted.callGatewayMock.mock.calls
|
||||
.map((call: unknown[]) => call[0] as { method?: string; params?: Record<string, unknown> })
|
||||
.find((request) => request.method === "agent");
|
||||
expect(agentCall?.params?.deliver).toBe(true);
|
||||
expect(agentCall?.params?.channel).toBe("telegram");
|
||||
expect(agentCall?.params?.to).toBe("telegram:6098642967");
|
||||
});
|
||||
|
||||
it("does not inline delivery for run-mode spawns from subagent requester sessions", async () => {
|
||||
const result = await spawnAcpDirect(
|
||||
{
|
||||
task: "Investigate flaky tests",
|
||||
agentId: "codex",
|
||||
mode: "run",
|
||||
},
|
||||
{
|
||||
it.each([
|
||||
{
|
||||
name: "inlines delivery for run-mode spawns from non-subagent requester sessions",
|
||||
ctx: createRequesterContext(),
|
||||
expectedAgentCall: {
|
||||
deliver: true,
|
||||
channel: "telegram",
|
||||
to: "telegram:6098642967",
|
||||
threadId: "1",
|
||||
} satisfies AgentCallParams,
|
||||
expectTranscriptPersistence: true,
|
||||
},
|
||||
{
|
||||
name: "does not inline delivery for run-mode spawns from subagent requester sessions",
|
||||
ctx: createRequesterContext({
|
||||
agentSessionKey: "agent:main:subagent:orchestrator",
|
||||
agentChannel: "telegram",
|
||||
agentAccountId: "default",
|
||||
agentTo: "telegram:6098642967",
|
||||
},
|
||||
);
|
||||
agentThreadId: undefined,
|
||||
}),
|
||||
expectedAgentCall: {
|
||||
deliver: false,
|
||||
channel: undefined,
|
||||
to: undefined,
|
||||
threadId: undefined,
|
||||
} satisfies AgentCallParams,
|
||||
expectTranscriptPersistence: false,
|
||||
},
|
||||
])("$name", async ({ ctx, expectedAgentCall, expectTranscriptPersistence }) => {
|
||||
const result = await spawnAcpDirect(createSpawnRequest(), ctx);
|
||||
|
||||
expect(result.status).toBe("accepted");
|
||||
expect(result.mode).toBe("run");
|
||||
expect(result.streamLogPath).toBeUndefined();
|
||||
expect(hoisted.startAcpSpawnParentStreamRelayMock).not.toHaveBeenCalled();
|
||||
const agentCall = hoisted.callGatewayMock.mock.calls
|
||||
.map((call: unknown[]) => call[0] as { method?: string; params?: Record<string, unknown> })
|
||||
.find((request) => request.method === "agent");
|
||||
expect(agentCall?.params?.deliver).toBe(false);
|
||||
expect(agentCall?.params?.channel).toBeUndefined();
|
||||
expect(agentCall?.params?.to).toBeUndefined();
|
||||
if (expectTranscriptPersistence) {
|
||||
expect(hoisted.resolveSessionTranscriptFileMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
sessionId: "sess-123",
|
||||
storePath: "/tmp/codex-sessions.json",
|
||||
agentId: "codex",
|
||||
}),
|
||||
);
|
||||
}
|
||||
expectAgentGatewayCall(expectedAgentCall);
|
||||
});
|
||||
|
||||
it("keeps ACP spawn running when session-file persistence fails", async () => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue