@openclaw/codex 2026.7.2-beta.5 → 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 (59) hide show
  1. package/README.md +2 -0
  2. package/dist/{app-server-policy-BmDgseo_.js → app-server-policy-zcBDc1JU.js} +1 -1
  3. package/dist/attempt-client-cleanup-DMLXUfa8.js +735 -0
  4. package/dist/binding-connection-I5Bo-AsX.js +33 -0
  5. package/dist/{bounded-turn-FEbUXoYT.js → bounded-turn-qgZmzy_4.js} +71 -63
  6. package/dist/{capabilities-BHRSI6Cn.js → capabilities-CybGI1oz.js} +8 -2
  7. package/dist/cli-metadata.js +1 -1
  8. package/dist/{command-formatters-ico4ZFnk.js → command-formatters-B1AEz8ZA.js} +18 -18
  9. package/dist/{command-handlers-CRmnwI2N.js → command-handlers-Db8pu_ds.js} +484 -95
  10. package/dist/{compact-dEN49UH6.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-LIt9ojep.js → dynamic-tools-BVdyWkUD.js} +2984 -1221
  14. package/dist/effective-mcp-catalog-DIIhAtOZ.js +119 -0
  15. package/dist/{event-projector-assistant-message-DTgnPPVF.js → event-projector-assistant-message-BwxV4d6N.js} +11 -23
  16. package/dist/{attempt-notifications-CMR2_fmR.js → event-projector-usage-e5huIQWu.js} +113 -29
  17. package/dist/harness.js +83 -13
  18. package/dist/image-payload-sanitizer-CnfoUPCE.js +65 -0
  19. package/dist/index.js +703 -329
  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-BA01NEez.js → models-BFlpn1Ex.js} +12 -17
  24. package/dist/native-subagent-monitor-DyTGmTUx.js +3111 -0
  25. package/dist/{plugin-app-cache-key-DSXX-rXO.js → plugin-app-cache-key-C3H2CVp6.js} +135 -42
  26. package/dist/plugin-marketplace-discovery-CzrGJdCR.js +385 -0
  27. package/dist/{computer-use-BjGylO-E.js → plugin-metadata-cache-CNJPj4_b.js} +211 -113
  28. package/dist/protocol-validators-B4F7L8Rf.js +2346 -0
  29. package/dist/{rate-limits-S_PXs0ul.js → rate-limits-DZXmOL8-.js} +17 -35
  30. package/dist/{request-CXpPennK.js → request-BRl5_UfX.js} +4 -4
  31. package/dist/{run-attempt-C5GTPJOE.js → run-attempt-P8BdxC1I.js} +1996 -5728
  32. package/dist/{runtime-artifact-C2ITXdhM.js → runtime-artifact-BVSPdd6g.js} +91 -40
  33. package/dist/{sandbox-guard-D1Wky__S.js → sandbox-guard-Cmwc9eIk.js} +10 -13
  34. package/dist/{session-binding-DlVQ-Pxs.js → session-binding-DPxIvMgE.js} +305 -271
  35. package/dist/{session-catalog-CP2oCcEb.js → session-catalog-xwNi_SDM.js} +418 -144
  36. package/dist/{session-cli-CqZ0Fp2a.js → session-cli-7hgXZDV7.js} +1 -1
  37. package/dist/session-retirement-DoMMJFKm.js +36 -0
  38. package/dist/{session-upstream-marker-QE-m5QFG.js → session-upstream-marker-CrIFX06J.js} +1 -1
  39. package/dist/{settled-turn-finalizer-CA_2QXIE.js → settled-turn-finalizer-BRWBO4MO.js} +36 -15
  40. package/dist/{shared-client-BVKE40c-.js → shared-client-kIBbGjk4.js} +721 -240
  41. package/dist/{side-question-CO12sHxo.js → side-question-9HAL26l9.js} +102 -53
  42. package/dist/{thread-lifecycle-DRg_FdzC.js → thread-lifecycle-Bu1BTDXr.js} +1355 -660
  43. package/dist/thread-ownership-6kOQHlyC.js +92 -0
  44. package/dist/thread-resume-CPrJNQVM.js +30 -0
  45. package/dist/{transcript-mirror-uKA-A4tB.js → transcript-mirror-B9gGgnJS.js} +202 -182
  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-_Vrz4WJr.js → upstream-session-fork-CE-_LdnP.js} +5 -5
  49. package/dist/{usage-UpVbdX5G.js → usage-CHlV0e-o.js} +3 -3
  50. package/dist/{web-search-provider.runtime-CaQMYDbp.js → web-search-provider.runtime-DRw2Vl42.js} +8 -9
  51. package/openclaw.plugin.json +18 -3
  52. package/package.json +6 -7
  53. package/dist/attempt-client-cleanup-Ia52yRWc.js +0 -127
  54. package/dist/conversation-control-DE7d9DOj.js +0 -287
  55. package/dist/event-projector-usage-tvgb1NCX.js +0 -69
  56. package/dist/notification-correlation-Bj_Ak_jI.js +0 -67
  57. package/dist/protocol-validators-Dm4eXZmt.js +0 -6337
  58. package/dist/realtime-voice-api-BPcA1uN9.js +0 -494
  59. package/dist/realtime-voice-api.js +0 -2
