@openclaw/codex 2026.5.4-beta.1 → 2026.5.4-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,6 +1,6 @@
1
1
  import { t as __exportAll } from "./rolldown-runtime-DUslC3ob.js";
2
- import { i as resolveCodexAppServerRuntimeOptions, t as codexAppServerStartOptionsKey } from "./config-CkkoMeqF.js";
3
- import { a as MANAGED_CODEX_APP_SERVER_PACKAGE, o as resolveCodexAppServerSpawnEnv, t as CodexAppServerClient } from "./client-chGfNrq5.js";
2
+ import { i as resolveCodexAppServerRuntimeOptions, t as codexAppServerStartOptionsKey } from "./config-ByrA30No.js";
3
+ import { a as MANAGED_CODEX_APP_SERVER_PACKAGE, o as resolveCodexAppServerSpawnEnv, t as CodexAppServerClient } from "./client-BGbqC7jk.js";
4
4
  import { createRequire } from "node:module";
5
5
  import fs, { access } from "node:fs/promises";
6
6
  import path from "node:path";
package/dist/test-api.js CHANGED
@@ -1,5 +1,5 @@
1
- import { i as resolveCodexAppServerRuntimeOptions } from "./config-CkkoMeqF.js";
2
- import { i as buildTurnStartParams, n as buildThreadResumeParams, o as createCodexDynamicToolBridge, r as buildThreadStartParams, s as applyCodexDynamicToolProfile, t as buildDeveloperInstructions } from "./thread-lifecycle-C2MSeIjn.js";
1
+ import { i as resolveCodexAppServerRuntimeOptions } from "./config-ByrA30No.js";
2
+ import { a as buildTurnStartParams, c as createCodexDynamicToolBridge, i as buildThreadStartParams, l as applyCodexDynamicToolProfile, n as buildDeveloperInstructions, r as buildThreadResumeParams } from "./thread-lifecycle-CzllX4PU.js";
3
3
  //#region extensions/codex/test-api.ts
