@openclaw/codex 2026.7.1-beta.6 → 2026.7.2-beta.1

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 (46) hide show
  1. package/README.md +27 -3
  2. package/dist/app-server-policy-DVcxdse_.js +49 -0
  3. package/dist/{attempt-notifications-BGsEIIDI.js → attempt-notifications-DEv9h7iC.js} +1 -1
  4. package/dist/auth-binding-C1czuHPA.js +62 -0
  5. package/dist/capabilities-42Dfn2TV.js +33 -0
  6. package/dist/cli-metadata.js +20 -0
  7. package/dist/{app-server-policy-C968Kgin.js → command-formatters-D6ZlGNmb.js} +8 -51
  8. package/dist/{command-handlers-Dv-pzAmg.js → command-handlers-Cpl9fUWv.js} +163 -60
  9. package/dist/{compact-4mVBriKT.js → compact-FnJmiPNA.js} +40 -10
  10. package/dist/computer-use-DVzr8OP1.js +685 -0
  11. package/dist/{config-CYEDnLJ2.js → config-c48K5HP9.js} +200 -29
  12. package/dist/conversation-control-DtQ-E7mr.js +288 -0
  13. package/dist/doctor-contract-api.js +120 -81
  14. package/dist/{provider-capabilities-CDnHbmUZ.js → dynamic-tools-BMLoaTeG.js} +5246 -5140
  15. package/dist/harness.js +55 -15
  16. package/dist/index.js +1435 -265
  17. package/dist/{media-understanding-provider-BHOu9-Gg.js → media-understanding-provider-D580L0P8.js} +28 -10
  18. package/dist/media-understanding-provider.js +1 -1
  19. package/dist/{models-DDmO1zwd.js → models-DuKzZA6G.js} +1 -1
  20. package/dist/notification-correlation-DfaCm0mx.js +67 -0
  21. package/dist/plugin-app-cache-key-BKNjHMEs.js +315 -0
  22. package/dist/{protocol-2POPqAY4.js → protocol-BMifTfdW.js} +3 -1
  23. package/dist/provider-catalog.js +66 -27
  24. package/dist/provider.js +306 -1
  25. package/dist/{provider-zjPfx5Fs.js → rate-limits-Dhp04Rqo.js} +4 -261
  26. package/dist/request-DborTWgw.js +111 -0
  27. package/dist/{run-attempt-FUyOjGCV.js → run-attempt-VPVJoYDP.js} +7897 -7136
  28. package/dist/runtime-artifact-C2ITXdhM.js +488 -0
  29. package/dist/{sandbox-guard-DA2TQfZW.js → sandbox-guard-D1Wky__S.js} +10 -1
  30. package/dist/{session-binding-C1ZXdP-x.js → session-binding-BMfX1OX-.js} +247 -88
  31. package/dist/session-catalog-7H112Tr_.js +2396 -0
  32. package/dist/session-cli-B28RhCyp.js +175 -0
  33. package/dist/{shared-client-4ICy3U6d.js → shared-client-D4mFI9al.js} +1997 -1297
  34. package/dist/{side-question-N4OaDer2.js → side-question-CgJBz52s.js} +135 -67
  35. package/dist/{thread-lifecycle-qWE88Dn2.js → thread-lifecycle-BgLXzjvV.js} +747 -317
  36. package/dist/transcript-mirror-DhLwFIL4.js +485 -0
  37. package/dist/transport-stdio-DXgGZ7Ib.js +88 -0
  38. package/dist/{web-search-provider.runtime-BSlriav6.js → web-search-provider.runtime-Bs-eTn5U.js} +3 -3
  39. package/npm-shrinkwrap.json +56 -30
  40. package/openclaw.plugin.json +168 -10
  41. package/package.json +8 -6
  42. package/dist/command-rpc-eLM_mtC7.js +0 -784
  43. package/dist/computer-use-Bmaz333N.js +0 -377
  44. package/dist/notification-correlation-Bo7KB3ks.js +0 -35
  45. package/dist/plugin-app-cache-key-BrhVdeEf.js +0 -98
  46. package/dist/request-BcJyl8KL.js +0 -36
@@ -1,239 +1,22 @@
1
- import { n as flattenCodexDynamicToolFunctions, r as isJsonObject } from "./protocol-2POPqAY4.js";
2
- import { h as resolveCodexPluginsPolicy, i as codexSandboxPolicyForTurn, t as CODEX_PLUGINS_MARKETPLACE_NAME } from "./config-CYEDnLJ2.js";
3
- import { n as assertCodexThreadResumeResponse, r as assertCodexThreadStartResponse } from "./protocol-validators-dZQ-UTOa.js";
1
+ import { i as isJsonObject, r as flattenCodexDynamicToolFunctions } from "./protocol-BMifTfdW.js";
2
+ import { _ as resolveCodexPluginsPolicy, n as CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME, o as codexSandboxPolicyForTurn, t as CODEX_PLUGINS_MARKETPLACE_NAME } from "./config-c48K5HP9.js";
3
+ import { n as assertCodexThreadResumeResponse, r as assertCodexThreadStartResponse, t as assertCodexThreadForkResponse } from "./protocol-validators-dZQ-UTOa.js";
4
+ import { a as serializeCodexAppInventoryError, i as defaultCodexAppInventoryCache, t as buildCodexAppServerConnectionFingerprint } from "./plugin-app-cache-key-BKNjHMEs.js";
5
+ import { O as CodexAppServerRpcError, P as isCodexAppServerPrewriteRequestCancellationError, d as retireSharedCodexAppServerClientIfCurrent, j as isCodexAppServerConnectionClosedError, k as getCodexAppServerClientInstanceId, n as clearSharedCodexAppServerClientIfCurrentAndUnclaimed, o as isCodexAppServerStartSelectionChangedError, t as clearSharedCodexAppServerClientIfCurrent } from "./shared-client-D4mFI9al.js";
6
+ import { a as isCodexAppServerNativeAuthProfile, c as sessionBindingIdentity, i as hashCodexAppServerBindingFingerprint, n as assertCodexBindingMayBeReplaced, o as normalizeCodexAppServerBindingModelProvider, s as reclaimCurrentCodexSessionGeneration } from "./session-binding-BMfX1OX-.js";
4
7
  import { CODEX_GPT5_HEARTBEAT_PROMPT_OVERLAY } from "./prompt-overlay.js";