@@ -0,0 +1,119 @@
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";
4
+ import { assignMcpCatalogSafeServerNames } from "openclaw/plugin-sdk/agent-harness-runtime";
5
+ //#region extensions/codex/src/app-server/effective-mcp-catalog.ts
6
+ const MCP_STATUS_PAGE_SIZE = 100;
7
+ const MCP_STATUS_MAX_PAGES = 100;
8
+ function catalogTool(params) {
9
+ const raw = asOptionalRecord(params.raw);
10
+ const description = normalizeOptionalString(raw?.description);
11
+ const title = normalizeOptionalString(raw?.title);
12
+ return {
13
+ serverName: params.serverName,
14
+ safeServerName: params.safeServerName,
15
+ toolName: params.toolName,
16
+ ...title ? { title } : {},
17
+ ...description ? { description } : {},
18
+ inputSchema: asOptionalRecord(raw?.inputSchema) ?? { type: "object" },
19
+ fallbackDescription: description ?? params.toolName,
20
+ ...params.deniedBySession ? { deniedBySession: true } : {}
21
+ };
22
+ }
23
+ /** Converts Codex's thread-scoped status response into OpenClaw's MCP catalog shape. */
24
+ function buildCodexEffectiveMcpCatalog(statuses, toolOverrides) {
25
+ const orderedStatuses = [...new Map(statuses.map((status) => [status.name, status])).values()].toSorted((left, right) => left.name.localeCompare(right.name));
26
+ const safeNames = assignMcpCatalogSafeServerNames(orderedStatuses.map((status) => status.name));
27
+ const serverEntries = [];
28
+ const tools = [];
29
+ const sessionDeniedTools = [];
30
+ for (const status of orderedStatuses) {
31
+ const safeServerName = safeNames.get(status.name) ?? status.name;
32
+ const denialMap = toolOverrides?.mcpToolsDeny;
33
+ const deniedNames = new Set(denialMap && Object.hasOwn(denialMap, status.name) ? denialMap[status.name] : []);
34
+ const observedNames = /* @__PURE__ */ new Set();
35
+ for (const [toolName, raw] of Object.entries(status.tools).toSorted(([left], [right]) => left.localeCompare(right))) {
36
+ observedNames.add(toolName);
37
+ const deniedBySession = deniedNames.has(toolName) ? true : void 0;
38
+ const tool = catalogTool({
39
+ serverName: status.name,
40
+ safeServerName,
41
+ toolName,
42
+ raw,
43
+ ...deniedBySession ? { deniedBySession } : {}
44
+ });
45
+ if (deniedBySession) sessionDeniedTools.push(tool);
46
+ else tools.push(tool);
47
+ }
48
+ for (const toolName of [...deniedNames].toSorted()) {
49
+ if (observedNames.has(toolName)) continue;
50
+ sessionDeniedTools.push(catalogTool({
51
+ serverName: status.name,
52
+ safeServerName,
53
+ toolName,
54
+ deniedBySession: true
55
+ }));
56
+ }
57
+ serverEntries.push([status.name, {
58
+ serverName: status.name,
59
+ safeServerName,
60
+ launchSummary: "Codex native MCP connection",
61
+ toolCount: observedNames.size + [...deniedNames].filter((name) => !observedNames.has(name)).length
62
+ }]);
63
+ }
64
+ return {
65
+ version: 1,
66
+ generatedAt: Date.now(),
67
+ servers: Object.fromEntries(serverEntries),
68
+ tools,
69
+ ...sessionDeniedTools.length > 0 ? { sessionDeniedTools } : {}
70
+ };
71
+ }
72
+ async function listCodexMcpServerStatuses(client, threadId) {
73
+ const statuses = [];
74
+ const seenCursors = /* @__PURE__ */ new Set();
75
+ let cursor;
76
+ for (let page = 0; page < MCP_STATUS_MAX_PAGES; page += 1) {
77
+ const response = await client.request("mcpServerStatus/list", {
78
+ threadId,
79
+ detail: "toolsAndAuthOnly",
80
+ limit: MCP_STATUS_PAGE_SIZE,
81
+ ...cursor ? { cursor } : {}
82
+ });
83
+ statuses.push(...response.data);
84
+ cursor = response.nextCursor;
85
+ if (!cursor) return statuses;
86
+ if (seenCursors.has(cursor)) throw new Error("Codex mcpServerStatus/list repeated its pagination cursor");
87
+ seenCursors.add(cursor);
88
+ }
89
+ throw new Error("Codex mcpServerStatus/list exceeded the bounded page limit");
90
+ }
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. */
97
+ async function loadCodexEffectiveMcpCatalog(params, options) {
98
+ const binding = await options.bindingStore.read(sessionBindingIdentity({
99
+ agentId: params.agentId,
100
+ sessionId: params.sessionId,
101
+ sessionKey: params.sessionKey,
102
+ config: params.config
103
+ }));
104
+ if (!binding?.clientId) return;
105
+ const retained = retainSharedCodexAppServerClientByInstanceId(binding.clientId);
106
+ if (!retained) return;
107
+ try {
108
+ return await loadCodexEffectiveMcpCatalogFromThread({
109
+ client: retained.client,
110
+ threadId: binding.threadId,
111
+ mcpServerNames: params.mcpServerNames,
112
+ toolOverrides: params.toolOverrides
113
+ });
114
+ } finally {
115
+ retained.release();
116
+ }
117
+ }
118
+ //#endregion
119
+ export { loadCodexEffectiveMcpCatalog };
@@ -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 { V as isJsonObject } from "./shared-client-BVKE40c-.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-_Vrz4WJr.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,13 +95,17 @@ function createCodexAppServerAgentHarness(options) {
50
95
  return fingerprintCodexAppServerAuthBinding(params);
