@openclaw/codex 2026.7.2-beta.7 → 2026.8.1-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.
Files changed (55) hide show
  1. package/README.md +2 -0
  2. package/dist/{app-server-policy-BSaO2JIT.js → app-server-policy-zcBDc1JU.js} +1 -1
  3. package/dist/attempt-client-cleanup-DMLXUfa8.js +735 -0
  4. package/dist/{notification-correlation-CU6_AnOb.js → binding-connection-I5Bo-AsX.js} +3 -37
  5. package/dist/{bounded-turn-D2ZAgZVz.js → bounded-turn-qgZmzy_4.js} +50 -49
  6. package/dist/{capabilities-BFDTVYr4.js → capabilities-CybGI1oz.js} +8 -2
  7. package/dist/cli-metadata.js +1 -1
  8. package/dist/{command-formatters-C336eRVS.js → command-formatters-B1AEz8ZA.js} +18 -18
  9. package/dist/{command-handlers-DAHUSry9.js → command-handlers-Db8pu_ds.js} +484 -95
  10. package/dist/{compact-D_uvHurS.js → compact-LspQaGfl.js} +213 -199
  11. package/dist/{conversation-binding-data-BHRpYbX3.js → conversation-binding-data-CW2GuupV.js} +6 -10
  12. package/dist/doctor-contract-api.js +40 -43
  13. package/dist/{dynamic-tools-D2gYkSBO.js → dynamic-tools-BVdyWkUD.js} +2597 -1221
  14. package/dist/{effective-mcp-catalog-Bbd98Inw.js → effective-mcp-catalog-DIIhAtOZ.js} +20 -15
  15. package/dist/{event-projector-assistant-message-DTgnPPVF.js → event-projector-assistant-message-BwxV4d6N.js} +11 -23
  16. package/dist/{attempt-notifications-AP-a-Q5k.js → event-projector-usage-e5huIQWu.js} +113 -29
  17. package/dist/harness.js +80 -14
  18. package/dist/image-payload-sanitizer-CnfoUPCE.js +65 -0
  19. package/dist/index.js +591 -240
  20. package/dist/isolated-completion-C58NbL40.js +75 -0
  21. package/dist/local-runtime-attribution-B_2mnqhb.js +19 -0
  22. package/dist/media-understanding-provider.js +5 -5
  23. package/dist/{models-BBMKU4jA.js → models-BFlpn1Ex.js} +12 -17
  24. package/dist/native-subagent-monitor-DyTGmTUx.js +3111 -0
  25. package/dist/{plugin-app-cache-key-DztPafOA.js → plugin-app-cache-key-C3H2CVp6.js} +5 -5
  26. package/dist/plugin-marketplace-discovery-CzrGJdCR.js +385 -0
  27. package/dist/{computer-use-CYEc8U3w.js → plugin-metadata-cache-CNJPj4_b.js} +105 -5
  28. package/dist/protocol-validators-B4F7L8Rf.js +2346 -0
  29. package/dist/{rate-limits-CU-gVCCS.js → rate-limits-DZXmOL8-.js} +17 -35
  30. package/dist/{request-qKh331yu.js → request-BRl5_UfX.js} +3 -3
  31. package/dist/{run-attempt-CY9WlDLc.js → run-attempt-P8BdxC1I.js} +4837 -9047
  32. package/dist/{runtime-artifact-CmtG_t1L.js → runtime-artifact-BVSPdd6g.js} +8 -23
  33. package/dist/{sandbox-guard-NuhpXmPB.js → sandbox-guard-Cmwc9eIk.js} +6 -13
  34. package/dist/{session-binding-BXpo9ymA.js → session-binding-DPxIvMgE.js} +246 -265
  35. package/dist/{session-catalog-DyOgR4WH.js → session-catalog-xwNi_SDM.js} +159 -109
  36. package/dist/{session-cli-2PZaFLRh.js → session-cli-7hgXZDV7.js} +1 -1
  37. package/dist/session-retirement-DoMMJFKm.js +36 -0
  38. package/dist/{session-upstream-marker-B6U7tLw5.js → session-upstream-marker-CrIFX06J.js} +1 -1
  39. package/dist/{settled-turn-finalizer-CXY2Z9dT.js → settled-turn-finalizer-BRWBO4MO.js} +21 -13
  40. package/dist/{shared-client-DTbvH-XV.js → shared-client-kIBbGjk4.js} +587 -223
  41. package/dist/{side-question-_ulBk1AL.js → side-question-9HAL26l9.js} +101 -52
  42. package/dist/{thread-lifecycle-DF53ogiA.js → thread-lifecycle-Bu1BTDXr.js} +694 -753
  43. package/dist/thread-ownership-6kOQHlyC.js +92 -0
  44. package/dist/thread-resume-CPrJNQVM.js +30 -0
  45. package/dist/transcript-mirror-B9gGgnJS.js +570 -0
  46. package/dist/{transport-stdio-DXgGZ7Ib.js → transport-stdio-DIImwDVS.js} +11 -0
  47. package/dist/upstream-prompt-provenance-ClRBije0.js +41 -0
  48. package/dist/{upstream-session-fork-Dy4Xvuoj.js → upstream-session-fork-CE-_LdnP.js} +5 -5
  49. package/dist/{usage-CQ6GhD5-.js → usage-CHlV0e-o.js} +3 -3
  50. package/dist/{web-search-provider.runtime-CCFhg2z5.js → web-search-provider.runtime-DRw2Vl42.js} +8 -9
  51. package/openclaw.plugin.json +18 -3
  52. package/package.json +5 -5
  53. package/dist/conversation-control-xsIeXbo4.js +0 -287
  54. package/dist/event-projector-usage-Xp4AlR2k.js +0 -86
  55. package/dist/transcript-mirror-DzsdNCf5.js +0 -6924
