Skip to content

Commit 2b05bd7

Browse files
committed
fix(cli): preserve sessions_yield over MCP
1 parent eea350f commit 2b05bd7

15 files changed

Lines changed: 1659 additions & 320 deletions

src/agents/cli-output.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export type CliOutput = {
3434
messagingToolSentMediaUrls?: string[];
3535
messagingToolSentTargets?: MessagingToolSend[];
3636
messagingToolSourceReplyPayloads?: MessagingToolSourceReplyPayload[];
37+
yielded?: true;
3738
};
3839

3940
/** Incremental assistant text emitted while parsing a streaming CLI response. */

src/agents/cli-runner.reliability.test.ts

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@ import { CURRENT_SESSION_VERSION } from "../config/sessions/version.js";
1414
import type { OpenClawConfig } from "../config/types.openclaw.js";
1515
import {
1616
markMcpLoopbackRequestClassified,
17+
markMcpLoopbackRequestFinished,
1718
markMcpLoopbackRequestStarted,
1819
markMcpLoopbackToolCallFinished,
1920
markMcpLoopbackToolCallStarted,
2021
recordMcpLoopbackToolCallResult,
22+
resolveMcpLoopbackYieldContext,
2123
updateMcpLoopbackToolCallCapture,
2224
} from "../gateway/mcp-http.loopback-runtime.js";
2325
import { getGlobalHookRunner } from "../plugins/hook-runner-global.js";
@@ -1687,35 +1689,39 @@ describe("runCliAgent reliability", () => {
16871689
expect(completion.refusal).toBe(false);
16881690
});
16891691

1690-
it("marks CLI runs as yielded when bundle MCP records sessions_yield", async () => {
1691-
const exit = {
1692-
reason: "exit" as const,
1693-
exitCode: 0,
1694-
exitSignal: null,
1695-
durationMs: 50,
1696-
stdout: "yield acknowledged",
1697-
stderr: "",
1698-
timedOut: false,
1699-
noOutputTimedOut: false,
1700-
};
1701-
supervisorSpawnMock.mockResolvedValueOnce({
1702-
...createManagedRun(exit),
1703-
wait: vi.fn(async () => {
1704-
const runtime = await import("../gateway/mcp-http.loopback-runtime.js");
1705-
runtime.resolveMcpLoopbackYieldHandler("s1")?.("waiting on subagents");
1706-
return exit;
1707-
}),
1692+
it("marks CLI runs as paused after sessions_yield", async () => {
1693+
supervisorSpawnMock.mockImplementationOnce(async (...args: unknown[]) => {
1694+
const input = args[0] as Parameters<ReturnType<typeof getProcessSupervisor>["spawn"]>[0];
1695+
const captureHandle = markMcpLoopbackRequestStarted(input.env?.OPENCLAW_MCP_CLI_CAPTURE_KEY);
1696+
await resolveMcpLoopbackYieldContext(captureHandle)?.onYield("waiting on subagents");
1697+
markMcpLoopbackRequestFinished(captureHandle);
1698+
input.onStdout?.("yield acknowledged");
1699+
return createManagedRun({
1700+
reason: "exit",
1701+
exitCode: 0,
1702+
exitSignal: null,
1703+
durationMs: 50,
1704+
stdout: "",
1705+
stderr: "",
1706+
timedOut: false,
1707+
noOutputTimedOut: false,
1708+
});
17081709
});
1710+
const context = buildPreparedContext();
1711+
context.mcpDeliveryCapture = true;
17091712

1710-
const result = await runPreparedCliAgent(buildPreparedContext());
1713+
const result = await runPreparedCliAgent(context);
17111714

1712-
expect(result.meta.yielded).toBe(true);
1713-
expect(result.meta.livenessState).toBe("paused");
1714-
expect(result.meta.stopReason).toBe("end_turn");
1715-
const completion = requireRecord(result.meta.completion, "completion");
1716-
expect(completion.finishReason).toBe("end_turn");
1717-
expect(completion.stopReason).toBe("end_turn");
1718-
expect(completion.refusal).toBe(false);
1715+
expect(result.meta).toMatchObject({
1716+
yielded: true,
1717+
livenessState: "paused",
1718+
stopReason: "end_turn",
1719+
completion: {
1720+
finishReason: "end_turn",
1721+
stopReason: "end_turn",
1722+
refusal: false,
1723+
},
1724+
});
17191725
});
17201726

17211727
it("seeds fresh CLI sessions from the OpenClaw transcript", async () => {

0 commit comments

Comments
 (0)