51
96
  } },
52
97
  runtimeArtifact: { validate: async (binding) => {
53
- const { validateCodexAppServerRuntimeArtifact } = await import("./runtime-artifact-C2ITXdhM.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-UpVbdX5G.js");
102
+ const { fetchCodexAppServerUsageSnapshot } = await import("./usage-CHlV0e-o.js");
58
103
  return await fetchCodexAppServerUsageSnapshot(ctx, { pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig });
59
104
  },
105
+ loadMcpToolCatalog: async (params) => {
106
+ const { loadCodexEffectiveMcpCatalog } = await import("./effective-mcp-catalog-DIIhAtOZ.js");
107
+ return await loadCodexEffectiveMcpCatalog(params, { bindingStore: options.bindingStore });
108
+ },
60
109
  supports: (ctx) => {
61
110
  const provider = ctx.provider.trim().toLowerCase();
62
111
  if (!providerIds.has(provider)) return {
@@ -65,7 +114,8 @@ function createCodexAppServerAgentHarness(options) {
65
114
  };
66
115
  if (ctx.modelProvider?.requestTransportOverrides === "present") return {
67
116
  supported: false,
68
- reason: "Codex cannot reproduce authored request transport overrides"
117
+ reason: "Codex cannot reproduce authored request transport overrides",
118
+ fallbackRuntime: "openclaw"
69
119
  };
70
120
  const preparedAuth = ctx.modelProvider?.preparedAuth;
71
121
  const runtimePolicy = ctx.modelProvider?.runtimePolicy;
@@ -95,19 +145,35 @@ function createCodexAppServerAgentHarness(options) {
95
145
  };
96
146
  },
97
147
  runAttempt: async (params) => {
98
- const { runCodexAppServerAttempt } = await import("./run-attempt-C5GTPJOE.js");
148
+ const { runCodexAppServerAttempt } = await import("./run-attempt-P8BdxC1I.js");
99
149
  return runCodexAppServerAttempt(params, {
100
150
  bindingStore: options.bindingStore,
101
151
  pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig,
102
152
  nativeHookRelay: { enabled: true }
103
153
  });
104
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
+ },
105
171
  finalizeSettledTurn: async (params) => {
106
- const { runCodexSettledTurnFinalization } = await import("./settled-turn-finalizer-CA_2QXIE.js");
172
+ const { runCodexSettledTurnFinalization } = await import("./settled-turn-finalizer-BRWBO4MO.js");
107
173
  return runCodexSettledTurnFinalization(params, { pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig });
108
174
  },
109
175
  runSideQuestion: async (params) => {
110
- const { runCodexAppServerSideQuestion } = await import("./side-question-CO12sHxo.js");
176
+ const { runCodexAppServerSideQuestion } = await import("./side-question-9HAL26l9.js");
111
177
  return runCodexAppServerSideQuestion(params, {
112
178
  bindingStore: options.bindingStore,
113
179
  pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig,
@@ -115,14 +181,14 @@ function createCodexAppServerAgentHarness(options) {
115
181
  });
116
182
  },
117
183
  compact: async (params) => {
118
- const { maybeCompactCodexAppServerSession } = await import("./compact-dEN49UH6.js");
184
+ const { maybeCompactCodexAppServerSession } = await import("./compact-LspQaGfl.js");
119
185
  return maybeCompactCodexAppServerSession(params, {
120
186
  bindingStore: options.bindingStore,
121
187
  pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig
122
188
  });
123
189
  },
124
190
  compactAfterContextEngine: async (params) => {
125
- const { maybeCompactCodexAppServerSession } = await import("./compact-dEN49UH6.js");
191
+ const { maybeCompactCodexAppServerSession } = await import("./compact-LspQaGfl.js");
126
192
  return maybeCompactCodexAppServerSession(params, {
127
193
  bindingStore: options.bindingStore,
128
194
  pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig,
@@ -131,20 +197,24 @@ function createCodexAppServerAgentHarness(options) {
131
197
  },
132
198
  reset: async (params) => {
133
199
  if (params.sessionId) {
134
- const { reclaimCurrentCodexSessionGeneration, sessionBindingIdentity } = await import("./session-binding-DlVQ-Pxs.js").then((n) => n.u);
200
+ const [{ reclaimCurrentCodexSessionGeneration, sessionBindingIdentity }, { retireCodexAppServerSessionGeneration }] = await Promise.all([import("./session-binding-DPxIvMgE.js").then((n) => n.f), import("./session-retirement-DoMMJFKm.js")]);
135
201
  const identity = sessionBindingIdentity({
136
202
  agentId: params.agentId,
137
203
  sessionId: params.sessionId,
138
204
  sessionKey: params.sessionKey
139
205
  });
140
- const resetGeneration = params.reason === "deleted" ? options.bindingStore.retireSessionGeneration.bind(options.bindingStore) : options.bindingStore.resetSessionGeneration.bind(options.bindingStore);
141
- 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();
142
212
  if (reset === "conflict") {
143
213
  if (await reclaimCurrentCodexSessionGeneration({
144
214
  bindingStore: options.bindingStore,
145
215
  identity,
146
216
  config: options.resolveConfig?.()
147
- })) reset = await resetGeneration(identity);
217
+ })) reset = await resetGeneration();
148
218
  }
149
219
  if (reset === "conflict") throw new Error(`Codex binding generation changed before session ${params.sessionId} could reset`);
150
220
  }