mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 11:00:42 +00:00
Keep Codex Computer Use hook relays live across turns (#74107)
* Fix Codex native hook relay across processes * fix: harden native hook relay bridge * test: stabilize pairing store cache assertion --------- Co-authored-by: pashpashpash <nik@vault77.ai>
This commit is contained in:
@@ -735,6 +735,71 @@ describe("runCodexAppServerAttempt", () => {
|
||||
expect(nativeHookRelayTesting.getNativeHookRelayRegistrationForTests(relayId)).toBeUndefined();
|
||||
});
|
||||
|
||||
it("reuses the Codex native hook relay id across runs for the same session", async () => {
|
||||
const sessionFile = path.join(tempDir, "session.jsonl");
|
||||
const workspaceDir = path.join(tempDir, "workspace");
|
||||
const firstHarness = createStartedThreadHarness();
|
||||
|
||||
const firstRun = runCodexAppServerAttempt(createParams(sessionFile, workspaceDir), {
|
||||
nativeHookRelay: {
|
||||
enabled: true,
|
||||
events: ["pre_tool_use"],
|
||||
},
|
||||
});
|
||||
await firstHarness.waitForMethod("turn/start");
|
||||
await firstHarness.completeTurn({ threadId: "thread-1", turnId: "turn-1" });
|
||||
await firstRun;
|
||||
|
||||
const firstStartRequest = firstHarness.requests.find(
|
||||
(request) => request.method === "thread/start",
|
||||
);
|
||||
const firstRelayId = extractRelayIdFromThreadRequest(firstStartRequest?.params);
|
||||
expect(
|
||||
nativeHookRelayTesting.getNativeHookRelayRegistrationForTests(firstRelayId),
|
||||
).toBeUndefined();
|
||||
|
||||
const secondHarness = createResumeHarness();
|
||||
const secondParams = createParams(sessionFile, workspaceDir);
|
||||
secondParams.runId = "run-2";
|
||||
const secondRun = runCodexAppServerAttempt(secondParams, {
|
||||
nativeHookRelay: {
|
||||
enabled: true,
|
||||
events: ["pre_tool_use"],
|
||||
},
|
||||
});
|
||||
await secondHarness.waitForMethod("turn/start");
|
||||
|
||||
const resumeRequest = secondHarness.requests.find(
|
||||
(request) => request.method === "thread/resume",
|
||||
);
|
||||
const secondRelayId = extractRelayIdFromThreadRequest(resumeRequest?.params);
|
||||
expect(secondRelayId).toBe(firstRelayId);
|
||||
expect(
|
||||
nativeHookRelayTesting.getNativeHookRelayRegistrationForTests(firstRelayId),
|
||||
).toMatchObject({
|
||||
runId: "run-2",
|
||||
allowedEvents: ["pre_tool_use"],
|
||||
});
|
||||
|
||||
await secondHarness.completeTurn({ threadId: "thread-existing", turnId: "turn-1" });
|
||||
await secondRun;
|
||||
expect(
|
||||
nativeHookRelayTesting.getNativeHookRelayRegistrationForTests(firstRelayId),
|
||||
).toBeUndefined();
|
||||
});
|
||||
|
||||
it("builds deterministic opaque Codex native hook relay ids", () => {
|
||||
const relayId = __testing.buildCodexNativeHookRelayId({
|
||||
agentId: "dev-codex",
|
||||
sessionId: "cu-pr-relay-smoke",
|
||||
sessionKey: "agent:dev-codex:cu-pr-relay-smoke",
|
||||
});
|
||||
|
||||
expect(relayId).toBe("codex-8810b5252975550c887ff0def512b25e944bac39");
|
||||
expect(relayId).not.toContain("dev-codex");
|
||||
expect(relayId).not.toContain("cu-pr-relay-smoke");
|
||||
});
|
||||
|
||||
it("sends clearing Codex native hook config when the relay is disabled", async () => {
|
||||
const sessionFile = path.join(tempDir, "session.jsonl");
|
||||
const workspaceDir = path.join(tempDir, "workspace");
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { createHash } from "node:crypto";
|
||||
import fs from "node:fs/promises";
|
||||
import { SessionManager } from "@mariozechner/pi-coding-agent";
|
||||
import {
|
||||
@@ -1009,6 +1010,11 @@ function createCodexNativeHookRelay(params: {
|
||||
}
|
||||
return registerNativeHookRelay({
|
||||
provider: "codex",
|
||||
relayId: buildCodexNativeHookRelayId({
|
||||
agentId: params.agentId,
|
||||
sessionId: params.sessionId,
|
||||
sessionKey: params.sessionKey,
|
||||
}),
|
||||
...(params.agentId ? { agentId: params.agentId } : {}),
|
||||
sessionId: params.sessionId,
|
||||
...(params.sessionKey ? { sessionKey: params.sessionKey } : {}),
|
||||
@@ -1022,6 +1028,20 @@ function createCodexNativeHookRelay(params: {
|
||||
});
|
||||
}
|
||||
|
||||
function buildCodexNativeHookRelayId(params: {
|
||||
agentId: string | undefined;
|
||||
sessionId: string;
|
||||
sessionKey: string | undefined;
|
||||
}): string {
|
||||
const hash = createHash("sha256");
|
||||
hash.update("openclaw:codex:native-hook-relay:v1");
|
||||
hash.update("\0");
|
||||
hash.update(params.agentId?.trim() || "");
|
||||
hash.update("\0");
|
||||
hash.update(params.sessionKey?.trim() || params.sessionId);
|
||||
return `codex-${hash.digest("hex").slice(0, 40)}`;
|
||||
}
|
||||
|
||||
function interruptCodexTurnBestEffort(
|
||||
client: CodexAppServerClient,
|
||||
params: {
|
||||
@@ -1297,6 +1317,7 @@ function handleApprovalRequest(params: {
|
||||
export const __testing = {
|
||||
CODEX_DYNAMIC_TOOL_TIMEOUT_MS,
|
||||
CODEX_TURN_COMPLETION_IDLE_TIMEOUT_MS,
|
||||
buildCodexNativeHookRelayId,
|
||||
filterToolsForVisionInputs,
|
||||
handleDynamicToolCallWithTimeout,
|
||||
...createCodexAppServerClientFactoryTestHooks((factory) => {
|
||||
|
||||
Reference in New Issue
Block a user