5
- import { a as readCodexSupportedReasoningEfforts, i as isModernCodexModel, o as resolveCodexFallbackReasoningEfforts, r as isMaxReasoningCodexModel, s as resolveCodexSupportedReasoningEffort } from "./provider-zjPfx5Fs.js";
6
- import { f as isCodexAppServerConnectionClosedError, n as clearSharedCodexAppServerClientIfCurrentAndUnclaimed, s as retireSharedCodexAppServerClientIfCurrent, t as clearSharedCodexAppServerClientIfCurrent, u as CodexAppServerRpcError } from "./shared-client-4ICy3U6d.js";
7
- import { a as normalizeCodexAppServerBindingModelProvider, i as isCodexAppServerNativeAuthProfile, o as reclaimCurrentCodexSessionGeneration, r as hashCodexAppServerBindingFingerprint, s as sessionBindingIdentity } from "./session-binding-C1ZXdP-x.js";
8
- import "node:fs/promises";
9
- import "node:path";
10
- import { isFutureDateTimestampMs, resolveDateTimestampMs, resolveExpiresAtMsFromDurationMs } from "openclaw/plugin-sdk/number-runtime";
11
- import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
8
+ import { isMaxReasoningCodexModel, isModernCodexModel, readCodexSupportedReasoningEfforts, resolveCodexFallbackReasoningEfforts, resolveCodexSupportedReasoningEffort } from "./provider.js";
9
+ import { a as projectBoundedCodexThreadHistory } from "./transcript-mirror-DhLwFIL4.js";
10
+ import { sliceUtf16Safe, truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
11
+ import * as crypto$1 from "node:crypto";
12
12
  import crypto from "node:crypto";
13
13
  import { isRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
14
- import { SKILL_WORKSHOP_TOOL_NAME, buildSkillWorkshopPromptSection, embeddedAgentLog, formatErrorMessage, isActiveHarnessContextEngine } from "openclaw/plugin-sdk/agent-harness-runtime";
15
- import { buildCodexUserMcpServersThreadConfigPatch } from "openclaw/plugin-sdk/codex-mcp-projection";
14
+ import { SKILL_WORKSHOP_TOOL_NAME, buildSkillWorkshopPromptSection, embeddedAgentLog, formatErrorMessage, isActiveHarnessContextEngine, isHostScopedAgentToolActive } from "openclaw/plugin-sdk/agent-harness-runtime";
15
+ import { buildCodexUserMcpServersThreadConfigPatchForRuntime } from "openclaw/plugin-sdk/codex-mcp-projection";
16
16
  import { listRegisteredPluginAgentPromptGuidance } from "openclaw/plugin-sdk/plugin-runtime";
17
17
  import { redactSensitiveFieldValue, redactToolPayloadText } from "openclaw/plugin-sdk/logging-core";
18
18
  import { INLINE_IMAGE_DATA_URL_PREFIX, sanitizeInlineImageDataUrl } from "openclaw/plugin-sdk/inline-image-data-url-runtime";
19
19
  import { isDiagnosticFlagEnabled } from "openclaw/plugin-sdk/diagnostic-runtime";
20
- const CODEX_TARGETED_APP_INVENTORY_LIMIT = 1e3;
21
- const MAX_SERIALIZED_ERROR_MESSAGE_LENGTH = 500;
22
- /** In-memory app inventory cache with coalesced refreshes per key. */
23
- var CodexAppInventoryCache = class {
24
- constructor(options = {}) {
25
- this.entries = /* @__PURE__ */ new Map();
26
- this.inFlight = /* @__PURE__ */ new Map();
27
- this.refreshTokens = /* @__PURE__ */ new Map();
28
- this.diagnostics = /* @__PURE__ */ new Map();
29
- this.revision = 0;
30
- this.ttlMs = options.ttlMs ?? 36e5;
31
- }
32
- /** Reads a snapshot and schedules refresh when missing, stale, or forced. */
33
- read(params) {
34
- const nowMs = resolveDateTimestampMs(params.nowMs);
35
- const entry = this.entries.get(params.key);
36
- if (!entry) {
37
- const refreshScheduled = params.suppressRefresh ? false : this.scheduleRefresh(params);
38
- return {
39
- state: "missing",
40
- key: params.key,
41
- revision: this.revision,
42
- refreshScheduled,
43
- ...this.diagnostics.get(params.key) ? { diagnostic: this.diagnostics.get(params.key) } : {}
44
- };
45
- }
46
- const state = entry.invalidated || !isFutureDateTimestampMs(entry.expiresAtMs, { nowMs }) ? "stale" : "fresh";
47
- const refreshScheduled = state === "fresh" && !params.forceRefetch ? false : this.scheduleRefresh(params);
48
- return {
49
- state,
50
- key: params.key,
51
- revision: entry.revision,
52
- snapshot: stripEntryState(entry),
53
- refreshScheduled,
54
- ...entry.lastError ? { diagnostic: entry.lastError } : {}
55
- };
56
- }
57
- /** Forces or joins an immediate refresh for a cache key. */
58
- refreshNow(params) {
59
- return this.refresh(params);
60
- }
61
- /** Marks a key stale and records the reason as a diagnostic. */
62
- invalidate(key, reason, nowMs = Date.now()) {
63
- this.revision += 1;
64
- const diagnostic = {
65
- message: reason,
66
- atMs: nowMs
67
- };
68
- const entry = this.entries.get(key);
69
- if (entry) {
70
- entry.invalidated = true;
71
- entry.lastError = diagnostic;
72
- entry.revision = this.revision;
73
- } else this.diagnostics.set(key, diagnostic);
74
- return this.revision;
75
- }
76
- /** Clears all cached snapshots, diagnostics, in-flight requests, and revision state. */
77
- clear() {
78
- this.entries.clear();
79
- this.inFlight.clear();
80
- this.refreshTokens.clear();
81
- this.diagnostics.clear();
82
- this.revision = 0;
83
- }
84
- /** Returns the monotonically increasing cache revision. */
85
- getRevision() {
86
- return this.revision;
87
- }
88
- scheduleRefresh(params) {
89
- if (this.inFlight.has(params.key) && !params.forceRefetch) return true;
90
- const promise = this.refresh(params);
91
- this.inFlight.set(params.key, promise);
92
- promise.catch(() => void 0);
93
- return true;
94
- }
95
- async refresh(params) {
96
- const existing = this.inFlight.get(params.key);
97
- if (existing && !params.forceRefetch) return existing;
98
- const refreshToken = (this.refreshTokens.get(params.key) ?? 0) + 1;
99
- this.refreshTokens.set(params.key, refreshToken);
100
- const promise = this.refreshUncoalesced(params, refreshToken);
101
- this.inFlight.set(params.key, promise);
102
- try {
103
- return await promise;
104
- } finally {
105
- if (this.inFlight.get(params.key) === promise) this.inFlight.delete(params.key);
106
- }
107
- }
108
- async refreshUncoalesced(params, refreshToken) {
109
- const nowMs = resolveDateTimestampMs(params.nowMs);
110
- try {
111
- const apps = await listAllApps(params.request, params.forceRefetch ?? false, params.targetAppIds);
112
- this.revision += 1;
113
- const expiresAtMs = resolveExpiresAtMsFromDurationMs(this.ttlMs, { nowMs }) ?? 0;
114
- const snapshot = {
115
- key: params.key,
116
- apps,
117
- fetchedAtMs: nowMs,
118
- expiresAtMs,
119
- revision: this.revision
120
- };
121
- if (this.refreshTokens.get(params.key) === refreshToken) {
122
- this.entries.set(params.key, {
123
- ...snapshot,
124
- invalidated: false
125
- });
126
- this.diagnostics.delete(params.key);
127
- }
128
- return snapshot;
129
- } catch (error) {
130
- const diagnostic = {
131
- message: sanitizeErrorMessage(error instanceof Error ? error.message : String(error)),
132
- atMs: nowMs
133
- };
134
- this.diagnostics.set(params.key, diagnostic);
135
- const entry = this.entries.get(params.key);
136
- if (entry) entry.lastError = diagnostic;
137
- embeddedAgentLog.warn("codex app inventory refresh failed", {
138
- forceRefetch: params.forceRefetch === true,
139
- keyFingerprint: fingerprintInventoryCacheKey(params.key),
140
- error: serializeCodexAppInventoryError(error)
141
- });
142
- throw error;
143
- }
144
- }
145
- };
146
- /** Serializes a refresh failure without leaking large or sensitive error data. */
147
- function serializeCodexAppInventoryError(error) {
148
- const record = isRecord(error) ? error : void 0;
149
- const data = record && "data" in record ? redactErrorData(record.data) : void 0;
150
- return {
151
- name: error instanceof Error ? error.name : typeof record?.name === "string" ? record.name : void 0,
152
- message: sanitizeErrorMessage(error instanceof Error ? error.message : String(error)),
153
- ...typeof record?.code === "number" ? { code: record.code } : {},
154
- ...data !== void 0 ? { data } : {}
155
- };
156
- }
157
- /** Shared app inventory cache used by Codex app-server runtime paths. */
158
- const defaultCodexAppInventoryCache = new CodexAppInventoryCache();
159
- /** Builds a stable cache key from build versions and runtime identity fields. */
160
- function buildCodexAppInventoryCacheKey(input, openClawVersion, codexPluginVersion) {
161
- return JSON.stringify({
162
- openClawVersion,
163
- codexPluginVersion,
164
- codexHome: input.codexHome ?? null,
165
- endpoint: input.endpoint ?? null,
166
- runtimeIdentity: normalizeRuntimeIdentityForCacheKey(input.runtimeIdentity),
167
- authProfileId: input.authProfileId ?? null,
168
- accountId: input.accountId ?? null,
169
- envApiKeyFingerprint: input.envApiKeyFingerprint ?? null,
170
- appServerVersion: input.appServerVersion ?? null
171
- });
172
- }
173
- function normalizeRuntimeIdentityForCacheKey(value) {
174
- if (!value) return null;
175
- const entries = Object.entries(value).flatMap(([key, rawValue]) => {
176
- const normalized = rawValue?.trim();
177
- return normalized ? [[key, normalized]] : [];
178
- }).toSorted(([left], [right]) => left.localeCompare(right));
179
- return entries.length > 0 ? Object.fromEntries(entries) : null;
180
- }
181
- async function listAllApps(request, forceRefetch, targetAppIds = []) {
182
- const apps = [];
183
- const targetIds = new Set(targetAppIds.filter(Boolean));
184
- const remainingTargetIds = new Set(targetIds);
185
- const seenCursors = /* @__PURE__ */ new Set();
186
- let cursor;
187
- do {
188
- const response = await request("app/list", {
189
- cursor,
190
- limit: targetIds.size > 0 ? CODEX_TARGETED_APP_INVENTORY_LIMIT : 100,
191
- forceRefetch
192
- });
193
- apps.push(...response.data);
194
- for (const app of response.data) remainingTargetIds.delete(app.id);
195
- if (targetIds.size > 0 && remainingTargetIds.size === 0) break;
196
- cursor = response.nextCursor;
197
- if (cursor && seenCursors.has(cursor)) throw new Error(`app/list returned repeated cursor ${cursor}`);
198
- if (cursor) seenCursors.add(cursor);
199
- } while (cursor);
200
- return apps;
201
- }
202
- function stripEntryState(entry) {
203
- const { invalidated: _invalidated, ...snapshot } = entry;
204
- return snapshot;
205
- }
206
- function fingerprintInventoryCacheKey(key) {
207
- let hash = 0;
208
- for (let index = 0; index < key.length; index += 1) hash = hash * 31 + key.charCodeAt(index) >>> 0;
209
- return hash.toString(16).padStart(8, "0");
210
- }
211
- function redactErrorData(value, depth = 0) {
212
- if (value === void 0) return;
213
- if (value === null || typeof value === "boolean" || typeof value === "number") return value;
214
- if (depth > 6) return "[truncated]";
215
- if (Array.isArray(value)) return value.map((entry) => redactErrorData(entry, depth + 1) ?? null);
216
- if (isRecord(value)) {
217
- const redacted = {};
218
- for (const [key, entry] of Object.entries(value)) redacted[key] = isSensitiveErrorDataKey(key) ? "<redacted>" : redactErrorData(entry, depth + 1) ?? null;
219
- return redacted;
220
- }
221
- if (typeof value === "string" && value.length > 500) return `${truncateUtf16Safe(value, 500)}...`;
222
- if (typeof value === "string") return value;
223
- if (typeof value === "bigint") return value.toString();
224
- if (typeof value === "symbol") return value.description ? `Symbol(${value.description})` : "Symbol()";
225
- if (typeof value === "function") return value.name ? `[function ${value.name}]` : "[function]";
226
- return "[unserializable]";
227
- }
228
- function sanitizeErrorMessage(message) {
229
- const htmlStart = message.search(/<html[\s>]/i);
230
- const redacted = (htmlStart >= 0 ? `${message.slice(0, htmlStart).trimEnd()} [HTML response body omitted]` : message).replace(/([?&][^=\s"'<>]*(?:api[_-]?key|authorization|cookie|credential|password|secret|token|tk)[^=\s"'<>]*=)[^&\s"'<>]+/gi, "$1<redacted>");
231
- return redacted.length > MAX_SERIALIZED_ERROR_MESSAGE_LENGTH ? `${redacted.slice(0, MAX_SERIALIZED_ERROR_MESSAGE_LENGTH)}...` : redacted;
232
- }
233
- function isSensitiveErrorDataKey(key) {
234
- return /api[_-]?key|authorization|cookie|credential|password|secret|token/i.test(key);
235
- }
236
- //#endregion
237
20
  //#region extensions/codex/src/app-server/plugin-inventory.ts
238
21
  /**
239
22
  * Reads Codex plugin marketplace state and app inventory to decide which
@@ -252,19 +35,21 @@ async function readCodexPluginInventory(params) {
252
35
  }]
253
36
  };
254
37
  const appInventory = readCachedAppInventory(params);
255
- const listed = await params.request("plugin/list", { cwds: [] });
256
- const marketplaceEntry = listed.marketplaces.find(isOpenAiCuratedMarketplace);
257
- if (!marketplaceEntry) return {
258
- policy,
259
- records: [],
260
- diagnostics: policy.pluginPolicies.filter((pluginPolicy) => pluginPolicy.enabled).map((pluginPolicy) => ({
261
- code: "marketplace_missing",
262
- plugin: pluginPolicy,
263
- message: `Codex marketplace ${CODEX_PLUGINS_MARKETPLACE_NAME} was not found.`
264
- })),
265
- ...appInventory ? { appInventory } : {}
266
- };
267
- let marketplace = marketplaceRef(marketplaceEntry);
38
+ const curatedListed = await params.request("plugin/list", { cwds: [] });
39
+ const shouldListWorkspacePlugins = policy.pluginPolicies.some((pluginPolicy) => pluginPolicy.enabled && pluginPolicy.marketplaceName === "workspace-directory");
40
+ let workspaceListResult;
41
+ if (shouldListWorkspacePlugins) try {
42
+ workspaceListResult = {
43
+ kind: "listed",
44
+ response: await params.request("plugin/list", {
45
+ cwds: [],
46
+ marketplaceKinds: [CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME]
47
+ })
48
+ };
49
+ } catch (error) {
50
+ if (!(error instanceof CodexAppServerRpcError)) throw error;
51
+ workspaceListResult = { kind: "rejected" };
52
+ }
268
53
  const diagnostics = [];
269
54
  const records = [];
270
55
  if (appInventory?.state === "missing") diagnostics.push({
@@ -277,19 +62,27 @@ async function readCodexPluginInventory(params) {
277
62
  });
278
63
  for (const pluginPolicy of policy.pluginPolicies) {
279
64
  if (!pluginPolicy.enabled) continue;
280
- const resolvedPlugin = findOpenAiCuratedMarketplacePlugin(listed, pluginPolicy.pluginName);
65
+ const listed = pluginPolicy.marketplaceName === "workspace-directory" ? workspaceListResult?.kind === "listed" ? workspaceListResult.response : void 0 : curatedListed;
66
+ const hasMarketplace = pluginPolicy.marketplaceName === "workspace-directory" ? listed?.marketplaces.some((entry) => entry.name === CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME) === true : listed?.marketplaces.some(isOpenAiCuratedMarketplace) === true;
67
+ if (!listed || !hasMarketplace) {
68
+ diagnostics.push({
69
+ code: "marketplace_missing",
70
+ plugin: pluginPolicy,
71
+ message: `Codex marketplace ${pluginPolicy.marketplaceName} was not found.`
72
+ });
73
+ continue;
74
+ }
75
+ const resolvedPlugin = pluginPolicy.marketplaceName === "workspace-directory" ? findWorkspaceMarketplacePlugin(listed, pluginPolicy.pluginName) : findOpenAiCuratedMarketplacePlugin(listed, pluginPolicy.pluginName);
281
76
  if (!resolvedPlugin) {
282
77
  diagnostics.push({
283
78
  code: "plugin_missing",
284
79
  plugin: pluginPolicy,
285
- message: `${pluginPolicy.pluginName} was not found in ${CODEX_PLUGINS_MARKETPLACE_NAME}.`
80
+ message: `${pluginPolicy.pluginName} was not found in ${pluginPolicy.marketplaceName}.`
286
81
  });
287
82
  continue;
288
83
  }
289
84
  const { summary } = resolvedPlugin;
290
- const pluginMarketplace = marketplaceRef(resolvedPlugin.marketplace);
291
- if (records.length === 0) marketplace = pluginMarketplace;
292
- const detail = await readPluginDetail(params, pluginMarketplace, pluginPolicy, summary, diagnostics);
85
+ const detail = await readPluginDetail(params, marketplaceRef(resolvedPlugin.marketplace, pluginPolicy.marketplaceName), pluginPolicy, summary, diagnostics);
293
86
  const ownedAppIds = detail?.apps.map((app) => app.id).filter(Boolean).toSorted() ?? [];
294
87
  const appOwnership = resolveAppOwnership({
295
88
  detail,
@@ -324,7 +117,6 @@ async function readCodexPluginInventory(params) {
324
117
  }
325
118
  return {
326
119
  policy,
327
- marketplace,
328
120
  records,
329
121
  diagnostics,
330
122
  ...appInventory ? { appInventory } : {}
@@ -334,7 +126,7 @@ async function readCodexPluginInventory(params) {
334
126
  function findOpenAiCuratedPluginSummary(listed, pluginName) {
335
127
  const resolved = findOpenAiCuratedMarketplacePlugin(listed, pluginName);
336
128
  return resolved ? {
337
- marketplace: marketplaceRef(resolved.marketplace),
129
+ marketplace: marketplaceRef(resolved.marketplace, CODEX_PLUGINS_MARKETPLACE_NAME),
338
130
  summary: resolved.summary
339
131
  } : void 0;
340
132
  }
@@ -358,6 +150,14 @@ function readCachedAppInventory(params) {
358
150
  }
359
151
  async function readPluginDetail(params, marketplace, pluginPolicy, summary, diagnostics) {
360
152
  if (params.readPluginDetails === false) return;
153
+ if (marketplace.name === "workspace-directory" && marketplace.remoteMarketplaceName && !summary.remotePluginId) {
154
+ diagnostics.push({
155
+ code: "plugin_detail_unavailable",
156
+ plugin: pluginPolicy,
157
+ message: `${pluginPolicy.pluginName} detail unavailable: Codex did not return a remote plugin id.`
158
+ });
159
+ return;
160
+ }
361
161
  try {
362
162
  return (await params.request("plugin/read", pluginReadParams(marketplace, marketplace.remoteMarketplaceName && summary.remotePluginId ? summary.remotePluginId : pluginPolicy.pluginName))).plugin;
363
163
  } catch (error) {
@@ -416,15 +216,23 @@ function findOpenAiCuratedMarketplacePlugin(listed, pluginName) {
416
216
  };
417
217
  }
418
218
  }
219
+ function findWorkspaceMarketplacePlugin(listed, pluginName) {
220
+ const marketplace = listed.marketplaces.find((entry) => entry.name === CODEX_PLUGINS_WORKSPACE_MARKETPLACE_NAME);
221
+ const summary = marketplace?.plugins.find((plugin) => plugin.id === pluginName);
222
+ return marketplace && summary ? {
223
+ marketplace,
224
+ summary
225
+ } : void 0;
226
+ }
419
227
  function pluginNameFromPluginId(pluginId, marketplaceName) {
420
228
  const trimmed = pluginId.trim();
421
229
  if (!trimmed) return;
422
230
  const marketplaceSuffix = `@${marketplaceName}`;
423
231
  return (trimmed.endsWith(marketplaceSuffix) ? trimmed.slice(0, -marketplaceSuffix.length) : trimmed).split("/").at(-1)?.trim() || void 0;
424
232
  }
425
- function marketplaceRef(marketplace) {
233
+ function marketplaceRef(marketplace, name) {
426
234
  return {
427
- name: CODEX_PLUGINS_MARKETPLACE_NAME,
235
+ name,
428
236
  ...marketplace.path ? { path: marketplace.path } : {},
429
237
  ...!marketplace.path ? { remoteMarketplaceName: marketplace.name } : {}
430
238
  };
@@ -434,9 +242,9 @@ function isOpenAiCuratedMarketplace(marketplace) {
434
242
  }
435
243
  //#endregion
436
244
  //#region extensions/codex/src/app-server/plugin-activation.ts
437
- /** Installs/enables a configured Codex plugin and refreshes plugin/app state. */
245
+ /** Activates a curated plugin or rejects a workspace plugin that is not already active. */
438
246
  async function ensureCodexPluginActivation(params) {
439
- if (params.identity.marketplaceName !== "openai-curated") return activationFailure(params.identity, "marketplace_missing", { message: "Only openai-curated plugins can be activated." });
247
+ if (params.identity.marketplaceName === "workspace-directory") return activationFailure(params.identity, "disabled", { message: "workspace-directory plugins must be installed and enabled outside OpenClaw before use." });
440
248
  const listed = await params.request("plugin/list", { cwds: [] });
441
249
  const resolved = findOpenAiCuratedPluginSummary(listed, params.identity.pluginName);
442
250
  if (!resolved) {
@@ -1033,17 +841,19 @@ async function unsubscribeCodexThreadBestEffort(client, params) {
1033
841
  * potentially wedged app-server connection.
1034
842
  */
1035
843
  async function retireCodexAppServerClientAfterTimedOutTurn(client, params) {
1036
- const retiredSharedClient = retireSharedCodexAppServerClientIfCurrent(client);
844
+ const retiredSharedClient = retireSharedCodexAppServerClientIfCurrent(client, { failActiveLeases: params.suspectPhysicalClient });
1037
845
  const detachedSharedClient = Boolean(retiredSharedClient);
1038
- interruptCodexTurnBestEffort(client, {
1039
- threadId: params.threadId,
1040
- turnId: params.turnId,
1041
- timeoutMs: CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS
1042
- });
1043
- await unsubscribeCodexThreadBestEffort(client, {
1044
- threadId: params.threadId,
1045
- timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS
1046
- });
846
+ if (!(params.suspectPhysicalClient && (retiredSharedClient?.closed ?? false))) {
847
+ interruptCodexTurnBestEffort(client, {
848
+ threadId: params.threadId,
849
+ turnId: params.turnId,
850
+ timeoutMs: CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS
851
+ });
852
+ await unsubscribeCodexThreadBestEffort(client, {
853
+ threadId: params.threadId,
854
+ timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS
855
+ });
856
+ }
1047
857
  let closedClient = retiredSharedClient?.closed ?? false;
1048
858
  if (!detachedSharedClient) {
1049
859
  const close = client.close;
@@ -1128,7 +938,7 @@ function resolveCodexContextEngineProjectionReserveTokens(params) {
1128
938
  const compaction = asRecord(asRecord(asRecord(params.config)?.agents)?.defaults)?.compaction;
1129
939
  const configuredReserveTokens = toNonNegativeInt(asRecord(compaction)?.reserveTokens);
1130
940
  const configuredReserveTokensFloor = toNonNegativeInt(asRecord(compaction)?.reserveTokensFloor);
1131
- if (configuredReserveTokens !== void 0) return Math.max(configuredReserveTokens, configuredReserveTokensFloor ?? 2e4);
941
+ if (configuredReserveTokens !== void 0) return Math.max(configuredReserveTokens, configuredReserveTokensFloor ?? DEFAULT_CODEX_PROJECTION_RESERVE_TOKENS);
1132
942
  if (configuredReserveTokensFloor !== void 0) return configuredReserveTokensFloor;
1133
943
  }
1134
944
  /** Fits projected context prompts under Codex app-server turn/start text limits. */
@@ -1311,7 +1121,9 @@ function resolveTextPartMaxChars(maxRenderedContextChars) {
1311
1121
  return Math.min(MAX_TEXT_PART_CHARS, Math.max(DEFAULT_TEXT_PART_CHARS, Math.floor(maxRenderedContextChars / 4)));
1312
1122
  }
1313
1123
  function truncateText(text, maxChars) {
1314
- return text.length > maxChars ? `${text.slice(0, maxChars)}\n[truncated ${text.length - maxChars} chars]` : text;
1124
+ if (text.length <= maxChars) return text;
1125
+ const truncated = truncateUtf16Safe(text, maxChars);
1126
+ return `${truncated}\n[truncated ${text.length - truncated.length} chars]`;
1315
1127
  }
1316
1128
  function truncateOlderContext(text, maxChars) {
1317
1129
  if (text.length <= maxChars) return text;
@@ -1322,15 +1134,7 @@ function truncateOlderContext(text, maxChars) {
1322
1134
  marker = buildMarker(text.length - tailChars);
1323
1135
  if (marker.length >= maxChars) return marker.slice(0, maxChars);
1324
1136
  tailChars = maxChars - marker.length;
1325
- return `${marker}${sliceTailFromCodePointBoundary(text, tailChars).trimStart()}`;
1326
- }
1327
- function sliceTailFromCodePointBoundary(text, tailChars) {
1328
- let start = text.length - tailChars;
1329
- if (start > 0 && start < text.length) {
1330
- const code = text.charCodeAt(start);
1331
- if (code >= 56320 && code <= 57343) start += 1;
1332
- }
1333
- return text.slice(start);
1137
+ return `${marker}${sliceUtf16Safe(text, -tailChars).trimStart()}`;
1334
1138
  }
1335
1139
  //#endregion
1336
1140
  //#region extensions/codex/src/app-server/dynamic-tool-profile.ts
@@ -1357,6 +1161,10 @@ function normalizeCodexDynamicToolName(name) {
1357
1161
  const normalized = name.trim().toLowerCase();
1358
1162
  return DYNAMIC_TOOL_NAME_ALIASES[normalized] ?? normalized;
1359
1163
  }
1164
+ /** True only for the host-scoped OpenClaw run's exact tool contract. */
1165
+ function isSystemAgentOnlyCodexDynamicToolAllowlist(toolsAllow) {
1166
+ return toolsAllow?.length === 1 && normalizeCodexDynamicToolName(toolsAllow[0] ?? "") === "openclaw";
1167
+ }
1360
1168
  /** Returns true for private QA runs that force the Codex runtime profile. */
1361
1169
  function isForcedPrivateQaCodexRuntime(env = process.env) {
1362
1170
  return env.OPENCLAW_BUILD_PRIVATE_QA === "1" && env.OPENCLAW_QA_FORCE_RUNTIME?.trim().toLowerCase() === "codex";
@@ -1481,6 +1289,7 @@ async function resumeCodexAppServerThread(params) {
1481
1289
  }));
1482
1290
  assertCodexThreadResumeSubscription(threadId, response.thread.id);
1483
1291
  } catch (error) {
1292
+ if (isCodexAppServerStartSelectionChangedError(error) || isCodexAppServerPrewriteRequestCancellationError(error)) throw error;
1484
1293
  if (error instanceof CodexAppServerRpcError) throw error;
1485
1294
  try {
1486
1295
  await params.abandonClient();
@@ -1573,7 +1382,21 @@ var CodexThreadBindingConflictError = class extends Error {
1573
1382
  this.name = "CodexThreadBindingConflictError";
1574
1383
  }
1575
1384
  };
1385
+ var CodexRingZeroAttestationError = class extends Error {
1386
+ constructor(cause) {
1387
+ super("Codex ring-zero MCP attestation failed", { cause });
1388
+ this.name = "CodexRingZeroAttestationError";
1389
+ }
1390
+ };
1391
+ var CodexThreadBindingConflictAfterCleanupError = class extends CodexThreadBindingConflictError {};
1392
+ var CodexAdoptedThreadActiveError = class extends Error {
1393
+ constructor() {
1394
+ super("Codex session became active in another runner; wait for it to finish before continuing");
1395
+ this.name = "CodexAdoptedThreadActiveError";
1396
+ }
1397
+ };
1576
1398
  const CODEX_NATIVE_PERSONALITY_NONE = "none";
1399
+ const CODEX_RING_ZERO_BASE_INSTRUCTIONS = "";
1577
1400
  const CODEX_CODE_MODE_THREAD_CONFIG = {
1578
1401
  "features.code_mode": true,
1579
1402
  "features.code_mode_only": false,
@@ -1585,6 +1408,64 @@ const CODEX_CODE_MODE_DISABLED_THREAD_CONFIG = {
1585
1408
  };
1586
1409
  const CODEX_LIGHTWEIGHT_CONTEXT_THREAD_CONFIG = { project_doc_max_bytes: 0 };
1587
1410
  const CODEX_TOOL_SEARCH_UNSUPPORTED_THREAD_CONFIG = { "features.multi_agent": false };
1411
+ const CODEX_RING_ZERO_THREAD_CONFIG = {
1412
+ "features.apps": false,
1413
+ "features.current_time_reminder": false,
1414
+ "features.deferred_executor": false,
1415
+ "features.enable_fanout": false,
1416
+ "features.goals": false,
1417
+ "features.hooks": false,
1418
+ "features.image_generation": false,
1419
+ "features.memories": false,
1420
+ "features.multi_agent": false,
1421
+ "features.multi_agent_v2": false,
1422
+ "features.plugins": false,
1423
+ "features.standalone_web_search": false,
1424
+ "features.token_budget": false,
1425
+ "orchestrator.mcp.enabled": false,
1426
+ "orchestrator.skills.enabled": false,
1427
+ "tools.experimental_request_user_input.enabled": false,
1428
+ hooks: {
1429
+ PreToolUse: [],
1430
+ PermissionRequest: [],
1431
+ PostToolUse: [],
1432
+ PreCompact: [],
1433
+ PostCompact: [],
1434
+ SessionStart: [],
1435
+ UserPromptSubmit: [],
1436
+ SubagentStart: [],
1437
+ SubagentStop: [],
1438
+ Stop: []
1439
+ },
1440
+ project_doc_max_bytes: 0,
1441
+ notify: [],
1442
+ web_search: "disabled"
1443
+ };
1444
+ const CODEX_RING_ZERO_RESTRICTED_FEATURES = /* @__PURE__ */ new Set([
1445
+ "apps",
1446
+ "code_mode",
1447
+ "code_mode_only",
1448
+ "current_time_reminder",
1449
+ "deferred_executor",
1450
+ "enable_fanout",
1451
+ "goals",
1452
+ "hooks",
1453
+ "image_generation",
1454
+ "memories",
1455
+ "multi_agent",
1456
+ "multi_agent_v2",
1457
+ "plugins",
1458
+ "standalone_web_search",
1459
+ "token_budget"
1460
+ ]);
1461
+ const CODEX_RING_ZERO_OVERRIDABLE_LAYER_TYPES = /* @__PURE__ */ new Set([
1462
+ "mdm",
1463
+ "system",
1464
+ "enterpriseManaged",
1465
+ "user",
1466
+ "project",
1467
+ "sessionFlags"
1468
+ ]);
1588
1469
  const CODEX_THREAD_LIFECYCLE_TIMING_WARN_TOTAL_MS = 1e3;
1589
1470
  const CODEX_THREAD_LIFECYCLE_TIMING_WARN_STAGE_MS = 500;
1590
1471
  function shouldWarnCodexThreadLifecycleTimingSummary(summary, options = {}) {
@@ -1696,10 +1577,29 @@ async function startOrResumeThread(params) {
1696
1577
  })).threadConfig);
1697
1578
  const networkProxyConfigFingerprint = params.appServer.networkProxy?.configFingerprint;
1698
1579
  const contextEngineBinding = lifecycleTiming.measureSync("context-engine-binding", () => buildContextEngineBinding(params.params, params.contextEngineProjection));
1699
- const userMcpServersConfigPatch = params.userMcpServersEnabled === false ? void 0 : buildCodexUserMcpServersThreadConfigPatch(params.params.config, { agentId: params.agentId ?? params.params.agentId });
1580
+ const userMcpServersConfigPatch = params.userMcpServersEnabled === false ? void 0 : await buildCodexUserMcpServersThreadConfigPatchForRuntime(params.params.config, {
1581
+ agentId: params.agentId ?? params.params.agentId,
1582
+ agentDir: params.params.agentDir,
1583
+ allowLiteralOAuthProjection: params.appServer.connectionClass !== "remote",
1584
+ onServerUnavailable: (serverName, error) => embeddedAgentLog.warn("skipping unavailable MCP OAuth server", {
1585
+ serverName,
1586
+ error: formatErrorMessage(error)
1587
+ })
1588
+ });
1700
1589
  const legacyUserMcpServersFingerprint = legacyFingerprintUserMcpServersConfigPatch(userMcpServersConfigPatch);
1701
1590
  const userMcpServersFingerprint = fingerprintUserMcpServersConfigPatch(userMcpServersConfigPatch);
1702
1591
  const environmentSelectionFingerprint = fingerprintEnvironmentSelection(params.environmentSelection);
1592
+ const hostSystemAgentActive = params.hostSystemAgentActive ?? isHostScopedAgentToolActive("openclaw");
1593
+ const ringZeroActive = hostSystemAgentActive && isSystemAgentOnlyCodexDynamicToolAllowlist(params.params.toolsAllow);
1594
+ if (ringZeroActive && params.nativeCodeModeEnabled !== false) throw new Error("Codex ring-zero requires native code mode to be disabled");
1595
+ const ringZeroInheritedMcpServerNames = ringZeroActive ? await lifecycleTiming.measure("ring-zero-mcp-config-read", () => readCodexInheritedMcpServerNames(params.client, params.cwd, params.signal)) : [];
1596
+ if (ringZeroActive) await lifecycleTiming.measure("ring-zero-config-requirements-read", () => assertCodexRingZeroHasNoManagedHooks(params.client, params.signal));
1597
+ const ringZeroConfigFingerprint = ringZeroActive ? fingerprintJsonObject({
1598
+ version: 1,
1599
+ baseInstructions: CODEX_RING_ZERO_BASE_INSTRUCTIONS,
1600
+ config: buildCodexRingZeroThreadConfigPatch(params.params, true, ringZeroInheritedMcpServerNames)
1601
+ }) : void 0;
1602
+ const ringZeroClientInstanceId = ringZeroActive ? getCodexAppServerClientInstanceId(params.client) : void 0;
1703
1603
  let binding = await lifecycleTiming.measure("read-binding", () => params.bindingStore.read(bindingIdentity));
1704
1604
  const normalizeBindingModelProvider = (authProfileId, modelProvider) => normalizeCodexAppServerBindingModelProvider({
1705
1605
  authProfileId,
@@ -1708,6 +1608,14 @@ async function startOrResumeThread(params) {
1708
1608
  agentDir: params.params.agentDir,
1709
1609
  config: params.params.config
1710
1610
  });
1611
+ const throwIfAborted = () => {
1612
+ if (!params.signal?.aborted) return;
1613
+ const reason = params.signal.reason;
1614
+ if (reason instanceof Error) throw reason;
1615
+ const error = new Error(typeof reason === "string" && reason.length > 0 ? reason : "codex app-server thread lifecycle aborted");
1616
+ error.name = "AbortError";
1617
+ throw error;
1618
+ };
1711
1619
  if (!binding && bindingIdentity.kind === "session" && bindingIdentity.sessionKey) {
1712
1620
  if (!await lifecycleTiming.measure("reclaim-binding-generation", () => reclaimCurrentCodexSessionGeneration({
1713
1621
  bindingStore: params.bindingStore,
@@ -1715,18 +1623,74 @@ async function startOrResumeThread(params) {
1715
1623
  config: params.params.config
1716
1624
  }))) throw new Error(`Codex session generation is no longer current: ${bindingIdentity.sessionId}`);
1717
1625
  }
1626
+ if (binding?.pendingSupervisionBranch) {
1627
+ const pendingBinding = binding;
1628
+ const pluginThreadConfig = params.pluginThreadConfig?.enabled ? await lifecycleTiming.measure("plugin-config-build", () => params.pluginThreadConfig?.build()) : void 0;
1629
+ const finalConfigPatch = params.buildFinalConfigPatch?.({ action: "start" }) ?? {
1630
+ configPatch: params.finalConfigPatch,
1631
+ nativeHookRelayGeneration: params.nativeHookRelayGeneration
1632
+ };
1633
+ const config = lifecycleTiming.measureSync("merge-thread-config", () => mergeCodexThreadConfigs(params.config, userMcpServersConfigPatch, pluginThreadConfig?.configPatch, finalConfigPatch.configPatch));
1634
+ return await materializePendingSupervisionBranch({
1635
+ client: params.client,
1636
+ abandonClient: params.abandonClient ?? (() => closeCodexStartupClientBestEffort(params.client)),
1637
+ bindingStore: params.bindingStore,
1638
+ bindingIdentity,
1639
+ binding: pendingBinding,
1640
+ attempt: params.params,
1641
+ cwd: params.cwd,
1642
+ dynamicTools: params.dynamicTools,
1643
+ appServer: params.appServer,
1644
+ developerInstructions: params.developerInstructions,
1645
+ config,
1646
+ nativeCodeModeEnabled: params.nativeCodeModeEnabled,
1647
+ nativeProviderWebSearchSupport: params.nativeProviderWebSearchSupport,
1648
+ nativeCodeModeOnlyEnabled: params.nativeCodeModeOnlyEnabled,
1649
+ webSearchAllowed: params.webSearchAllowed,
1650
+ environmentSelection: params.environmentSelection,
1651
+ signal: params.signal,
1652
+ throwIfAborted,
1653
+ lifecycleTiming,
1654
+ normalizeBindingModelProvider,
1655
+ bindingPatch: {
1656
+ cwd: params.cwd,
1657
+ authProfileId: void 0,
1658
+ preserveNativeModel: true,
1659
+ dynamicToolsFingerprint,
1660
+ dynamicToolsContainDeferred,
1661
+ webSearchThreadConfigFingerprint,
1662
+ userMcpServersFingerprint,
1663
+ mcpServersFingerprint: params.mcpServersFingerprintEvaluated === true ? params.mcpServersFingerprint : pendingBinding.mcpServersFingerprint,
1664
+ networkProxyProfileName: params.appServer.networkProxy?.profileName,
1665
+ networkProxyConfigFingerprint,
1666
+ nativeHookRelayGeneration: finalConfigPatch.nativeHookRelayGeneration,
1667
+ appServerRuntimeFingerprint: buildCodexAppServerConnectionFingerprint(params.appServer, params.params.agentDir),
1668
+ pluginAppsFingerprint: pluginThreadConfig?.fingerprint,
1669
+ pluginAppsInputFingerprint: pluginThreadConfig?.inputFingerprint,
1670
+ pluginAppPolicyContext: pluginThreadConfig?.policyContext,
1671
+ contextEngine: contextEngineBinding,
1672
+ environmentSelectionFingerprint,
1673
+ conversationSourceTransferComplete: true
1674
+ }
1675
+ });
1676
+ }
1718
1677
  const clearCurrentBinding = async (operation) => {
1719
1678
  const current = binding;
1720
1679
  if (!current?.threadId) return;
1680
+ assertCodexBindingMayBeReplaced(current, operation);
1721
1681
  if (!await params.bindingStore.mutate(bindingIdentity, {
1722
1682
  kind: "clear",
1723
1683
  threadId: current.threadId
1724
1684
  })) throw new CodexThreadBindingConflictError(current.threadId, operation);
1725
1685
  binding = void 0;
1726
1686
  };
1687
+ if (binding?.threadId && (binding.ringZeroConfigFingerprint !== ringZeroConfigFingerprint || binding.ringZeroClientInstanceId !== ringZeroClientInstanceId) && (ringZeroActive || binding.ringZeroConfigFingerprint !== void 0)) {
1688
+ embeddedAgentLog.debug("codex app-server ring-zero restriction changed; rotating thread", { threadId: binding.threadId });
1689
+ await clearCurrentBinding("rotating a ring-zero thread binding");
1690
+ }
1727
1691
  if (binding?.threadId && shouldRotateCodexAppServerBindingForRuntime({
1728
1692
  connectionClass: params.appServer.connectionClass,
1729
- current: params.appServerRuntimeFingerprint,
1693
+ current: binding.connectionScope === "supervision" ? buildCodexAppServerConnectionFingerprint(params.appServer, params.params.agentDir) : params.appServerRuntimeFingerprint,
1730
1694
  binding: binding.appServerRuntimeFingerprint
1731
1695
  })) {
1732
1696
  embeddedAgentLog.debug("codex app-server runtime identity changed; starting a new thread", {
@@ -1758,17 +1722,9 @@ async function startOrResumeThread(params) {
1758
1722
  config: params.params.config
1759
1723
  });
1760
1724
  const startModelProvider = startModelSelection.modelProvider;
1761
- let preserveExistingBinding = params.nativeProviderWebSearchSupport === "unknown" && !binding?.threadId;
1725
+ let preserveExistingBinding = !ringZeroActive && params.nativeProviderWebSearchSupport === "unknown" && !binding?.threadId;
1762
1726
  let rotatedContextEngineBinding = false;
1763
1727
  let prebuiltPluginThreadConfig;
1764
- const throwIfAborted = () => {
1765
- if (!params.signal?.aborted) return;
1766
- const reason = params.signal.reason;
1767
- if (reason instanceof Error) throw reason;
1768
- const error = new Error(typeof reason === "string" && reason.length > 0 ? reason : "codex app-server thread lifecycle aborted");
1769
- error.name = "AbortError";
1770
- throw error;
1771
- };
1772
1728
  const webSearchBindingChanged = binding?.threadId && binding.webSearchThreadConfigFingerprint !== webSearchThreadConfigFingerprint;
1773
1729
  const persistentWebSearchRestriction = params.webSearchAllowed === false && params.persistentWebSearchAllowed === false;
1774
1730
  const transientNativeToolRestriction = params.nativeCodeModeEnabled === false && !persistentWebSearchRestriction;
@@ -1776,7 +1732,8 @@ async function startOrResumeThread(params) {
1776
1732
  const explicitTransientWebSearchRestriction = params.webSearchAllowed === false && params.persistentWebSearchAllowed !== false && transientWebSearchRestriction;
1777
1733
  const unknownProviderWebSearchSupport = params.nativeProviderWebSearchSupport === "unknown";
1778
1734
  if (binding?.threadId && params.mcpServersFingerprintEvaluated === true && binding.mcpServersFingerprint !== params.mcpServersFingerprint) {
1779
- if (transientNativeToolRestriction || webSearchBindingChanged && (explicitTransientWebSearchRestriction || unknownProviderWebSearchSupport)) {
1735
+ assertCodexBindingMayBeReplaced(binding, "changing MCP configuration");
1736
+ if (!ringZeroActive && (transientNativeToolRestriction || webSearchBindingChanged && (explicitTransientWebSearchRestriction || unknownProviderWebSearchSupport))) {
1780
1737
  embeddedAgentLog.debug("codex app-server MCP config changed during transient restricted turn; starting transient thread", { threadId: binding.threadId });
1781
1738
  preserveExistingBinding = true;
1782
1739
  } else {
@@ -1787,7 +1744,8 @@ async function startOrResumeThread(params) {
1787
1744
  }
1788
1745
  const deferLegacyWebSearchRotationToTransientNativeSurface = params.nativeCodeModeEnabled === false && binding?.webSearchThreadConfigFingerprint === void 0 && !persistentWebSearchRestriction;
1789
1746
  if (binding?.threadId && webSearchBindingChanged && !deferLegacyWebSearchRotationToTransientNativeSurface) {
1790
- if (transientWebSearchRestriction) {
1747
+ assertCodexBindingMayBeReplaced(binding, "changing web-search configuration");
1748
+ if (!ringZeroActive && transientWebSearchRestriction) {
1791
1749
  embeddedAgentLog.debug("codex app-server web search restricted for turn; starting transient thread", { threadId: binding.threadId });
1792
1750
  preserveExistingBinding = true;
1793
1751
  } else {
@@ -1796,7 +1754,8 @@ async function startOrResumeThread(params) {
1796
1754
  }
1797
1755
  binding = void 0;
1798
1756
  }
1799
- if (binding?.threadId && transientNativeToolRestriction) {
1757
+ if (binding?.threadId && transientNativeToolRestriction && !ringZeroActive) {
1758
+ assertCodexBindingMayBeReplaced(binding, "starting a native-tool-restricted turn");
1800
1759
  embeddedAgentLog.debug("codex app-server native tool surface disabled for turn; starting transient thread", { threadId: binding.threadId });
1801
1760
  preserveExistingBinding = true;
1802
1761
  binding = void 0;
@@ -1872,6 +1831,7 @@ async function startOrResumeThread(params) {
1872
1831
  }
1873
1832
  }
1874
1833
  if (binding?.threadId) if (binding.dynamicToolsFingerprint && !areDynamicToolFingerprintsCompatible(binding.dynamicToolsFingerprint, dynamicToolsFingerprint, legacyDynamicToolsFingerprint)) {
1834
+ assertCodexBindingMayBeReplaced(binding, "changing the dynamic tool catalog");
1875
1835
  preserveExistingBinding = shouldStartTransientNoToolThread({
1876
1836
  previous: binding.dynamicToolsFingerprint,
1877
1837
  nextHasDynamicTools: params.dynamicTools.length > 0
@@ -1885,7 +1845,7 @@ async function startOrResumeThread(params) {
1885
1845
  const resumeBinding = binding;
1886
1846
  let resumeReservation;
1887
1847
  try {
1888
- const authProfileId = params.params.authProfileId ?? resumeBinding.authProfileId;
1848
+ const authProfileId = resumeBinding.connectionScope === "supervision" ? void 0 : params.params.authProfileId ?? resumeBinding.authProfileId;
1889
1849
  const finalConfigPatch = params.buildFinalConfigPatch?.({
1890
1850
  action: "resume",
1891
1851
  binding: resumeBinding
@@ -1900,6 +1860,7 @@ async function startOrResumeThread(params) {
1900
1860
  authProfileId,
1901
1861
  model: startModelSelection.model,
1902
1862
  modelProvider: startModelProvider,
1863
+ preserveNativeModel: resumeBinding.preserveNativeModel === true,
1903
1864
  appServer: params.appServer,
1904
1865
  dynamicTools: params.dynamicTools,
1905
1866
  developerInstructions: params.developerInstructions,
@@ -1907,10 +1868,20 @@ async function startOrResumeThread(params) {
1907
1868
  nativeCodeModeEnabled: params.nativeCodeModeEnabled,
1908
1869
  nativeProviderWebSearchSupport: params.nativeProviderWebSearchSupport,
1909
1870
  nativeCodeModeOnlyEnabled: params.nativeCodeModeOnlyEnabled,
1910
- webSearchAllowed: params.webSearchAllowed
1871
+ webSearchAllowed: params.webSearchAllowed,
1872
+ hostSystemAgentActive,
1873
+ ringZeroInheritedMcpServerNames
1911
1874
  }));
1912
1875
  const requestModelProvider = typeof resumeParams.modelProvider === "string" && resumeParams.modelProvider.trim() ? resumeParams.modelProvider : void 0;
1913
1876
  throwIfAborted();
1877
+ if (resumeBinding.preserveNativeModel === true) {
1878
+ const current = await lifecycleTiming.measure("thread-read-adoption-status", () => params.client.request("thread/read", {
1879
+ threadId: resumeBinding.threadId,
1880
+ includeTurns: false
1881
+ }, { signal: params.signal }));
1882
+ throwIfAborted();
1883
+ if (current.thread.status?.type === "active") throw new CodexAdoptedThreadActiveError();
1884
+ }
1914
1885
  resumeReservation = params.reserveResumeThread?.(resumeBinding.threadId);
1915
1886
  const response = await lifecycleTiming.measure("thread-resume-request", () => resumeCodexAppServerThread({
1916
1887
  client: params.client,
@@ -1918,6 +1889,12 @@ async function startOrResumeThread(params) {
1918
1889
  request: resumeParams,
1919
1890
  signal: params.signal
1920
1891
  }));
1892
+ if (ringZeroActive) try {
1893
+ await lifecycleTiming.measure("ring-zero-mcp-attestation", () => attestCodexRingZeroThreadHasNoMcpServers(params.client, response.thread.id, params.signal));
1894
+ } catch (error) {
1895
+ await (params.abandonClient ?? (() => closeCodexStartupClientBestEffort(params.client)))();
1896
+ throw new CodexRingZeroAttestationError(error);
1897
+ }
1921
1898
  throwIfAborted();
1922
1899
  const boundAuthProfileId = authProfileId;
1923
1900
  const nextMcpServersFingerprint = params.mcpServersFingerprintEvaluated === true ? params.mcpServersFingerprint : resumeBinding.mcpServersFingerprint;
@@ -1925,16 +1902,19 @@ async function startOrResumeThread(params) {
1925
1902
  cwd: params.cwd,
1926
1903
  authProfileId: boundAuthProfileId,
1927
1904
  model: response.model ?? resumeParams.model ?? params.params.modelId,
1905
+ preserveNativeModel: resumeBinding.preserveNativeModel === true ? true : void 0,
1928
1906
  modelProvider: normalizeBindingModelProvider(boundAuthProfileId, response.modelProvider ?? requestModelProvider ?? startModelProvider),
1929
1907
  dynamicToolsFingerprint,
1930
1908
  dynamicToolsContainDeferred,
1931
1909
  webSearchThreadConfigFingerprint,
1932
1910
  userMcpServersFingerprint,
1933
1911
  mcpServersFingerprint: nextMcpServersFingerprint,
1912
+ ringZeroConfigFingerprint,
1913
+ ringZeroClientInstanceId,
1934
1914
  networkProxyProfileName: params.appServer.networkProxy?.profileName,
1935
1915
  networkProxyConfigFingerprint,
1936
1916
  nativeHookRelayGeneration: finalConfigPatch.nativeHookRelayGeneration ?? resumeBinding.nativeHookRelayGeneration,
1937
- appServerRuntimeFingerprint: params.appServerRuntimeFingerprint,
1917
+ appServerRuntimeFingerprint: resumeBinding.connectionScope === "supervision" ? buildCodexAppServerConnectionFingerprint(params.appServer, params.params.agentDir) : params.appServerRuntimeFingerprint,
1938
1918
  pluginAppsFingerprint: resumeBinding.pluginAppsFingerprint,
1939
1919
  pluginAppsInputFingerprint: resumeBinding.pluginAppsInputFingerprint,
1940
1920
  pluginAppPolicyContext: resumeBinding.pluginAppPolicyContext,
@@ -1975,6 +1955,12 @@ async function startOrResumeThread(params) {
1975
1955
  };
1976
1956
  } catch (error) {
1977
1957
  resumeReservation?.release();
1958
+ if (isCodexAppServerStartSelectionChangedError(error)) throw error;
1959
+ if (error instanceof CodexRingZeroAttestationError) {
1960
+ await clearCurrentBinding("retiring a failed ring-zero thread attestation");
1961
+ throw error;
1962
+ }
1963
+ if (error instanceof CodexAdoptedThreadActiveError) throw error;
1978
1964
  if (isCodexAppServerUnsafeSubscriptionError(error)) throw error;
1979
1965
  const resumeRejected = error instanceof CodexAppServerRpcError;
1980
1966
  if (!await unsubscribeCodexThreadBestEffort(params.client, {
@@ -2004,7 +1990,9 @@ async function startOrResumeThread(params) {
2004
1990
  webSearchAllowed: params.webSearchAllowed,
2005
1991
  environmentSelection: params.environmentSelection,
2006
1992
  model: startModelSelection.model,
2007
- modelProvider: startModelProvider
1993
+ modelProvider: startModelProvider,
1994
+ hostSystemAgentActive,
1995
+ ringZeroInheritedMcpServerNames
2008
1996
  }));
2009
1997
  const requestModelProvider = typeof startParams.modelProvider === "string" && startParams.modelProvider.trim() ? startParams.modelProvider : void 0;
2010
1998
  const response = assertCodexThreadStartResponse(await lifecycleTiming.measure("thread-start-request", async () => {
@@ -2015,6 +2003,12 @@ async function startOrResumeThread(params) {
2015
2003
  throw error;
2016
2004
  }
2017
2005
  }));
2006
+ if (ringZeroActive) try {
2007
+ await lifecycleTiming.measure("ring-zero-mcp-attestation", () => attestCodexRingZeroThreadHasNoMcpServers(params.client, response.thread.id, params.signal));
2008
+ } catch (error) {
2009
+ await (params.abandonClient ?? (() => closeCodexStartupClientBestEffort(params.client)))();
2010
+ throw error;
2011
+ }
2018
2012
  throwIfAborted();
2019
2013
  const modelProvider = resolveCodexAppServerModelProvider({
2020
2014
  provider: params.params.provider,
@@ -2039,6 +2033,8 @@ async function startOrResumeThread(params) {
2039
2033
  webSearchThreadConfigFingerprint,
2040
2034
  userMcpServersFingerprint,
2041
2035
  mcpServersFingerprint: nextMcpServersFingerprint,
2036
+ ringZeroConfigFingerprint,
2037
+ ringZeroClientInstanceId,
2042
2038
  networkProxyProfileName: params.appServer.networkProxy?.profileName,
2043
2039
  networkProxyConfigFingerprint,
2044
2040
  nativeHookRelayGeneration: finalConfigPatch.nativeHookRelayGeneration,
@@ -2078,6 +2074,8 @@ async function startOrResumeThread(params) {
2078
2074
  dynamicToolsContainDeferred,
2079
2075
  userMcpServersFingerprint,
2080
2076
  mcpServersFingerprint: nextMcpServersFingerprint,
2077
+ ringZeroConfigFingerprint,
2078
+ ringZeroClientInstanceId,
2081
2079
  networkProxyProfileName: params.appServer.networkProxy?.profileName,
2082
2080
  networkProxyConfigFingerprint,
2083
2081
  nativeHookRelayGeneration: finalConfigPatch.nativeHookRelayGeneration,
@@ -2094,6 +2092,325 @@ async function startOrResumeThread(params) {
2094
2092
  };
2095
2093
  });
2096
2094
  }
2095
+ async function materializePendingSupervisionBranch(params) {
2096
+ let pending = params.binding.pendingSupervisionBranch;
2097
+ const connectionFingerprint = buildCodexAppServerConnectionFingerprint(params.appServer, params.attempt.agentDir);
2098
+ if (!pending.connectionFingerprint || pending.connectionFingerprint !== connectionFingerprint) throw new Error("Codex supervision source connection changed before branch materialization");
2099
+ pending = await recoverPendingSupervisionArtifacts(params, pending);
2100
+ params.throwIfAborted();
2101
+ const sourceResponse = await params.lifecycleTiming.measure("supervision-source-read", () => params.client.request("thread/read", {
2102
+ threadId: pending.sourceThreadId,
2103
+ includeTurns: true
2104
+ }, { signal: params.signal }));
2105
+ params.throwIfAborted();
2106
+ const sourceThread = sourceResponse.thread;
2107
+ if (sourceThread.id !== pending.sourceThreadId) throw new Error(`Codex supervision source read returned ${sourceThread.id} for ${pending.sourceThreadId}`);
2108
+ assertPendingSupervisionSnapshotUnchanged(sourceThread, pending);
2109
+ const history = projectBoundedCodexThreadHistory({
2110
+ thread: sourceThread,
2111
+ throughTurnId: pending.lastTurnId ?? null,
2112
+ importedAt: Date.now(),
2113
+ modelProvider: sourceThread.modelProvider
2114
+ });
2115
+ let bindingCommitted = false;
2116
+ let provisionalCleanupSafe = true;
2117
+ try {
2118
+ const probeParams = buildPendingSupervisionProbeForkParams(params, pending);
2119
+ const rawProbeResponse = await params.lifecycleTiming.measure("supervision-model-probe-fork", async () => {
2120
+ try {
2121
+ return await params.client.request("thread/fork", probeParams, { signal: params.signal });
2122
+ } catch (error) {
2123
+ if (!(error instanceof CodexAppServerRpcError)) throw new CodexAppServerUnsafeSubscriptionError("Codex model probe fork may have materialized without a response", { cause: error });
2124
+ throw error;
2125
+ }
2126
+ });
2127
+ const probeThreadId = requireDistinctSupervisionThreadId({
2128
+ threadId: readSupervisionResponseThreadId(rawProbeResponse),
2129
+ sourceThreadId: pending.sourceThreadId,
2130
+ role: "model probe"
2131
+ });
2132
+ pending = await trackPendingSupervisionArtifacts(params, pending, [probeThreadId]);
2133
+ params.throwIfAborted();
2134
+ const probeResponse = assertCodexThreadForkResponse(rawProbeResponse);
2135
+ const nativeModel = requireNonBlankSupervisionValue(probeResponse.model, "native model");
2136
+ const nativeModelProvider = requireNativeSupervisionModelProvider({
2137
+ responseModelProvider: probeResponse.modelProvider,
2138
+ responseThreadModelProvider: probeResponse.thread.modelProvider
2139
+ });
2140
+ const startParams = buildThreadStartParams({
2141
+ ...params.attempt,
2142
+ modelId: nativeModel
2143
+ }, {
2144
+ cwd: params.cwd,
2145
+ dynamicTools: params.dynamicTools,
2146
+ appServer: params.appServer,
2147
+ developerInstructions: params.developerInstructions,
2148
+ config: params.config,
2149
+ nativeCodeModeEnabled: params.nativeCodeModeEnabled,
2150
+ nativeProviderWebSearchSupport: params.nativeProviderWebSearchSupport,
2151
+ nativeCodeModeOnlyEnabled: params.nativeCodeModeOnlyEnabled,
2152
+ webSearchAllowed: params.webSearchAllowed,
2153
+ environmentSelection: params.environmentSelection,
2154
+ model: nativeModel,
2155
+ modelProvider: nativeModelProvider
2156
+ });
2157
+ assertExactSupervisionModelSelection(startParams, {
2158
+ model: nativeModel,
2159
+ modelProvider: nativeModelProvider,
2160
+ operation: "thread/start request"
2161
+ });
2162
+ const rawStartResponse = await params.lifecycleTiming.measure("supervision-thread-start", async () => {
2163
+ try {
2164
+ return await params.client.request("thread/start", startParams, { signal: params.signal });
2165
+ } catch (error) {
2166
+ if (error instanceof CodexAppServerRpcError) throw new CodexThreadStartRequestError(error);
2167
+ throw new CodexAppServerUnsafeSubscriptionError("Canonical Codex branch may have started without a response", { cause: error });
2168
+ }
2169
+ });
2170
+ const finalThreadId = requireDistinctSupervisionThreadId({
2171
+ threadId: readSupervisionResponseThreadId(rawStartResponse),
2172
+ sourceThreadId: pending.sourceThreadId,
2173
+ otherThreadId: probeThreadId,
2174
+ role: "canonical branch"
2175
+ });
2176
+ pending = await trackPendingSupervisionArtifacts(params, pending, [probeThreadId, finalThreadId]);
2177
+ params.throwIfAborted();
2178
+ assertExactSupervisionModelSelection(assertCodexThreadStartResponse(rawStartResponse), {
2179
+ model: nativeModel,
2180
+ modelProvider: nativeModelProvider,
2181
+ operation: "thread/start response"
2182
+ });
2183
+ if (history.responseItems.length > 0) {
2184
+ await params.lifecycleTiming.measure("supervision-history-inject", () => params.client.request("thread/inject_items", {
2185
+ threadId: finalThreadId,
2186
+ items: history.responseItems
2187
+ }, { signal: params.signal }));
2188
+ params.throwIfAborted();
2189
+ }
2190
+ if (!await archiveSupervisionArtifact(params.client, probeThreadId)) throw new Error(`Failed to archive temporary Codex model probe: ${probeThreadId}`);
2191
+ pending = await trackPendingSupervisionArtifacts(params, pending, [finalThreadId]);
2192
+ const historyCoveredThrough = (/* @__PURE__ */ new Date()).toISOString();
2193
+ const bindingModelProvider = params.normalizeBindingModelProvider(params.attempt.authProfileId, nativeModelProvider);
2194
+ let committed = false;
2195
+ try {
2196
+ committed = await params.bindingStore.mutate(params.bindingIdentity, {
2197
+ kind: "commit-pending-supervision-branch",
2198
+ expected: pending,
2199
+ threadId: finalThreadId,
2200
+ patch: {
2201
+ ...params.bindingPatch,
2202
+ model: nativeModel,
2203
+ modelProvider: bindingModelProvider,
2204
+ historyCoveredThrough
2205
+ }
2206
+ });
2207
+ } catch (error) {
2208
+ let current;
2209
+ try {
2210
+ current = await params.bindingStore.read(params.bindingIdentity);
2211
+ } catch (readError) {
2212
+ provisionalCleanupSafe = false;
2213
+ throw new CodexAppServerUnsafeSubscriptionError(`Canonical Codex branch binding could not be verified: ${finalThreadId}`, { cause: new AggregateError([error, readError]) });
2214
+ }
2215
+ if (matchesMaterializedSupervisionBranch(current, {
2216
+ sourceThreadId: pending.sourceThreadId,
2217
+ connectionFingerprint,
2218
+ threadId: finalThreadId,
2219
+ model: nativeModel,
2220
+ modelProvider: bindingModelProvider,
2221
+ historyCoveredThrough
2222
+ })) committed = true;
2223
+ else {
2224
+ if (!matchesPendingSupervisionState(current, pending)) {
2225
+ provisionalCleanupSafe = false;
2226
+ throw new CodexAppServerUnsafeSubscriptionError(`Canonical Codex branch binding changed while commit was uncertain: ${finalThreadId}`, { cause: error });
2227
+ }
2228
+ throw error;
2229
+ }
2230
+ }
2231
+ if (!committed) throw new CodexThreadBindingConflictError(pending.sourceThreadId, "committing a supervised Codex branch");
2232
+ bindingCommitted = true;
2233
+ params.lifecycleTiming.mark("thread-ready");
2234
+ params.lifecycleTiming.logSummary({
2235
+ runId: params.attempt.runId,
2236
+ sessionId: params.attempt.sessionId,
2237
+ sessionKey: params.attempt.sessionKey,
2238
+ threadId: finalThreadId,
2239
+ action: "forked"
2240
+ });
2241
+ return {
2242
+ ...params.binding,
2243
+ ...params.bindingPatch,
2244
+ threadId: finalThreadId,
2245
+ pendingSupervisionBranch: void 0,
2246
+ model: nativeModel,
2247
+ modelProvider: bindingModelProvider,
2248
+ historyCoveredThrough,
2249
+ lifecycle: { action: "forked" }
2250
+ };
2251
+ } catch (error) {
2252
+ if (bindingCommitted) throw error;
2253
+ if (error instanceof CodexThreadBindingConflictAfterCleanupError) throw error;
2254
+ if (!provisionalCleanupSafe) {
2255
+ await params.abandonClient();
2256
+ throw error;
2257
+ }
2258
+ const cleanup = await cleanPendingSupervisionArtifacts(params.client, pending);
2259
+ let cleanupStateError;
2260
+ if (cleanup.remaining.length !== (pending.cleanupThreadIds?.length ?? 0)) {
2261
+ const nextPending = withPendingSupervisionCleanup(pending, cleanup.remaining);
2262
+ try {
2263
+ if (await params.bindingStore.mutate(params.bindingIdentity, {
2264
+ kind: "patch-pending-supervision-branch",
2265
+ expected: pending,
2266
+ pending: nextPending
2267
+ })) pending = nextPending;
2268
+ } catch (stateError) {
2269
+ cleanupStateError = stateError;
2270
+ }
2271
+ }
2272
+ const unsafeCleanup = cleanup.remaining.length > 0 || isCodexAppServerUnsafeSubscriptionError(error);
2273
+ if (unsafeCleanup) await params.abandonClient();
2274
+ if (cleanupStateError) {
2275
+ const cause = new AggregateError([error, cleanupStateError]);
2276
+ if (unsafeCleanup) throw new CodexAppServerUnsafeSubscriptionError("Codex supervised branch cleanup state could not be recorded", { cause });
2277
+ throw new AggregateError([error, cleanupStateError], "Codex supervised branch cleanup state could not be recorded", { cause: error });
2278
+ }
2279
+ if (cleanup.remaining.length > 0) throw new CodexAppServerUnsafeSubscriptionError(`Codex supervised branch cleanup remains pending: ${cleanup.remaining.join(", ")}`, { cause: error });
2280
+ throw error;
2281
+ }
2282
+ }
2283
+ function buildPendingSupervisionProbeForkParams(params, pending) {
2284
+ const runtimeConfig = buildCodexRuntimeThreadConfigForRun(params.attempt, params.config, {
2285
+ nativeCodeModeEnabled: params.nativeCodeModeEnabled,
2286
+ nativeProviderWebSearchSupport: params.nativeProviderWebSearchSupport,
2287
+ nativeCodeModeOnlyEnabled: params.nativeCodeModeOnlyEnabled,
2288
+ webSearchAllowed: params.webSearchAllowed,
2289
+ appServer: params.appServer
2290
+ });
2291
+ return {
2292
+ threadId: pending.sourceThreadId,
2293
+ ...pending.lastTurnId ? { lastTurnId: pending.lastTurnId } : {},
2294
+ cwd: params.cwd,
2295
+ approvalPolicy: params.appServer.approvalPolicy,
2296
+ approvalsReviewer: resolveCodexThreadApprovalsReviewer(params.appServer, runtimeConfig),
2297
+ ...codexThreadSandboxOrPermissions(params.appServer),
2298
+ ...params.appServer.serviceTier !== void 0 ? { serviceTier: params.appServer.serviceTier } : {},
2299
+ config: runtimeConfig,
2300
+ developerInstructions: params.developerInstructions ?? buildDeveloperInstructions(params.attempt, { dynamicTools: params.dynamicTools }),
2301
+ ephemeral: false,
2302
+ threadSource: "appServer",
2303
+ excludeTurns: true
2304
+ };
2305
+ }
2306
+ function assertPendingSupervisionSnapshotUnchanged(thread, pending) {
2307
+ if (pending.lastTurnId) return;
2308
+ if (thread.status?.type === "active" || (thread.turns?.length ?? 0) > 0) throw new Error("Codex source changed after Continue; reopen the source session before sending a message");
2309
+ }
2310
+ function requireNonBlankSupervisionValue(value, label) {
2311
+ if (typeof value !== "string" || !value.trim()) throw new Error(`Codex supervision ${label} is missing`);
2312
+ return value.trim();
2313
+ }
2314
+ function requireNativeSupervisionModelProvider(params) {
2315
+ const responseProvider = requireNonBlankSupervisionValue(params.responseModelProvider, "native model provider");
2316
+ const threadProvider = params.responseThreadModelProvider?.trim();
2317
+ if (threadProvider && threadProvider !== responseProvider) throw new Error(`Codex supervision model provider mismatch: ${responseProvider} != ${threadProvider}`);
2318
+ return responseProvider;
2319
+ }
2320
+ function assertExactSupervisionModelSelection(value, expected) {
2321
+ if (value.model !== expected.model || value.modelProvider !== expected.modelProvider) throw new Error(`Codex supervision ${expected.operation} changed native model selection: ${value.modelProvider ?? "unknown"}/${value.model ?? "unknown"}`);
2322
+ }
2323
+ function matchesPendingSupervisionState(binding, expected) {
2324
+ const pending = binding?.pendingSupervisionBranch;
2325
+ const cleanupThreadIds = pending?.cleanupThreadIds ?? [];
2326
+ const expectedCleanupThreadIds = expected.cleanupThreadIds ?? [];
2327
+ return binding?.threadId === expected.sourceThreadId && binding.connectionScope === "supervision" && binding.supervisionSourceThreadId === expected.sourceThreadId && pending?.sourceThreadId === expected.sourceThreadId && pending.connectionFingerprint === expected.connectionFingerprint && pending.lastTurnId === expected.lastTurnId && cleanupThreadIds.length === expectedCleanupThreadIds.length && cleanupThreadIds.every((threadId, index) => threadId === expectedCleanupThreadIds[index]);
2328
+ }
2329
+ function matchesMaterializedSupervisionBranch(binding, expected) {
2330
+ return binding?.threadId === expected.threadId && binding.connectionScope === "supervision" && binding.supervisionSourceThreadId === expected.sourceThreadId && binding.appServerRuntimeFingerprint === expected.connectionFingerprint && binding.pendingSupervisionBranch === void 0 && binding.model === expected.model && binding.modelProvider === expected.modelProvider && binding.historyCoveredThrough === expected.historyCoveredThrough;
2331
+ }
2332
+ function requireDistinctSupervisionThreadId(params) {
2333
+ let threadId;
2334
+ try {
2335
+ threadId = requireNonBlankSupervisionValue(params.threadId, `${params.role} thread id`);
2336
+ } catch (error) {
2337
+ throw new CodexAppServerUnsafeSubscriptionError(`Codex supervision ${params.role} may have materialized without a safe thread id`, { cause: error });
2338
+ }
2339
+ if (threadId === params.sourceThreadId || threadId === params.otherThreadId) throw new CodexAppServerUnsafeSubscriptionError(`Codex supervision ${params.role} reused an existing thread: ${threadId}`);
2340
+ return threadId;
2341
+ }
2342
+ function readSupervisionResponseThreadId(value) {
2343
+ if (!value || typeof value !== "object" || Array.isArray(value)) return;
2344
+ const thread = value.thread;
2345
+ if (!thread || typeof thread !== "object" || Array.isArray(thread)) return;
2346
+ return thread.id;
2347
+ }
2348
+ async function recoverPendingSupervisionArtifacts(params, pending) {
2349
+ if (!pending.cleanupThreadIds?.length) return pending;
2350
+ const cleanup = await cleanPendingSupervisionArtifacts(params.client, pending);
2351
+ const next = withPendingSupervisionCleanup(pending, cleanup.remaining);
2352
+ if (cleanup.remaining.length > 0) {
2353
+ if (cleanup.remaining.length !== pending.cleanupThreadIds.length) {
2354
+ if (!await params.bindingStore.mutate(params.bindingIdentity, {
2355
+ kind: "patch-pending-supervision-branch",
2356
+ expected: pending,
2357
+ pending: next
2358
+ })) throw new CodexThreadBindingConflictError(pending.sourceThreadId, "recording supervised Codex cleanup recovery");
2359
+ }
2360
+ throw new Error(`Codex supervised branch cleanup must finish before retry: ${cleanup.remaining.join(", ")}`);
2361
+ }
2362
+ if (!await params.bindingStore.mutate(params.bindingIdentity, {
2363
+ kind: "patch-pending-supervision-branch",
2364
+ expected: pending,
2365
+ pending: next
2366
+ })) throw new CodexThreadBindingConflictError(pending.sourceThreadId, "recovering a supervised Codex branch");
2367
+ return next;
2368
+ }
2369
+ async function trackPendingSupervisionArtifacts(params, pending, cleanupThreadIds) {
2370
+ const next = withPendingSupervisionCleanup(pending, cleanupThreadIds);
2371
+ if (!await params.bindingStore.mutate(params.bindingIdentity, {
2372
+ kind: "patch-pending-supervision-branch",
2373
+ expected: pending,
2374
+ pending: next
2375
+ })) {
2376
+ const cleanupFailed = [];
2377
+ for (const threadId of cleanupThreadIds) if (!await archiveSupervisionArtifact(params.client, threadId)) cleanupFailed.push(threadId);
2378
+ if (cleanupFailed.length > 0) throw new CodexAppServerUnsafeSubscriptionError(`Codex supervised branch CAS cleanup failed: ${cleanupFailed.join(", ")}`);
2379
+ throw new CodexThreadBindingConflictAfterCleanupError(pending.sourceThreadId, "tracking supervised Codex branch cleanup");
2380
+ }
2381
+ return next;
2382
+ }
2383
+ function withPendingSupervisionCleanup(pending, cleanupThreadIds) {
2384
+ return {
2385
+ sourceThreadId: pending.sourceThreadId,
2386
+ ...pending.connectionFingerprint ? { connectionFingerprint: pending.connectionFingerprint } : {},
2387
+ ...pending.lastTurnId ? { lastTurnId: pending.lastTurnId } : {},
2388
+ ...cleanupThreadIds.length > 0 ? { cleanupThreadIds } : {}
2389
+ };
2390
+ }
2391
+ async function cleanPendingSupervisionArtifacts(client, pending) {
2392
+ const remaining = [];
2393
+ for (const threadId of pending.cleanupThreadIds ?? []) if (!await archiveSupervisionArtifact(client, threadId)) remaining.push(threadId);
2394
+ return { remaining };
2395
+ }
2396
+ async function archiveSupervisionArtifact(client, threadId) {
2397
+ try {
2398
+ await client.request("thread/archive", { threadId }, { timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS });
2399
+ return true;
2400
+ } catch (error) {
2401
+ const message = formatErrorMessage(error).toLowerCase();
2402
+ if (message.includes("no rollout found for thread id") || message.includes("thread not found") || message.includes("already archived")) return true;
2403
+ await unsubscribeCodexThreadBestEffort(client, {
2404
+ threadId,
2405
+ timeoutMs: CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS
2406
+ });
2407
+ embeddedAgentLog.warn("failed to archive temporary Codex supervision thread", {
2408
+ threadId,
2409
+ error
2410
+ });
2411
+ return false;
2412
+ }
2413
+ }
2097
2414
  function shouldRotateCodexAppServerBindingForRuntime(params) {
2098
2415
  if (!params.current) return false;
2099
2416
  if (params.binding === params.current) return false;
@@ -2191,6 +2508,7 @@ function shouldRecheckRecoverablePluginBinding(params) {
2191
2508
  return Object.keys(policyContext.apps).length === 0 || expectedPluginConfigKeys.length > 0;
2192
2509
  }
2193
2510
  function buildThreadStartParams(params, options) {
2511
+ const ringZeroActive = (options.hostSystemAgentActive ?? isHostScopedAgentToolActive("openclaw")) && isSystemAgentOnlyCodexDynamicToolAllowlist(params.toolsAllow);
2194
2512
  const resolvedModelProvider = resolveCodexAppServerModelProvider({
2195
2513
  provider: params.provider,
2196
2514
  authProfileId: params.authProfileId,
@@ -2216,12 +2534,16 @@ function buildThreadStartParams(params, options) {
2216
2534
  ...options.appServer.serviceTier !== void 0 ? { serviceTier: options.appServer.serviceTier } : {},
2217
2535
  personality: CODEX_NATIVE_PERSONALITY_NONE,
2218
2536
  serviceName: "OpenClaw",
2537
+ ...ringZeroActive ? { baseInstructions: CODEX_RING_ZERO_BASE_INSTRUCTIONS } : {},
2219
2538
  config: buildCodexRuntimeThreadConfigForRun(params, options.config, {
2220
2539
  nativeCodeModeEnabled: options.nativeCodeModeEnabled,
2221
2540
  nativeProviderWebSearchSupport: options.nativeProviderWebSearchSupport,
2222
2541
  nativeCodeModeOnlyEnabled: options.nativeCodeModeOnlyEnabled,
2542
+ directOnlyToolNamespaces: resolveDirectOnlyToolNamespaces(options.dynamicTools),
2223
2543
  webSearchAllowed: options.webSearchAllowed,
2224
- appServer: options.appServer
2544
+ appServer: options.appServer,
2545
+ hostSystemAgentActive: options.hostSystemAgentActive,
2546
+ ringZeroInheritedMcpServerNames: options.ringZeroInheritedMcpServerNames
2225
2547
  }),
2226
2548
  ...resolveCodexThreadEnvironmentSelection(options),
2227
2549
  developerInstructions: options.developerInstructions ?? buildDeveloperInstructions(params, { dynamicTools: options.dynamicTools }),
@@ -2230,16 +2552,15 @@ function buildThreadStartParams(params, options) {
2230
2552
  };
2231
2553
  }
2232
2554
  function buildThreadResumeParams(params, options) {
2233
- const resolvedModelProvider = resolveCodexAppServerModelProvider({
2234
- provider: params.provider,
2235
- authProfileId: options.authProfileId ?? params.authProfileId,
2236
- authProfileStore: params.authProfileStore,
2237
- agentDir: params.agentDir,
2238
- config: params.config
2239
- });
2240
- const modelSelection = resolveCodexAppServerRequestModelSelection({
2555
+ const modelSelection = options.preserveNativeModel ? void 0 : resolveCodexAppServerRequestModelSelection({
2241
2556
  model: options.model ?? params.modelId,
2242
- modelProvider: options.modelProvider ?? resolvedModelProvider,
2557
+ modelProvider: options.modelProvider ?? resolveCodexAppServerModelProvider({
2558
+ provider: params.provider,
2559
+ authProfileId: options.authProfileId ?? params.authProfileId,
2560
+ authProfileStore: params.authProfileStore,
2561
+ agentDir: params.agentDir,
2562
+ config: params.config
2563
+ }),
2243
2564
  authProfileId: options.authProfileId ?? params.authProfileId,
2244
2565
  authProfileStore: params.authProfileStore,
2245
2566
  agentDir: params.agentDir,
@@ -2247,8 +2568,10 @@ function buildThreadResumeParams(params, options) {
2247
2568
  });
2248
2569
  return {
2249
2570
  threadId: options.threadId,
2250
- model: modelSelection.model,
2251
- ...modelSelection.modelProvider ? { modelProvider: modelSelection.modelProvider } : {},
2571
+ ...modelSelection ? {
2572
+ model: modelSelection.model,
2573
+ ...modelSelection.modelProvider ? { modelProvider: modelSelection.modelProvider } : {}
2574
+ } : {},
2252
2575
  approvalPolicy: options.appServer.approvalPolicy,
2253
2576
  approvalsReviewer: resolveCodexThreadApprovalsReviewer(options.appServer, options.config),
2254
2577
  ...codexThreadSandboxOrPermissions(options.appServer),
@@ -2258,8 +2581,11 @@ function buildThreadResumeParams(params, options) {
2258
2581
  nativeCodeModeEnabled: options.nativeCodeModeEnabled,
2259
2582
  nativeProviderWebSearchSupport: options.nativeProviderWebSearchSupport,
2260
2583
  nativeCodeModeOnlyEnabled: options.nativeCodeModeOnlyEnabled,
2584
+ directOnlyToolNamespaces: resolveDirectOnlyToolNamespaces(options.dynamicTools),
2261
2585
  webSearchAllowed: options.webSearchAllowed,
2262
- appServer: options.appServer
2586
+ appServer: options.appServer,
2587
+ hostSystemAgentActive: options.hostSystemAgentActive,
2588
+ ringZeroInheritedMcpServerNames: options.ringZeroInheritedMcpServerNames
2263
2589
  }),
2264
2590
  developerInstructions: options.developerInstructions ?? buildDeveloperInstructions(params, { dynamicTools: options.dynamicTools })
2265
2591
  };
@@ -2332,13 +2658,29 @@ function buildCodexRuntimeThreadConfig(config, options = {}) {
2332
2658
  delete disabledConfig["features.apply_patch_streaming_events"];
2333
2659
  return disabledConfig;
2334
2660
  }
2335
- if (options.nativeCodeModeOnlyEnabled === true) return mergeCodexThreadConfigs(codeModeConfig, config, { "features.code_mode_only": true }) ?? {
2661
+ if (options.nativeCodeModeOnlyEnabled === true) return ensureDirectOnlyToolNamespaces(mergeCodexThreadConfigs(codeModeConfig, config, { "features.code_mode_only": true }) ?? {
2336
2662
  ...codeModeConfig,
2337
2663
  "features.code_mode_only": true
2664
+ }, options.directOnlyToolNamespaces);
2665
+ return ensureDirectOnlyToolNamespaces(mergeCodexThreadConfigs(codeModeConfig, config) ?? { ...codeModeConfig }, options.directOnlyToolNamespaces);
2666
+ }
2667
+ function ensureDirectOnlyToolNamespaces(config, requiredNamespaces) {
2668
+ if (!requiredNamespaces?.length) return config;
2669
+ const configured = config["code_mode.direct_only_tool_namespaces"];
2670
+ const namespaces = Array.isArray(configured) ? configured.filter((entry) => typeof entry === "string" && entry.length > 0) : [];
2671
+ return {
2672
+ ...config,
2673
+ "code_mode.direct_only_tool_namespaces": [.../* @__PURE__ */ new Set([...namespaces, ...requiredNamespaces])]
2338
2674
  };
2339
- return mergeCodexThreadConfigs(codeModeConfig, config) ?? { ...codeModeConfig };
2675
+ }
2676
+ function resolveDirectOnlyToolNamespaces(dynamicTools) {
2677
+ return (dynamicTools ?? []).filter((tool) => tool.type === "namespace" && tool.name === "openclaw_direct").map((tool) => tool.name);
2340
2678
  }
2341
2679
  function buildCodexRuntimeThreadConfigForRun(params, config, options = {}) {
2680
+ const ringZeroActive = (options.hostSystemAgentActive ?? isHostScopedAgentToolActive("openclaw")) && isSystemAgentOnlyCodexDynamicToolAllowlist(params.toolsAllow);
2681
+ const configMcpServers = config?.mcp_servers;
2682
+ if (ringZeroActive && configMcpServers !== void 0 && !isJsonObject(configMcpServers)) throw new Error("Codex ring-zero received invalid thread mcp_servers config");
2683
+ const ringZeroMcpServerNames = [...options.ringZeroInheritedMcpServerNames ?? [], ...isJsonObject(configMcpServers) ? Object.keys(configMcpServers) : []];
2342
2684
  const webSearchConfig = resolveCodexWebSearchPlan({
2343
2685
  config: params.config,
2344
2686
  disableTools: params.disableTools,
@@ -2347,15 +2689,85 @@ function buildCodexRuntimeThreadConfigForRun(params, config, options = {}) {
2347
2689
  webSearchAllowed: options.webSearchAllowed
2348
2690
  }).threadConfig;
2349
2691
  const baseConfig = buildCodexRuntimeThreadConfig(mergeCodexThreadConfigs(config, webSearchConfig), options);
2350
- const runtimeConfig = mergeCodexThreadConfigs(baseConfig, options.appServer?.networkProxy?.configPatch, shouldDisableCodexToolSearchForModel(params.modelId) ? CODEX_TOOL_SEARCH_UNSUPPORTED_THREAD_CONFIG : void 0) ?? baseConfig;
2692
+ const runtimeConfig = mergeCodexThreadConfigs(baseConfig, options.appServer?.networkProxy?.configPatch, shouldDisableCodexToolSearchForModel(params.modelId) ? CODEX_TOOL_SEARCH_UNSUPPORTED_THREAD_CONFIG : void 0, buildCodexRingZeroThreadConfigPatch(params, options.hostSystemAgentActive, ringZeroMcpServerNames)) ?? baseConfig;
2351
2693
  if (params.bootstrapContextMode !== "lightweight") return runtimeConfig;
2352
2694
  return mergeCodexThreadConfigs(runtimeConfig, CODEX_LIGHTWEIGHT_CONTEXT_THREAD_CONFIG) ?? {
2353
2695
  ...runtimeConfig,
2354
2696
  ...CODEX_LIGHTWEIGHT_CONTEXT_THREAD_CONFIG
2355
2697
  };
2356
2698
  }
2699
+ function buildCodexRingZeroThreadConfigPatch(params, hostSystemAgentActive = isHostScopedAgentToolActive("openclaw"), inheritedMcpServerNames = []) {
2700
+ if (!hostSystemAgentActive || !isSystemAgentOnlyCodexDynamicToolAllowlist(params.toolsAllow)) return;
2701
+ const mcpServers = Object.fromEntries([...new Set(inheritedMcpServerNames)].toSorted().map((name) => [name, { enabled: false }]));
2702
+ return {
2703
+ ...CODEX_RING_ZERO_THREAD_CONFIG,
2704
+ ...Object.keys(mcpServers).length > 0 ? { mcp_servers: mcpServers } : {}
2705
+ };
2706
+ }
2707
+ async function readCodexInheritedMcpServerNames(client, cwd, signal) {
2708
+ const response = await client.request("config/read", {
2709
+ cwd,
2710
+ includeLayers: true
2711
+ }, { signal });
2712
+ if (!isJsonObject(response) || !isJsonObject(response.config)) throw new Error("Codex config/read returned an invalid effective config");
2713
+ if (!Array.isArray(response.layers)) throw new Error("Codex config/read omitted effective config layers");
2714
+ for (const layer of response.layers) {
2715
+ if (!isJsonObject(layer) || !isJsonObject(layer.name) || typeof layer.name.type !== "string") throw new Error("Codex config/read returned invalid effective config layers");
2716
+ if (layer.name.type === "legacyManagedConfigTomlFromFile" || layer.name.type === "legacyManagedConfigTomlFromMdm") throw new Error(`Codex ring-zero cannot override config layer ${layer.name.type}`);
2717
+ if (!CODEX_RING_ZERO_OVERRIDABLE_LAYER_TYPES.has(layer.name.type)) throw new Error(`Codex ring-zero does not recognize config layer ${layer.name.type}`);
2718
+ }
2719
+ const configuredServers = response.config.mcp_servers;
2720
+ if (configuredServers === void 0) return [];
2721
+ if (!isJsonObject(configuredServers)) throw new Error("Codex config/read returned invalid mcp_servers");
2722
+ return Object.keys(configuredServers).toSorted();
2723
+ }
2724
+ async function assertCodexRingZeroHasNoManagedHooks(client, signal) {
2725
+ const response = await client.request("configRequirements/read", void 0, { signal });
2726
+ if (!isJsonObject(response) || !Object.hasOwn(response, "requirements")) throw new Error("Codex configRequirements/read returned an invalid response");
2727
+ if (response.requirements === null) return;
2728
+ if (!isJsonObject(response.requirements)) throw new Error("Codex configRequirements/read returned invalid requirements");
2729
+ for (const key of [
2730
+ "hooks",
2731
+ "managedHooks",
2732
+ "managed_hooks"
2733
+ ]) {
2734
+ const hooks = response.requirements[key];
2735
+ if (hooks === void 0 || hooks === null) continue;
2736
+ if (!isJsonObject(hooks)) throw new Error("Codex configRequirements/read returned invalid managed hooks");
2737
+ if (hasNonEmptyJsonValue(hooks)) throw new Error("Codex ring-zero cannot override managed hooks");
2738
+ }
2739
+ for (const key of ["featureRequirements", "feature_requirements"]) {
2740
+ const requirements = response.requirements[key];
2741
+ if (requirements === void 0 || requirements === null) continue;
2742
+ if (!isJsonObject(requirements)) throw new Error("Codex configRequirements/read returned invalid feature requirements");
2743
+ for (const [feature, enabled] of Object.entries(requirements)) {
2744
+ if (typeof enabled !== "boolean") throw new Error("Codex configRequirements/read returned invalid feature requirements");
2745
+ if (enabled && CODEX_RING_ZERO_RESTRICTED_FEATURES.has(feature)) throw new Error(`Codex ring-zero cannot override required feature ${feature}`);
2746
+ }
2747
+ }
2748
+ }
2749
+ async function attestCodexRingZeroThreadHasNoMcpServers(client, threadId, signal) {
2750
+ const response = await client.request("mcpServerStatus/list", {
2751
+ threadId,
2752
+ limit: 1,
2753
+ detail: "toolsAndAuthOnly"
2754
+ }, { signal });
2755
+ if (!isJsonObject(response) || !Array.isArray(response.data)) throw new Error("Codex mcpServerStatus/list returned an invalid ring-zero attestation");
2756
+ if (response.data.length > 0) {
2757
+ const first = response.data[0];
2758
+ const serverName = isJsonObject(first) && typeof first.name === "string" ? first.name : "unknown";
2759
+ throw new Error(`Codex ring-zero MCP attestation found server ${serverName}`);
2760
+ }
2761
+ if (response.nextCursor !== void 0 && response.nextCursor !== null) throw new Error("Codex mcpServerStatus/list returned an invalid empty-page cursor");
2762
+ }
2763
+ function hasNonEmptyJsonValue(value) {
2764
+ if (value === null || value === false || value === "") return false;
2765
+ if (Array.isArray(value)) return value.length > 0;
2766
+ if (typeof value === "object") return Object.values(value).some(hasNonEmptyJsonValue);
2767
+ return true;
2768
+ }
2357
2769
  function buildTurnStartParams(params, options) {
2358
- const modelSelection = resolveCodexAppServerRequestModelSelection({
2770
+ const modelSelection = options.preserveNativeTurnSettings ? void 0 : resolveCodexAppServerRequestModelSelection({
2359
2771
  model: options.model ?? params.modelId,
2360
2772
  modelProvider: options.modelProvider,
2361
2773
  authProfileId: params.authProfileId,
@@ -2371,18 +2783,20 @@ function buildTurnStartParams(params, options) {
2371
2783
  approvalPolicy: options.appServer.approvalPolicy,
2372
2784
  approvalsReviewer: options.appServer.approvalsReviewer,
2373
2785
  ...useThreadPermissionProfile ? {} : { sandboxPolicy: options.sandboxPolicy ?? codexSandboxPolicyForTurn(options.appServer.sandbox, options.cwd) },
2374
- model: modelSelection.model,
2375
- personality: CODEX_NATIVE_PERSONALITY_NONE,
2786
+ ...modelSelection ? {
2787
+ model: modelSelection.model,
2788
+ personality: CODEX_NATIVE_PERSONALITY_NONE
2789
+ } : {},
2376
2790
  ...options.appServer.serviceTier !== void 0 ? { serviceTier: options.appServer.serviceTier } : {},
2377
- effort: resolveReasoningEffort(params.thinkLevel, modelSelection.model, readCodexSupportedReasoningEfforts(params.model?.compat)),
2791
+ ...modelSelection ? { effort: resolveReasoningEffort(params.thinkLevel, modelSelection.model, readCodexSupportedReasoningEfforts(params.model?.compat)) } : {},
2378
2792
  ...options.environmentSelection ? { environments: options.environmentSelection } : {},
2379
- collaborationMode: buildTurnCollaborationMode(params, {
2793
+ ...modelSelection ? { collaborationMode: buildTurnCollaborationMode(params, {
2380
2794
  model: modelSelection.model,
2381
2795
  turnScopedDeveloperInstructions: options.turnScopedDeveloperInstructions,
2382
2796
  skillsCollaborationInstructions: options.skillsCollaborationInstructions,
2383
2797
  memoryCollaborationInstructions: options.memoryCollaborationInstructions,
2384
2798
  heartbeatCollaborationInstructions: options.heartbeatCollaborationInstructions
2385
- })
2799
+ }) } : {}
2386
2800
  };
2387
2801
  }
2388
2802
  function resolveCodexThreadApprovalsReviewer(appServer, config) {
@@ -2467,7 +2881,23 @@ function legacyFingerprintUserMcpServersConfigPatch(configPatch) {
2467
2881
  return configPatch ? JSON.stringify(stabilizeJsonValue(configPatch)) : void 0;
2468
2882
  }
2469
2883
  function fingerprintUserMcpServersConfigPatch(configPatch) {
2470
- return configPatch ? hashCodexAppServerBindingFingerprint(JSON.stringify(stabilizeJsonValue(configPatch))) : void 0;
2884
+ return configPatch ? hashCodexAppServerBindingFingerprint(JSON.stringify(stabilizeJsonValue(redactUserMcpServersFingerprintSecrets(configPatch)))) : void 0;
2885
+ }
2886
+ function redactUserMcpServersFingerprintSecrets(value) {
2887
+ if (Array.isArray(value)) return value.map(redactUserMcpServersFingerprintSecrets);
2888
+ if (!value || typeof value !== "object") return value;
2889
+ const next = {};
2890
+ for (const [key, entry] of Object.entries(value)) {
2891
+ if (key === "http_headers" && entry && typeof entry === "object" && !Array.isArray(entry)) {
2892
+ next[key] = Object.fromEntries(Object.entries(entry).map(([header, headerValue]) => [header, header.toLowerCase() === "authorization" ? fingerprintUserMcpServersAuthorizationHeader(headerValue) : headerValue]));
2893
+ continue;
2894
+ }
2895
+ next[key] = redactUserMcpServersFingerprintSecrets(entry);
2896
+ }
2897
+ return next;
2898
+ }
2899
+ function fingerprintUserMcpServersAuthorizationHeader(value) {
2900
+ return typeof value === "string" && value.length > 0 ? `<redacted:sha256:${crypto$1.createHash("sha256").update(value).digest("hex")}>` : "<redacted>";
2471
2901
  }
2472
2902
  function fingerprintJsonObject(value) {
2473
2903
  return JSON.stringify(stabilizeJsonValue(value));
@@ -2541,7 +2971,7 @@ function buildSkillWorkshopInstruction(dynamicTools) {
2541
2971
  }
2542
2972
  function buildVisibleReplyInstruction(params, dynamicTools) {
2543
2973
  const messageToolAvailable = dynamicTools ? flattenCodexDynamicToolFunctions(dynamicTools).some((tool) => tool.name.trim() === "message") : params.disableMessageTool !== true;
2544
- if (params.sourceReplyDeliveryMode === "message_tool_only" && messageToolAvailable) return "Visible source replies are not automatically delivered for this run. Use `message(action=send)` for user-visible source-channel output. Do not repeat that visible content in your final answer.";
2974
+ if (params.sourceReplyDeliveryMode === "message_tool_only" && messageToolAvailable) return "Visible source replies are not automatically delivered for this run. Use `message(action=send)` for user-visible source-channel output. For progress, set `final=false`. When the message is the completed reply to the current source conversation, set `final=true`; OpenClaw stops after confirming delivery. Do not repeat that visible content in your final answer.";
2545
2975
  if (messageToolAvailable) return "For the current source conversation, reply normally in your final assistant message; OpenClaw will deliver it through the active source conversation. Use `message` only for explicit out-of-band sends, media/file sends, or sends to a different target.";
2546
2976
  return "For the current source conversation, reply normally in your final assistant message; OpenClaw will deliver it through the active source conversation.";
2547
2977
  }
@@ -2587,4 +3017,4 @@ function resolveReasoningEffort(thinkLevel, modelId, supportedReasoningEfforts)
2587
3017
  return null;
2588
3018
  }
2589
3019
  //#endregion
2590
- export { resolveCodexContextEngineProjectionMaxChars as A, buildCodexPluginThreadConfig as B, filterCodexDynamicTools as C, resolveCodexDynamicToolsLoadingForRuntime as D, resolveCodexDynamicToolsLoading as E, closeCodexStartupClientBestEffort as F, pluginReadParams as G, mergeCodexThreadConfigs as H, interruptCodexTurnBestEffort as I, buildCodexAppInventoryCacheKey as K, retireCodexAppServerClientAfterTimedOutTurn as L, CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS as M, CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS as N, fitCodexProjectedContextForTurnStart as O, CodexAppServerUnsafeSubscriptionError as P, unsubscribeCodexThreadBestEffort as R, sanitizeInlineImageDataUrl$1 as S, normalizeCodexDynamicToolName as T, shouldBuildCodexPluginThreadConfig as U, buildCodexPluginThreadConfigInputFingerprint as V, ensureCodexPluginActivation as W, buildCodexNativeWebSearchThreadConfig as _, buildDeveloperInstructions as a, invalidInlineImageText as b, codexDynamicToolsFingerprint as c, resolveCodexAppServerModelProvider as d, resolveCodexAppServerRequestModelSelection as f, startOrResumeThread as g, resolveReasoningEffort as h, buildContextEngineBinding as i, resolveCodexContextEngineProjectionReserveTokens as j, projectContextEngineAssemblyForCodex as k, codexLegacyDynamicToolsFingerprint as l, resolveCodexBindingModelProviderFallback as m, areCodexDynamicToolFingerprintsCompatible as n, buildTurnCollaborationMode as o, resolveCodexAppServerThreadModelSelection as p, defaultCodexAppInventoryCache as q, buildCodexRuntimeThreadConfig as r, buildTurnStartParams as s, CODEX_NATIVE_PERSONALITY_NONE as t, isContextEngineBindingCompatible as u, resolveCodexWebSearchPlan as v, isForcedPrivateQaCodexRuntime as w, sanitizeCodexHistoryImagePayloads as x, isCodexAppServerProfilerEnabled as y, buildCodexPluginAppsConfigPatchFromPolicyContext as z };
3020
+ export { fitCodexProjectedContextForTurnStart as A, unsubscribeCodexThreadBestEffort as B, sanitizeInlineImageDataUrl$1 as C, normalizeCodexDynamicToolName as D, isSystemAgentOnlyCodexDynamicToolAllowlist as E, CODEX_APP_SERVER_UNSUBSCRIBE_TIMEOUT_MS as F, shouldBuildCodexPluginThreadConfig as G, buildCodexPluginThreadConfig as H, CodexAppServerUnsafeSubscriptionError as I, ensureCodexPluginActivation as K, closeCodexStartupClientBestEffort as L, resolveCodexContextEngineProjectionMaxChars as M, resolveCodexContextEngineProjectionReserveTokens as N, resolveCodexDynamicToolsLoading as O, CODEX_APP_SERVER_INTERRUPT_TIMEOUT_MS as P, interruptCodexTurnBestEffort as R, sanitizeCodexHistoryImagePayloads as S, isForcedPrivateQaCodexRuntime as T, buildCodexPluginThreadConfigInputFingerprint as U, buildCodexPluginAppsConfigPatchFromPolicyContext as V, mergeCodexThreadConfigs as W, buildCodexNativeWebSearchThreadConfig as _, buildDeveloperInstructions as a, isCodexAppServerProfilerEnabled as b, codexDynamicToolsFingerprint as c, resolveCodexAppServerModelProvider as d, resolveCodexAppServerRequestModelSelection as f, startOrResumeThread as g, resolveReasoningEffort as h, buildContextEngineBinding as i, projectContextEngineAssemblyForCodex as j, resolveCodexDynamicToolsLoadingForRuntime as k, codexLegacyDynamicToolsFingerprint as l, resolveCodexBindingModelProviderFallback as m, areCodexDynamicToolFingerprintsCompatible as n, buildTurnCollaborationMode as o, resolveCodexAppServerThreadModelSelection as p, pluginReadParams as q, buildCodexRuntimeThreadConfig as r, buildTurnStartParams as s, CODEX_NATIVE_PERSONALITY_NONE as t, isContextEngineBindingCompatible as u, resolveCodexWebSearchPlan as v, filterCodexDynamicTools as w, invalidInlineImageText as x, resumeCodexAppServerThread as y, retireCodexAppServerClientAfterTimedOutTurn as z };