@@ -1,25 +1,21 @@
1
- import { d as retainSharedCodexAppServerClientByInstanceId } from "./shared-client-DTbvH-XV.js";
2
- import { d as sessionBindingIdentity } from "./session-binding-BXpo9ymA.js";
1
+ import { d as sessionBindingIdentity } from "./session-binding-DPxIvMgE.js";
2
+ import { d as retainSharedCodexAppServerClientByInstanceId } from "./shared-client-kIBbGjk4.js";
3
+ import { asOptionalRecord, normalizeOptionalString } from "openclaw/plugin-sdk/string-coerce-runtime";
3
4
  import { assignMcpCatalogSafeServerNames } from "openclaw/plugin-sdk/agent-harness-runtime";
4
5
  //#region extensions/codex/src/app-server/effective-mcp-catalog.ts
5
6
  const MCP_STATUS_PAGE_SIZE = 100;
6
7
  const MCP_STATUS_MAX_PAGES = 100;
7
- function asRecord(value) {
8
- return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
9
- }
10
- function readString(value) {
11
- return typeof value === "string" && value.trim() ? value.trim() : void 0;
12
- }
13
8
  function catalogTool(params) {
14
- const raw = asRecord(params.raw);
15
- const description = readString(raw?.description);
9
+ const raw = asOptionalRecord(params.raw);
10
+ const description = normalizeOptionalString(raw?.description);
11
+ const title = normalizeOptionalString(raw?.title);
16
12
  return {
17
13
  serverName: params.serverName,
18
14
  safeServerName: params.safeServerName,
19
15
  toolName: params.toolName,
20
- ...readString(raw?.title) ? { title: readString(raw?.title) } : {},
16
+ ...title ? { title } : {},
21
17
  ...description ? { description } : {},
22
- inputSchema: asRecord(raw?.inputSchema) ?? { type: "object" },
18
+ inputSchema: asOptionalRecord(raw?.inputSchema) ?? { type: "object" },
23
19
  fallbackDescription: description ?? params.toolName,
24
20
  ...params.deniedBySession ? { deniedBySession: true } : {}
25
21
  };
@@ -92,7 +88,12 @@ async function listCodexMcpServerStatuses(client, threadId) {
92
88
  }
93
89
  throw new Error("Codex mcpServerStatus/list exceeded the bounded page limit");
94
90
  }