4
4
  function resolveCodexPromptSnapshotAppServerOptions(pluginConfig) {
5
5
  return resolveCodexAppServerRuntimeOptions({
@@ -1,9 +1,9 @@
1
- import { n as codexSandboxPolicyForTurn } from "./config-CkkoMeqF.js";
2
- import { n as assertCodexThreadStartResponse, t as assertCodexThreadResumeResponse } from "./protocol-validators-Cpopom3_.js";
1
+ import { n as codexSandboxPolicyForTurn } from "./config-ByrA30No.js";
2
+ import { n as assertCodexThreadStartResponse, t as assertCodexThreadResumeResponse } from "./protocol-validators-Dky2yV4W.js";
3
3
  import { t as isJsonObject } from "./protocol-C9UWI98H.js";
4
4
  import { CODEX_GPT5_HEARTBEAT_PROMPT_OVERLAY, renderCodexPromptOverlay } from "./prompt-overlay.js";
5
5
  import { isModernCodexModel } from "./provider.js";
6
- import { i as isCodexAppServerConnectionClosedError } from "./client-chGfNrq5.js";
6
+ import { i as isCodexAppServerConnectionClosedError } from "./client-BGbqC7jk.js";
7
7
  import { i as readCodexAppServerBinding, n as isCodexAppServerNativeAuthProfile, o as writeCodexAppServerBinding, t as clearCodexAppServerBinding } from "./session-binding-DuJYTJQy.js";
8
8
  import { HEARTBEAT_RESPONSE_TOOL_NAME, createAgentToolResultMiddlewareRunner, createCodexAppServerToolResultExtensionRunner, embeddedAgentLog, extractToolResultMediaArtifact, filterToolResultMediaUrls, isMessagingTool, isMessagingToolSendAction, isToolWrappedWithBeforeToolCallHook, normalizeHeartbeatToolResponse, runAgentHarnessAfterToolCallHook, wrapToolWithBeforeToolCallHook } from "openclaw/plugin-sdk/agent-harness-runtime";
9
9
  //#region extensions/codex/src/app-server/dynamic-tool-profile.ts
@@ -28,6 +28,7 @@ function applyCodexDynamicToolProfile(tools, config) {
28
28
  //#endregion
29
29
  //#region extensions/codex/src/app-server/dynamic-tools.ts
30
30
  function createCodexDynamicToolBridge(params) {
31
+ const toolResultHookContext = toToolResultHookContext(params.hookContext);
31
32
  const tools = params.tools.map((tool) => isToolWrappedWithBeforeToolCallHook(tool) ? tool : wrapToolWithBeforeToolCallHook(tool, params.hookContext));
32
33
  const toolMap = new Map(tools.map((tool) => [tool.name, tool]));
33
34
  const telemetry = {
@@ -40,9 +41,9 @@ function createCodexDynamicToolBridge(params) {
40
41
  };
41
42
  const middlewareRunner = createAgentToolResultMiddlewareRunner({
42
43
  runtime: "codex",
43
- ...params.hookContext
44
+ ...toolResultHookContext
44
45
  });
45
- const legacyExtensionRunner = createCodexAppServerToolResultExtensionRunner(params.hookContext ?? {});
46
+ const legacyExtensionRunner = createCodexAppServerToolResultExtensionRunner(toolResultHookContext);
46
47
  return {
47
48
  specs: tools.map((tool) => ({
48
49
  name: tool.name,
@@ -83,28 +84,29 @@ function createCodexDynamicToolBridge(params) {
83
84
  args,
84
85
  result: middlewareResult
85
86
  });
87
+ const resultIsError = rawIsError || isToolResultError(result);
86
88
  collectToolTelemetry({
87
89
  toolName: tool.name,
88
90
  args,
89
91
  result,
90
92
  mediaTrustResult: rawResult,
91
93
  telemetry,
92
- isError: rawIsError || isToolResultError(result)
94
+ isError: resultIsError
93
95
  });
94
96
  runAgentHarnessAfterToolCallHook({
95
97
  toolName: tool.name,
96
98
  toolCallId: call.callId,
97
- runId: params.hookContext?.runId,
98
- agentId: params.hookContext?.agentId,
99
- sessionId: params.hookContext?.sessionId,
100
- sessionKey: params.hookContext?.sessionKey,
99
+ runId: toolResultHookContext.runId,
100
+ agentId: toolResultHookContext.agentId,
101
+ sessionId: toolResultHookContext.sessionId,
102
+ sessionKey: toolResultHookContext.sessionKey,
101
103
  startArgs: args,
102
104
  result,
103
105
  startedAt
104
106
  });
105
107
  return {
106
108
  contentItems: result.content.flatMap(convertToolContent),
107
- success: true
109
+ success: !resultIsError
108
110
  };
109
111
  } catch (error) {
110
112
  collectToolTelemetry({
@@ -117,10 +119,10 @@ function createCodexDynamicToolBridge(params) {
117
119
  runAgentHarnessAfterToolCallHook({
118
120
  toolName: tool.name,
119
121
  toolCallId: call.callId,
120
- runId: params.hookContext?.runId,
121
- agentId: params.hookContext?.agentId,
122
- sessionId: params.hookContext?.sessionId,
123
- sessionKey: params.hookContext?.sessionKey,
122
+ runId: toolResultHookContext.runId,
123
+ agentId: toolResultHookContext.agentId,
124
+ sessionId: toolResultHookContext.sessionId,
125
+ sessionKey: toolResultHookContext.sessionKey,
124
126
  startArgs: args,
125
127
  error: error instanceof Error ? error.message : String(error),
126
128
  startedAt
@@ -136,6 +138,15 @@ function createCodexDynamicToolBridge(params) {
136
138
  }
137
139
  };
138
140
  }
141
+ function toToolResultHookContext(ctx) {
142
+ const { agentId, sessionId, sessionKey, runId } = ctx ?? {};
143
+ return {
144
+ ...agentId && { agentId },
145
+ ...sessionId && { sessionId },
146
+ ...sessionKey && { sessionKey },
147
+ ...runId && { runId }
148
+ };
149
+ }
139
150
  function composeAbortSignals(...signals) {
140
151
  const activeSignals = signals.filter((signal) => Boolean(signal));
141
152
  if (activeSignals.length === 0) return new AbortController().signal;
@@ -268,9 +279,17 @@ async function startOrResumeThread(params) {
268
279
  agentDir: params.params.agentDir,
269
280
  config: params.params.config
270
281
  });
271
- if (binding?.threadId) if (binding.dynamicToolsFingerprint && binding.dynamicToolsFingerprint !== dynamicToolsFingerprint) {
272
- embeddedAgentLog.debug("codex app-server dynamic tool catalog changed; starting a new thread", { threadId: binding.threadId });
273
- await clearCodexAppServerBinding(params.params.sessionFile);
282
+ let preserveExistingBinding = false;
283
+ if (binding?.threadId) if (binding.dynamicToolsFingerprint && !areDynamicToolFingerprintsCompatible(binding.dynamicToolsFingerprint, dynamicToolsFingerprint)) {
284
+ preserveExistingBinding = shouldStartTransientNoToolThread({
285
+ previous: binding.dynamicToolsFingerprint,
286
+ next: dynamicToolsFingerprint
287
+ });
288
+ if (preserveExistingBinding) embeddedAgentLog.debug("codex app-server dynamic tools unavailable for turn; starting transient thread", { threadId: binding.threadId });
289
+ else {
290
+ embeddedAgentLog.debug("codex app-server dynamic tool catalog changed; starting a new thread", { threadId: binding.threadId });
291
+ await clearCodexAppServerBinding(params.params.sessionFile);
292
+ }
274
293
  } else try {
275
294
  const authProfileId = params.params.authProfileId ?? binding.authProfileId;
276
295
  const response = assertCodexThreadResumeResponse(await params.client.request("thread/resume", buildThreadResumeParams(params.params, {
@@ -330,7 +349,7 @@ async function startOrResumeThread(params) {
330
349
  config: params.params.config
331
350
  });
332
351
  const createdAt = (/* @__PURE__ */ new Date()).toISOString();
333
- await writeCodexAppServerBinding(params.params.sessionFile, {
352
+ if (!preserveExistingBinding) await writeCodexAppServerBinding(params.params.sessionFile, {
334
353
  threadId: response.thread.id,
335
354
  cwd: params.cwd,
336
355
  authProfileId: params.params.authProfileId,
@@ -428,8 +447,14 @@ function buildTurnCollaborationMode(params) {
428
447
  function buildHeartbeatCollaborationInstructions() {
429
448
  return ["This is an OpenClaw heartbeat turn. Apply these instructions only to this heartbeat wake; ordinary chat turns should stay in Codex Default mode.", CODEX_GPT5_HEARTBEAT_PROMPT_OVERLAY].join("\n\n");
430
449
  }
450
+ function codexDynamicToolsFingerprint(dynamicTools) {
451
+ return fingerprintDynamicTools(dynamicTools);
452
+ }
453
+ function areCodexDynamicToolFingerprintsCompatible(params) {
454
+ return areDynamicToolFingerprintsCompatible(params.previous, params.next);
455
+ }
431
456
  function fingerprintDynamicTools(dynamicTools) {
432
- return JSON.stringify(dynamicTools.map(fingerprintDynamicToolSpec));
457
+ return JSON.stringify(dynamicTools.map(fingerprintDynamicToolSpec).toSorted(compareJsonFingerprint));
433
458
  }
434
459
  function fingerprintDynamicToolSpec(tool) {
435
460
  if (!isJsonObject(tool)) return stabilizeJsonValue(tool);
@@ -447,6 +472,16 @@ function stabilizeJsonValue(value) {
447
472
  for (const [key, child] of Object.entries(value).toSorted(([left], [right]) => left.localeCompare(right))) stable[key] = stabilizeJsonValue(child);
448
473
  return stable;
449
474
  }
475
+ const EMPTY_DYNAMIC_TOOLS_FINGERPRINT = JSON.stringify([]);
476
+ function areDynamicToolFingerprintsCompatible(previous, next) {
477
+ return !previous || previous === next;
478
+ }
479
+ function shouldStartTransientNoToolThread(params) {
480
+ return Boolean(params.previous && params.previous !== EMPTY_DYNAMIC_TOOLS_FINGERPRINT && params.next === EMPTY_DYNAMIC_TOOLS_FINGERPRINT);
481
+ }
482
+ function compareJsonFingerprint(left, right) {
483
+ return JSON.stringify(left).localeCompare(JSON.stringify(right));
484
+ }
450
485
  function buildDeveloperInstructions(params) {
451
486
  return [
452
487
  "You are running inside OpenClaw. Use OpenClaw dynamic tools for OpenClaw-specific integrations such as messaging, cron, sessions, media, gateway, and nodes when available.",
@@ -500,4 +535,4 @@ function resolveReasoningEffort(thinkLevel, modelId) {
500
535
  return null;
501
536
  }
502
537
  //#endregion
503
- export { startOrResumeThread as a, buildTurnStartParams as i, buildThreadResumeParams as n, createCodexDynamicToolBridge as o, buildThreadStartParams as r, applyCodexDynamicToolProfile as s, buildDeveloperInstructions as t };
538
+ export { buildTurnStartParams as a, createCodexDynamicToolBridge as c, buildThreadStartParams as i, applyCodexDynamicToolProfile as l, buildDeveloperInstructions as n, codexDynamicToolsFingerprint as o, buildThreadResumeParams as r, startOrResumeThread as s, areCodexDynamicToolFingerprintsCompatible as t };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/codex",
3
- "version": "2026.5.4-beta.1",
3
+ "version": "2026.5.4-beta.2",
4
4
  "description": "OpenClaw Codex harness and model provider plugin",
5
5
  "repository": {
6
6
  "type": "git",
@@ -8,11 +8,11 @@
8
8
  },
9
9
  "type": "module",
10
10
  "dependencies": {
11
- "@mariozechner/pi-coding-agent": "0.71.1",
11
+ "@mariozechner/pi-coding-agent": "0.73.0",
12
12
  "@openai/codex": "0.128.0",
13
13
  "ajv": "^8.20.0",
14
14
  "ws": "^8.20.0",
15
- "zod": "^4.4.1"
15
+ "zod": "^4.4.3"
16
16
  },
17
17
  "devDependencies": {
18
18
  "@openclaw/plugin-sdk": "workspace:*"
@@ -27,10 +27,10 @@
27
27
  "minHostVersion": ">=2026.5.1-beta.1"
28
28
  },
29
29
  "compat": {
30
- "pluginApi": ">=2026.5.4-beta.1"
30
+ "pluginApi": ">=2026.5.4-beta.2"
31
31
  },
32
32
  "build": {
33
- "openclawVersion": "2026.5.4-beta.1"
33
+ "openclawVersion": "2026.5.4-beta.2"
34
34
  },
35
35
  "release": {
36
36
  "publishToClawHub": true,
@@ -45,7 +45,7 @@
45
45
  "openclaw.plugin.json"
46
46
  ],
47
47
  "peerDependencies": {
48
- "openclaw": ">=2026.5.4-beta.1"
48
+ "openclaw": ">=2026.5.4-beta.2"
49
49
  },
50
50
  "peerDependenciesMeta": {
51
51
  "openclaw": {
@@ -1,22 +0,0 @@
1
- import { n as CodexAppServerRpcError } from "./client-chGfNrq5.js";
2
- //#region extensions/codex/src/app-server/capabilities.ts
3
- const CODEX_CONTROL_METHODS = {
4
- account: "account/read",
5
- compact: "thread/compact/start",
6
- feedback: "feedback/upload",
7
- listMcpServers: "mcpServerStatus/list",
8
- listSkills: "skills/list",
9
- listThreads: "thread/list",
10
- rateLimits: "account/rateLimits/read",
11
- resumeThread: "thread/resume",
12
- review: "review/start"
13
- };
14
- function describeControlFailure(error) {
15
- if (isUnsupportedControlError(error)) return "unsupported by this Codex app-server";
16
- return error instanceof Error ? error.message : String(error);
17
- }
18
- function isUnsupportedControlError(error) {
19
- return error instanceof CodexAppServerRpcError && error.code === -32601;
20
- }
21
- //#endregion
22
- export { describeControlFailure as n, CODEX_CONTROL_METHODS as t };