95
- /** Loads MCP inventory only from the already-bound Codex process and thread. */
91
+ /** Loads the requested MCP inventory from the exact client/thread already selected for a run. */
92
+ async function loadCodexEffectiveMcpCatalogFromThread(params) {
93
+ const allowedServerNames = new Set(params.mcpServerNames);
94
+ return buildCodexEffectiveMcpCatalog((await listCodexMcpServerStatuses(params.client, params.threadId)).filter((status) => allowedServerNames.has(status.name)), params.toolOverrides);
95
+ }
96
+ /** Loads MCP inventory from the bound Codex client while retaining its lease through all pages. */
96
97
  async function loadCodexEffectiveMcpCatalog(params, options) {
97
98
  const binding = await options.bindingStore.read(sessionBindingIdentity({
98
99
  agentId: params.agentId,
@@ -104,8 +105,12 @@ async function loadCodexEffectiveMcpCatalog(params, options) {
104
105
  const retained = retainSharedCodexAppServerClientByInstanceId(binding.clientId);
105
106
  if (!retained) return;
106
107
  try {
107
- const allowedServerNames = new Set(params.mcpServerNames);
108
- return buildCodexEffectiveMcpCatalog((await listCodexMcpServerStatuses(retained.client, binding.threadId)).filter((status) => allowedServerNames.has(status.name)), params.toolOverrides);
108
+ return await loadCodexEffectiveMcpCatalogFromThread({
109
+ client: retained.client,
110
+ threadId: binding.threadId,
111
+ mcpServerNames: params.mcpServerNames,
112
+ toolOverrides: params.toolOverrides
113
+ });
109
114
  } finally {
110
115
  retained.release();
111
116
  }
@@ -1,24 +1,5 @@
1
+ import { t as resolveCodexLocalRuntimeAttribution } from "./local-runtime-attribution-B_2mnqhb.js";
1
2
  import { formatErrorMessage } from "openclaw/plugin-sdk/agent-harness-runtime";
2
- //#region extensions/codex/src/app-server/local-runtime-attribution.ts
3
- const OPENAI_PROVIDER_ID = "openai";
4
- const OPENAI_RESPONSES_API = "openai-responses";
5
- const OPENAI_CODEX_RESPONSES_API = "openai-chatgpt-responses";
6
- function normalizeRuntimeId(value) {
7
- return value?.trim().toLowerCase() ?? "";
8
- }
9
- /** Maps local Codex runtime plans onto the provider/api pair exposed to event projection. */
10
- function resolveCodexLocalRuntimeAttribution(params) {
11
- const authProfileProvider = normalizeRuntimeId(params.runtimePlan?.auth?.authProfileProviderForAuth);
12
- if (normalizeRuntimeId(params.runtimePlan?.observability.harnessId) === "codex" && authProfileProvider !== OPENAI_PROVIDER_ID && normalizeRuntimeId(params.model.provider) === OPENAI_PROVIDER_ID && normalizeRuntimeId(params.model.api) === OPENAI_RESPONSES_API) return {
13
- provider: OPENAI_PROVIDER_ID,
14
- api: OPENAI_CODEX_RESPONSES_API
15
- };
16
- return {
17
- provider: params.provider,
18
- api: params.model.api
19
- };
20
- }
21
- //#endregion
22
3
  //#region extensions/codex/src/app-server/event-projector-assistant-message.ts
23
4
  const ZERO_USAGE = {
24
5
  input: 0,
@@ -35,12 +16,19 @@ const ZERO_USAGE = {
35
16
  }
36
17
  };
37
18
  function createAssistantMessage(params, text, options) {
38
- const attribution = resolveCodexLocalRuntimeAttribution(params);
19
+ return createAttributedCodexAssistantMessage({
20
+ ...resolveCodexLocalRuntimeAttribution(params),
21
+ modelId: params.modelId
22
+ }, text, options);
23
+ }
24
+ /** Creates a Codex assistant row when a bounded call already owns attribution. */
25
+ function createAttributedCodexAssistantMessage(attribution, text, options) {
39
26
  const usage = options.tokenUsage ? {
40
27
  input: options.tokenUsage.input ?? 0,
41
28
  output: options.tokenUsage.output ?? 0,
42
29
  cacheRead: options.tokenUsage.cacheRead ?? 0,
43
30
  cacheWrite: options.tokenUsage.cacheWrite ?? 0,
31
+ ...options.tokenUsage.reasoningTokens !== void 0 ? { reasoningTokens: options.tokenUsage.reasoningTokens } : {},
44
32
  ...options.tokenUsage.contextUsage ? { contextUsage: options.tokenUsage.contextUsage } : {},
45
33
  totalTokens: options.tokenUsage.total ?? (options.tokenUsage.input ?? 0) + (options.tokenUsage.output ?? 0) + (options.tokenUsage.cacheRead ?? 0) + (options.tokenUsage.cacheWrite ?? 0),
46
34
  cost: ZERO_USAGE.cost
@@ -53,7 +41,7 @@ function createAssistantMessage(params, text, options) {
53
41
  }],
54
42
  api: attribution.api ?? "openai-chatgpt-responses",
55
43
  provider: attribution.provider,
56
- model: params.modelId,
44
+ model: attribution.modelId,
57
45
  usage,
58
46
  stopReason: options.aborted ? "aborted" : options.promptError ? "error" : "stop",
59
47
  errorMessage: options.promptError ? formatErrorMessage(options.promptError) : void 0,
@@ -98,4 +86,4 @@ function createAssistantMirrorMessage(params, title, text) {
98
86
  };
99
87
  }
100
88
  //#endregion
101
- export { resolveCodexLocalRuntimeAttribution as i, createAssistantMessage as n, createAssistantMirrorMessage as r, createAssistantCommentaryMessage as t };
89
+ export { createAttributedCodexAssistantMessage as i, createAssistantMessage as n, createAssistantMirrorMessage as r, createAssistantCommentaryMessage as t };
@@ -1,4 +1,6 @@
1
- import { W as isJsonObject } from "./shared-client-DTbvH-XV.js";
1
+ import { ct as isJsonObject } from "./shared-client-kIBbGjk4.js";
2
+ import { asFiniteNumber, asSafeIntegerInRange, readStringField } from "openclaw/plugin-sdk/string-coerce-runtime";
3
+ import { normalizeUsage } from "openclaw/plugin-sdk/agent-harness-runtime";
2
4
  import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
3
5
  //#region extensions/codex/src/app-server/attempt-notifications.ts
4
6
  /**
@@ -14,9 +16,9 @@ function describeNotificationActivity(notification) {
14
16
  if (!item) return { lastNotificationMethod: notification.method };
15
17
  return {
16
18
  lastNotificationMethod: notification.method,
17
- lastNotificationItemId: readString(item, "id"),
18
- lastNotificationItemType: readString(item, "type"),
19
- lastNotificationItemRole: readString(item, "role"),
19
+ lastNotificationItemId: readStringField(item, "id"),
20
+ lastNotificationItemType: readStringField(item, "type"),
21
+ lastNotificationItemRole: readStringField(item, "role"),
20
22
  lastAssistantTextPreview: readRawAssistantTextPreview(item)
21
23
  };
22
24
  }
@@ -59,25 +61,25 @@ function isCompletedAssistantNotification(notification) {
59
61
  if (!isJsonObject(notification.params)) return false;
60
62
  if (notification.method !== "item/completed") return false;
61
63
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
62
- return Boolean(item && readString(item, "type") === "agentMessage" && readString(item, "phase") !== "commentary");
64
+ return Boolean(item && readStringField(item, "type") === "agentMessage" && readStringField(item, "phase") !== "commentary");
63
65
  }
64
66
  /** Returns true for completed app-server reasoning items. */
65
67
  function isReasoningItemCompletionNotification(notification) {
66
68
  if (!isJsonObject(notification.params) || notification.method !== "item/completed") return false;
67
69
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
68
- return item ? readString(item, "type") === "reasoning" : false;
70
+ return item ? readStringField(item, "type") === "reasoning" : false;
69
71
  }
70
72
  /** Returns true for completed assistant commentary items. */
71
73
  function isAssistantCommentaryCompletionNotification(notification) {
72
74
  if (!isJsonObject(notification.params) || notification.method !== "item/completed") return false;
73
75
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
74
- return Boolean(item && readString(item, "type") === "agentMessage" && readString(item, "phase") === "commentary");
76
+ return Boolean(item && readStringField(item, "type") === "agentMessage" && readStringField(item, "phase") === "commentary");
75
77
  }
76
78
  /** Returns true for completed raw response reasoning items. */
77
79
  function isRawReasoningCompletionNotification(notification) {
78
80
  if (!isJsonObject(notification.params) || notification.method !== "rawResponseItem/completed") return false;
79
81
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
80
- return item ? readString(item, "type") === "reasoning" : false;
82
+ return item ? readStringField(item, "type") === "reasoning" : false;
81
83
  }
82
84
  /** Returns true for streamed app-server reasoning progress. */
83
85
  function isReasoningProgressNotification(notification) {
@@ -99,7 +101,7 @@ function shouldDisarmAssistantCompletionIdleWatch(notification) {
99
101
  function readNotificationItemId(notification) {
100
102
  if (!isJsonObject(notification.params)) return;
101
103
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
102
- return (item ? readString(item, "id") : void 0) ?? readString(notification.params, "itemId") ?? readString(notification.params, "id");
104
+ return (item ? readStringField(item, "id") : void 0) ?? readStringField(notification.params, "itemId") ?? readStringField(notification.params, "id");
103
105
  }
104
106
  /** Detects completion for an OpenClaw dynamic tool result still awaited by Codex. */
105
107
  function isPendingOpenClawDynamicToolCompletionNotification(notification, pendingOpenClawDynamicToolCompletionIds) {
@@ -107,14 +109,14 @@ function isPendingOpenClawDynamicToolCompletionNotification(notification, pendin
107
109
  const itemId = readNotificationItemId(notification);
108
110
  if (!itemId || !pendingOpenClawDynamicToolCompletionIds.has(itemId)) return false;
109
111
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
110
- const itemType = item ? readString(item, "type") : void 0;
112
+ const itemType = item ? readStringField(item, "type") : void 0;
111
113
  return itemType === void 0 || itemType === "dynamicToolCall";
112
114
  }
113
115
  /** Returns true for raw response tool-output completion notifications. */
114
116
  function isRawToolOutputCompletionNotification(notification) {
115
117
  if (notification.method !== "rawResponseItem/completed" || !isJsonObject(notification.params)) return false;
116
118
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
117
- switch (item ? readString(item, "type") : void 0) {
119
+ switch (item ? readStringField(item, "type") : void 0) {
118
120
  case "custom_tool_call_output":
119
121
  case "function_call_output": return true;
120
122
  default: return false;
@@ -123,14 +125,14 @@ function isRawToolOutputCompletionNotification(notification) {
123
125
  function isRawFunctionToolOutputCompletionNotification(notification) {
124
126
  if (notification.method !== "rawResponseItem/completed" || !isJsonObject(notification.params)) return false;
125
127
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
126
- return item ? readString(item, "type") === "function_call_output" : false;
128
+ return item ? readStringField(item, "type") === "function_call_output" : false;
127
129
  }
128
130
  /** Returns true for progress on Codex-native tool item types. */
129
131
  function isNativeToolProgressNotification(notification) {
130
132
  if (notification.method !== "item/started" && notification.method !== "item/completed" && notification.method !== "item/updated") return false;
131
133
  if (!isJsonObject(notification.params)) return false;
132
134
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
133
- switch (item ? readString(item, "type") : void 0) {
135
+ switch (item ? readStringField(item, "type") : void 0) {
134
136
  case "commandExecution":
135
137
  case "fileChange":
136
138
  case "mcpToolCall":
@@ -146,19 +148,19 @@ function isFileChangePatchUpdatedNotification(notification) {
146
148
  function isRawAssistantProgressNotification(notification) {
147
149
  if (notification.method !== "rawResponseItem/completed" || !isJsonObject(notification.params)) return false;
148
150
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
149
- return Boolean(item && readString(item, "type") === "message" && readString(item, "role") === "assistant" && readRawAssistantTextPreview(item));
151
+ return Boolean(item && readStringField(item, "type") === "message" && readStringField(item, "role") === "assistant" && readRawAssistantTextPreview(item));
150
152
  }
151
153
  /** Returns true for raw assistant completion outside commentary phase. */
152
154
  function isRawAssistantCompletionNotification(notification) {
153
155
  if (!isRawAssistantProgressNotification(notification) || !isJsonObject(notification.params)) return false;
154
156
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
155
- return Boolean(item && readString(item, "phase") !== "commentary");
157
+ return Boolean(item && readStringField(item, "phase") !== "commentary");
156
158
  }
157
159
  function readRawAssistantTextPreview(item) {
158
- if (readString(item, "role") !== "assistant" || !Array.isArray(item.content)) return;
160
+ if (readStringField(item, "role") !== "assistant" || !Array.isArray(item.content)) return;
159
161
  const text = item.content.flatMap((content) => {
160
162
  if (!isJsonObject(content)) return [];
161
- const contentText = readString(content, "text");
163
+ const contentText = readStringField(content, "text");
162
164
  return contentText ? [contentText] : [];
163
165
  }).join("\n").trim();
164
166
  if (!text) return;
@@ -179,8 +181,8 @@ function isTerminalTurnStatus(status) {
179
181
  function isCodexTurnAbortMarkerNotification(notification, options = {}) {
180
182
  if (notification.method !== "rawResponseItem/completed" || !isJsonObject(notification.params)) return false;
181
183
  const item = notification.params.item;
182
- const role = isJsonObject(item) ? readString(item, "role") : void 0;
183
- if (!isJsonObject(item) || readString(item, "type") !== "message" || role !== "user" && role !== "developer") return false;
184
+ const role = isJsonObject(item) ? readStringField(item, "role") : void 0;
185
+ if (!isJsonObject(item) || readStringField(item, "type") !== "message" || role !== "user" && role !== "developer") return false;
184
186
  const text = extractRawResponseItemText(item).trim();
185
187
  const currentPromptTexts = [options.currentPromptText, ...options.currentPromptTexts ?? []].filter(isNonEmptyString).map((prompt) => prompt.trim());
186
188
  if (role === "user" && currentPromptTexts.includes(text)) return false;
@@ -195,16 +197,12 @@ function extractRawResponseItemText(item) {
195
197
  if (!Array.isArray(content)) return "";
196
198
  return content.flatMap((entry) => {
197
199
  if (!isJsonObject(entry)) return [];
198
- const type = readString(entry, "type");
200
+ const type = readStringField(entry, "type");
199
201
  if (type !== "input_text" && type !== "text") return [];
200
- const text = readString(entry, "text");
202
+ const text = readStringField(entry, "text");
201
203
  return text ? [text] : [];
202
204
  }).join("");
203
205
  }
204
- function readString(record, key) {
205
- const value = record[key];
206
- return typeof value === "string" ? value : void 0;
207
- }
208
206
  /** Reads a typed Codex item from notification params when id/type are present. */
209
207
  function readCodexNotificationItem(params) {
210
208
  if (!isJsonObject(params) || !isJsonObject(params.item)) return;
@@ -216,13 +214,13 @@ function readRawResponseToolCallId(notification) {
216
214
  if (notification.method !== "rawResponseItem/completed" || !isJsonObject(notification.params)) return;
217
215
  const item = isJsonObject(notification.params.item) ? notification.params.item : void 0;
218
216
  if (!item) return;
219
- switch (readString(item, "type")) {
217
+ switch (readStringField(item, "type")) {
220
218
  case "custom_tool_call":
221
219
  case "function_call":
222
220
  case "local_shell_call":
223
- case "tool_search_call": return readString(item, "call_id");
221
+ case "tool_search_call": return readStringField(item, "call_id");
224
222
  case "image_generation_call":
225
- case "web_search_call": return readString(item, "id");
223
+ case "web_search_call": return readStringField(item, "id");
226
224
  default: return;
227
225
  }
228
226
  }
@@ -241,4 +239,90 @@ function isNonEmptyString(value) {
241
239
  return typeof value === "string" && value.length > 0;
242
240
  }
243
241
  //#endregion
244
- export { updateActiveTurnItemIds as S, readCodexNotificationItem as _, isCodexTurnAbortMarkerNotification as a, shouldDisarmAssistantCompletionIdleWatch as b, isPendingOpenClawDynamicToolCompletionNotification as c, isRawReasoningCompletionNotification as d, isRawToolOutputCompletionNotification as f, isTerminalTurnStatus as g, isRetryableErrorNotification as h, isAssistantCompletionReleaseNotification as i, isRawAssistantProgressNotification as l, isReasoningProgressNotification as m, describeNotificationActivity as n, isFileChangePatchUpdatedNotification as o, isReasoningItemCompletionNotification as p, isAssistantCommentaryCompletionNotification as r, isNativeToolProgressNotification as s, codexExecutionToolName as t, isRawFunctionToolOutputCompletionNotification as u, readNotificationItemId as v, updateActiveCompletionBlockerItemIds as x, readRawResponseToolCallId as y };
242
+ //#region extensions/codex/src/app-server/event-projector-usage.ts
243
+ function readTokenCount(record, key) {
244
+ return asSafeIntegerInRange(record[key], { min: 0 });
245
+ }
246
+ function readCodexThreadTokenUsage(params) {
247
+ const tokenUsage = isJsonObject(params.tokenUsage) ? params.tokenUsage : void 0;
248
+ const last = tokenUsage && isJsonObject(tokenUsage.last) ? tokenUsage.last : void 0;
249
+ return last ? normalizeCodexThreadTokenUsage(last) : void 0;
250
+ }
251
+ function readCodexThreadContextSnapshot(params) {
252
+ const tokenUsage = isJsonObject(params.tokenUsage) ? params.tokenUsage : void 0;
253
+ const last = tokenUsage && isJsonObject(tokenUsage.last) ? tokenUsage.last : void 0;
254
+ const modelContextWindow = tokenUsage ? readTokenCount(tokenUsage, "modelContextWindow") : void 0;
255
+ const activeContextTokens = last ? readTokenCount(last, "totalTokens") : void 0;
256
+ const inputTokens = last ? readTokenCount(last, "inputTokens") : void 0;
257
+ const cachedInputTokens = last ? readTokenCount(last, "cachedInputTokens") : void 0;
258
+ const cacheWriteInputTokens = last ? readTokenCount(last, "cacheWriteInputTokens") : void 0;
259
+ const outputTokens = last ? readTokenCount(last, "outputTokens") : void 0;
260
+ const reasoningOutputTokens = last ? readTokenCount(last, "reasoningOutputTokens") : void 0;
261
+ return {
262
+ ...activeContextTokens !== void 0 ? { activeContextTokens } : {},
263
+ ...cachedInputTokens !== void 0 ? { cachedInputTokens } : {},
264
+ ...cacheWriteInputTokens !== void 0 ? { cacheWriteInputTokens } : {},
265
+ ...inputTokens !== void 0 ? { inputTokens } : {},
266
+ ...modelContextWindow && modelContextWindow > 0 ? { modelContextWindow } : {},
267
+ ...outputTokens !== void 0 ? { outputTokens } : {},
268
+ ...inputTokens !== void 0 ? { promptTokens: inputTokens } : {},
269
+ ...reasoningOutputTokens !== void 0 ? { reasoningOutputTokens } : {}
270
+ };
271
+ }
272
+ function projectCodexThreadUsageUpdate(params, currentUsage, applyUsage, emitContext) {
273
+ applyUsage(readCodexThreadTokenUsage(params) ?? currentUsage);
274
+ const context = readCodexThreadContextSnapshot(params);
275
+ if (Object.keys(context).length > 0) emitContext(context);
276
+ }
277
+ function normalizeCodexThreadTokenUsage(record) {
278
+ return normalizeCodexTokenUsageBreakdown(record, "thread");
279
+ }
280
+ function normalizeCodexResponseTokenUsage(record) {
281
+ return normalizeCodexTokenUsageBreakdown(record, "response");
282
+ }
283
+ function normalizeCodexTokenUsageBreakdown(record, source) {
284
+ const readCount = source === "response" ? readTokenCount : (value, key) => asFiniteNumber(value[key]);
285
+ const totalTokens = readCount(record, "totalTokens");
286
+ const inputTokens = readCount(record, "inputTokens");
287
+ const cacheRead = readCount(record, "cachedInputTokens");
288
+ const output = readCount(record, "outputTokens");
289
+ const reasoningTokens = readCount(record, "reasoningOutputTokens");
290
+ const cacheWrite = record.cacheWriteInputTokens === void 0 && source === "response" ? 0 : readCount(record, "cacheWriteInputTokens");
291
+ if (source === "response" && (totalTokens === void 0 || inputTokens === void 0 || cacheRead === void 0 || cacheWrite === void 0 || output === void 0 || reasoningTokens === void 0 || cacheRead + cacheWrite > inputTokens || totalTokens !== inputTokens + output)) return;
292
+ const usage = normalizeUsage({
293
+ input: inputTokens === void 0 ? void 0 : Math.max(0, inputTokens - (cacheRead ?? 0) - (cacheWrite ?? 0)),
294
+ output,
295
+ cacheRead,
296
+ cacheWrite,
297
+ reasoningTokens,
298
+ total: totalTokens
299
+ });
300
+ if (!usage) return;
301
+ return {
302
+ ...usage,
303
+ contextUsage: source === "response" && inputTokens !== void 0 && totalTokens !== void 0 ? {
304
+ state: "available",
305
+ promptTokens: inputTokens,
306
+ totalTokens
307
+ } : { state: "unavailable" }
308
+ };
309
+ }
310
+ var CodexResponseCompletionProjection = class {
311
+ constructor() {
312
+ this.responseIds = /* @__PURE__ */ new Set();
313
+ }
314
+ get modelIterations() {
315
+ return this.responseIds.size;
316
+ }
317
+ clear() {
318
+ this.usage = void 0;
319
+ }
320
+ record(params) {
321
+ const responseId = readStringField(params, "responseId");
322
+ if (responseId) this.responseIds.add(responseId);
323
+ const usage = isJsonObject(params.usage) ? params.usage : void 0;
324
+ this.usage = usage ? normalizeCodexResponseTokenUsage(usage) : void 0;
325
+ }
326
+ };
327
+ //#endregion
328
+ export { readRawResponseToolCallId as C, updateActiveTurnItemIds as E, readNotificationItemId as S, updateActiveCompletionBlockerItemIds as T, isReasoningItemCompletionNotification as _, codexExecutionToolName as a, isTerminalTurnStatus as b, isAssistantCompletionReleaseNotification as c, isNativeToolProgressNotification as d, isPendingOpenClawDynamicToolCompletionNotification as f, isRawToolOutputCompletionNotification as g, isRawReasoningCompletionNotification as h, readCodexThreadContextSnapshot as i, isCodexTurnAbortMarkerNotification as l, isRawFunctionToolOutputCompletionNotification as m, normalizeCodexResponseTokenUsage as n, describeNotificationActivity as o, isRawAssistantProgressNotification as p, projectCodexThreadUsageUpdate as r, isAssistantCommentaryCompletionNotification as s, CodexResponseCompletionProjection as t, isFileChangePatchUpdatedNotification as u, isReasoningProgressNotification as v, shouldDisarmAssistantCompletionIdleWatch as w, readCodexNotificationItem as x, isRetryableErrorNotification as y };
package/dist/harness.js CHANGED
@@ -1,6 +1,24 @@
1
+ import { completeWithPreparedSimpleCompletionModel } from "openclaw/plugin-sdk/simple-completion-runtime";
1
2
  //#region extensions/codex/harness.ts
2
3
  const DEFAULT_CODEX_HARNESS_PROVIDER_IDS = /* @__PURE__ */ new Set(["codex", "openai"]);
3
4
  const SHARED_CODEX_APP_SERVER_CLIENT_DISPOSER = Symbol.for("openclaw.codexAppServerClientDisposer");
5
+ const CODEX_TOOL_POLICY_SAFE_DENY_NAMES = [
6
+ "web_fetch",
7
+ "x_search",
8
+ "memory_search",
9
+ "memory_get",
10
+ "dashboard",
11
+ "canvas",
12
+ "show_widget",
13
+ "message",
14
+ "heartbeat_respond",
15
+ "automations",
16
+ "gateway",
17
+ "skill_workshop",
18
+ "music_generate",
19
+ "video_generate",
20
+ "tts"
21
+ ];
4
22
  const CODEX_APP_SERVER_CONTEXT_ENGINE_HOST_CAPABILITIES = [
5
23
  "bootstrap",
6
24
  "assemble-before-prompt",
@@ -10,6 +28,30 @@ const CODEX_APP_SERVER_CONTEXT_ENGINE_HOST_CAPABILITIES = [
10
28
  "runtime-llm-complete",
11
29
  "thread-bootstrap-projection"
12
30
  ];
31
+ async function runCodexHostPreparedIsolatedCompletion(params) {
32
+ const timeoutSignal = AbortSignal.timeout(params.timeoutMs);
33
+ const signal = params.abortSignal ? AbortSignal.any([params.abortSignal, timeoutSignal]) : timeoutSignal;
34
+ return { assistant: await completeWithPreparedSimpleCompletionModel({
35
+ model: params.model,
36
+ auth: params.auth,
37
+ cfg: params.config,
38
+ context: {
39
+ systemPrompt: params.systemPrompt,
40
+ messages: [{
41
+ role: "user",
42
+ content: params.prompt,
43
+ timestamp: Date.now()
44
+ }],
45
+ tools: []
46
+ },
47
+ options: {
48
+ maxTokens: params.streamParams?.maxTokens,
49
+ temperature: params.streamParams?.temperature,
50
+ reasoning: params.thinkLevel,
51
+ signal
52
+ }
53
+ }) };
54
+ }
13
55
  async function disposeSharedCodexAppServerClients() {
14
56
  const dispose = globalThis[SHARED_CODEX_APP_SERVER_CLIENT_DISPOSER];
15
57
  await dispose?.();
@@ -28,14 +70,17 @@ function createCodexAppServerAgentHarness(options) {
28
70
  id: harnessRuntimeId,
29
71
  label: options?.label ?? "Codex agent harness",
30
72
  autoSelection: { providerIds: [...providerIds] },
73
+ cloudPlacement: { mode: "remote-exec" },
31
74
  delegatedExecutionPluginIds: ["voice-call"],
32
75
  contextEngineHostCapabilities: CODEX_APP_SERVER_CONTEXT_ENGINE_HOST_CAPABILITIES,
76
+ conversationToolPolicySupport: "exact",
77
+ conversationToolPolicySafeDenyTools: CODEX_TOOL_POLICY_SAFE_DENY_NAMES,
33
78
  deliveryDefaults: { visibleReplies: "message_tool" },
34
79
  authBootstrap: "harness",
35
80
  ...sessionCatalogControl && sessionRuntime ? { sessionFork: {
36
81
  upstreamKinds: ["codex-app-server"],
37
82
  fork: async (params) => {
38
- const { forkCodexUpstreamSession } = await import("./upstream-session-fork-Dy4Xvuoj.js");
83
+ const { forkCodexUpstreamSession } = await import("./upstream-session-fork-CE-_LdnP.js");
39
84
  return await forkCodexUpstreamSession(params, {
40
85
  bindingStore: options.bindingStore,
41
86
  control: sessionCatalogControl,
@@ -50,15 +95,15 @@ function createCodexAppServerAgentHarness(options) {
50
95
  return fingerprintCodexAppServerAuthBinding(params);
51
96
  } },
52
97
  runtimeArtifact: { validate: async (binding) => {
53
- const { validateCodexAppServerRuntimeArtifact } = await import("./runtime-artifact-CmtG_t1L.js");
98
+ const { validateCodexAppServerRuntimeArtifact } = await import("./runtime-artifact-BVSPdd6g.js");
54
99
  return validateCodexAppServerRuntimeArtifact(binding);
55
100
  } },
56
101
  fetchUsageSnapshot: async (ctx) => {
57
- const { fetchCodexAppServerUsageSnapshot } = await import("./usage-CQ6GhD5-.js");
102
+ const { fetchCodexAppServerUsageSnapshot } = await import("./usage-CHlV0e-o.js");
58
103
  return await fetchCodexAppServerUsageSnapshot(ctx, { pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig });
59
104
  },
60
105
  loadMcpToolCatalog: async (params) => {
61
- const { loadCodexEffectiveMcpCatalog } = await import("./effective-mcp-catalog-Bbd98Inw.js");
106
+ const { loadCodexEffectiveMcpCatalog } = await import("./effective-mcp-catalog-DIIhAtOZ.js");
62
107
  return await loadCodexEffectiveMcpCatalog(params, { bindingStore: options.bindingStore });
63
108
  },
64
109
  supports: (ctx) => {
@@ -69,7 +114,8 @@ function createCodexAppServerAgentHarness(options) {
69
114
  };
70
115
  if (ctx.modelProvider?.requestTransportOverrides === "present") return {
71
116
  supported: false,
72
- reason: "Codex cannot reproduce authored request transport overrides"
117
+ reason: "Codex cannot reproduce authored request transport overrides",
118
+ fallbackRuntime: "openclaw"
73
119
  };
74
120
  const preparedAuth = ctx.modelProvider?.preparedAuth;
75
121
  const runtimePolicy = ctx.modelProvider?.runtimePolicy;
@@ -99,19 +145,35 @@ function createCodexAppServerAgentHarness(options) {
99
145
  };
100
146
  },
101
147
  runAttempt: async (params) => {
102
- const { runCodexAppServerAttempt } = await import("./run-attempt-CY9WlDLc.js");
148
+ const { runCodexAppServerAttempt } = await import("./run-attempt-P8BdxC1I.js");
103
149
  return runCodexAppServerAttempt(params, {
104
150
  bindingStore: options.bindingStore,
105
151
  pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig,
106
152
  nativeHookRelay: { enabled: true }
107
153
  });
108
154
  },
155
+ runIsolatedCompletionV2: async (params) => {
156
+ if (params.authorization.owner === "host") {
157
+ const { authorization, ...commonParams } = params;
158
+ return runCodexHostPreparedIsolatedCompletion({
159
+ ...commonParams,
160
+ model: authorization.model,
161
+ auth: authorization.auth,
162
+ ...authorization.sourceAuthFingerprint ? { sourceAuthFingerprint: authorization.sourceAuthFingerprint } : {}
163
+ });
164
+ }
165
+ const { runCodexIsolatedCompletion } = await import("./isolated-completion-C58NbL40.js");
166
+ return runCodexIsolatedCompletion(params, { pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig });
167
+ },
168
+ runIsolatedCompletion: async (params) => {
169
+ return runCodexHostPreparedIsolatedCompletion(params);
170
+ },
109
171
  finalizeSettledTurn: async (params) => {
110
- const { runCodexSettledTurnFinalization } = await import("./settled-turn-finalizer-CXY2Z9dT.js");
172
+ const { runCodexSettledTurnFinalization } = await import("./settled-turn-finalizer-BRWBO4MO.js");
111
173
  return runCodexSettledTurnFinalization(params, { pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig });
112
174
  },
113
175
  runSideQuestion: async (params) => {
114
- const { runCodexAppServerSideQuestion } = await import("./side-question-_ulBk1AL.js");
176
+ const { runCodexAppServerSideQuestion } = await import("./side-question-9HAL26l9.js");
115
177
  return runCodexAppServerSideQuestion(params, {
116
178
  bindingStore: options.bindingStore,
117
179
  pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig,
@@ -119,14 +181,14 @@ function createCodexAppServerAgentHarness(options) {
119
181
  });
120
182
  },
121
183
  compact: async (params) => {
122
- const { maybeCompactCodexAppServerSession } = await import("./compact-D_uvHurS.js");
184
+ const { maybeCompactCodexAppServerSession } = await import("./compact-LspQaGfl.js");
123
185
  return maybeCompactCodexAppServerSession(params, {
124
186
  bindingStore: options.bindingStore,
125
187
  pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig
126
188
  });
127
189
  },
128
190
  compactAfterContextEngine: async (params) => {
129
- const { maybeCompactCodexAppServerSession } = await import("./compact-D_uvHurS.js");
191
+ const { maybeCompactCodexAppServerSession } = await import("./compact-LspQaGfl.js");
130
192
  return maybeCompactCodexAppServerSession(params, {
131
193
  bindingStore: options.bindingStore,
132
194
  pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig,
@@ -135,20 +197,24 @@ function createCodexAppServerAgentHarness(options) {
135
197
  },
136
198
  reset: async (params) => {
137
199
  if (params.sessionId) {
138
- const { reclaimCurrentCodexSessionGeneration, sessionBindingIdentity } = await import("./session-binding-BXpo9ymA.js").then((n) => n.f);
200
+ const [{ reclaimCurrentCodexSessionGeneration, sessionBindingIdentity }, { retireCodexAppServerSessionGeneration }] = await Promise.all([import("./session-binding-DPxIvMgE.js").then((n) => n.f), import("./session-retirement-DoMMJFKm.js")]);
139
201
  const identity = sessionBindingIdentity({
140
202
  agentId: params.agentId,
141
203
  sessionId: params.sessionId,
142
204
  sessionKey: params.sessionKey
143
205
  });
144
- const resetGeneration = params.reason === "deleted" ? options.bindingStore.retireSessionGeneration.bind(options.bindingStore) : options.bindingStore.resetSessionGeneration.bind(options.bindingStore);
145
- let reset = await resetGeneration(identity);
206
+ const resetGeneration = () => retireCodexAppServerSessionGeneration({
207
+ bindingStore: options.bindingStore,
208
+ identity,
209
+ mode: params.reason === "deleted" ? "retire" : "reset"
210
+ });
211
+ let reset = await resetGeneration();
146
212
  if (reset === "conflict") {
147
213
  if (await reclaimCurrentCodexSessionGeneration({
148
214
  bindingStore: options.bindingStore,
149
215
  identity,
150
216
  config: options.resolveConfig?.()
151
- })) reset = await resetGeneration(identity);
217
+ })) reset = await resetGeneration();
152
218
  }
153
219
  if (reset === "conflict") throw new Error(`Codex binding generation changed before session ${params.sessionId} could reset`);
154
220
  }
@@ -0,0 +1,65 @@
1
+ import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
2
+ import { INLINE_IMAGE_DATA_URL_PREFIX, sanitizeInlineImageDataUrl } from "openclaw/plugin-sdk/inline-image-data-url-runtime";
3
+ //#region extensions/codex/src/app-server/image-payload-sanitizer.ts
4
+ /**
5
+ * Sanitizes inline image payloads mirrored through Codex history so invalid
6
+ * base64 data becomes readable text instead of poisoning replayed transcripts.
7
+ */
8
+ const IMAGE_OMITTED_TEXT = "omitted image payload: invalid inline image data";
9
+ /** Validates and normalizes an inline image data URL for Codex history payloads. */
10
+ function sanitizeInlineImageDataUrl$1(imageUrl) {
11
+ return sanitizeInlineImageDataUrl(imageUrl);
12
+ }
13
+ /** Builds the replacement text inserted when an inline image payload is invalid. */
14
+ function invalidInlineImageText(label) {
15
+ return `[${label}] ${IMAGE_OMITTED_TEXT}`;
16
+ }
17
+ function sanitizeImageContentRecord(record, label) {
18
+ if (record.type === "image" && typeof record.data === "string") {
19
+ const mimeType = typeof record.mimeType === "string" ? record.mimeType : "image/png";
20
+ const imageUrl = sanitizeInlineImageDataUrl$1(`data:${mimeType};base64,${record.data}`);
21
+ if (!imageUrl) return {
22
+ type: "text",
23
+ text: invalidInlineImageText(label)
24
+ };
25
+ const commaIndex = imageUrl.indexOf(",");
26
+ const mime = imageUrl.slice(INLINE_IMAGE_DATA_URL_PREFIX.length, commaIndex).split(";")[0] ?? mimeType;
27
+ return {
28
+ ...record,
29
+ mimeType: mime,
30
+ data: imageUrl.slice(commaIndex + 1)
31
+ };
32
+ }
33
+ if (record.type === "inputImage" && typeof record.imageUrl === "string") {
34
+ const imageUrl = sanitizeInlineImageDataUrl$1(record.imageUrl);
35
+ return imageUrl ? {
36
+ ...record,
37
+ imageUrl
38
+ } : {
39
+ type: "inputText",
40
+ text: invalidInlineImageText(label)
41
+ };
42
+ }
43
+ if (record.type === "input_image" && typeof record.image_url === "string") {
44
+ const imageUrl = sanitizeInlineImageDataUrl$1(record.image_url);
45
+ return imageUrl ? {
46
+ ...record,
47
+ image_url: imageUrl
48
+ } : {
49
+ type: "input_text",
50
+ text: invalidInlineImageText(label)
51
+ };
52
+ }
53
+ }
54
+ /** Recursively sanitizes all Codex history image shapes while preserving unknown structure. */
55
+ function sanitizeCodexHistoryImagePayloads(value, label) {
56
+ if (Array.isArray(value)) return value.map((entry) => sanitizeCodexHistoryImagePayloads(entry, label));
57
+ if (!isRecord(value)) return value;
58
+ const imageRecord = sanitizeImageContentRecord(value, label);
59
+ if (imageRecord) return imageRecord;
60
+ const next = {};
61
+ for (const [key, child] of Object.entries(value)) next[key] = sanitizeCodexHistoryImagePayloads(child, label);
62
+ return next;
63
+ }
64
+ //#endregion
65
+ export { sanitizeCodexHistoryImagePayloads as n, sanitizeInlineImageDataUrl$1 as r, invalidInlineImageText as t };