@openclaw/codex 2026.6.8-beta.2 → 2026.6.9-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 (34) hide show
  1. package/dist/{notification-correlation-BGoG0N90.js → app-server-policy-KpyUye2D.js} +15 -74
  2. package/dist/attempt-notifications-Meja3TX6.js +249 -0
  3. package/dist/{client-factory-C71Xdb6z.js → client-factory-CPuoOOx6.js} +3 -2
  4. package/dist/{client-DovmVtbr.js → client-m7XiCQpO.js} +24 -2
  5. package/dist/{command-handlers-DHecBkuc.js → command-handlers-CqS0Kv3Z.js} +17 -13
  6. package/dist/{compact-GEKusemL.js → compact-CMVlldii.js} +5 -5
  7. package/dist/{computer-use-D1qxvTE_.js → computer-use-qLm7Gf35.js} +3 -3
  8. package/dist/{config-DJXpBkGf.js → config-BksX0T33.js} +160 -20
  9. package/dist/{conversation-binding-CbnMilVW.js → conversation-binding-DBof5w9J.js} +166 -58
  10. package/dist/doctor-contract-api.js +37 -3
  11. package/dist/harness.js +6 -6
  12. package/dist/index.js +108 -27
  13. package/dist/media-understanding-provider-CiwPkR58.js +463 -0
  14. package/dist/media-understanding-provider.js +1 -355
  15. package/dist/{models-DRKnOpzF.js → models-BsyV1Psm.js} +2 -2
  16. package/dist/{plugin-app-cache-key-kIqpGTQj.js → plugin-app-cache-key-CN9zBiCG.js} +17 -6
  17. package/dist/{protocol-oeJQu4rs.js → protocol-dh-ETiNd.js} +4 -1
  18. package/dist/{protocol-validators-B48C6S9O.js → protocol-validators-B19q5BIX.js} +210 -16
  19. package/dist/{native-hook-relay-C3i3FYtc.js → provider-capabilities-BOvTfMhF.js} +803 -78
  20. package/dist/{provider-C5P6352f.js → provider-qJygHQx4.js} +4 -4
  21. package/dist/provider.js +1 -1
  22. package/dist/{request-BxZ40QKY.js → request-DTIEyUrA.js} +2 -2
  23. package/dist/{run-attempt-D_q-VrpR.js → run-attempt-DRhB6bTc.js} +421 -774
  24. package/dist/{sandbox-guard-C-Yv9uwY.js → sandbox-guard-3tnjhjFb.js} +37 -10
  25. package/dist/{session-binding-ElbcSq2o.js → session-binding-BRUi8y6E.js} +27 -8
  26. package/dist/{shared-client-jFMumCOe.js → shared-client-Bg5d7VV9.js} +4 -4
  27. package/dist/{side-question-DqKLfWMB.js → side-question-BdYL4kj1.js} +106 -42
  28. package/dist/{thread-lifecycle-cban34w3.js → thread-lifecycle-CbJqqnEw.js} +912 -616
  29. package/dist/web-search-contract-api.js +10 -0
  30. package/dist/web-search-provider.runtime-DrpQ8Cyd.js +74 -0
  31. package/dist/web-search-provider.shared-BrZmlqyR.js +32 -0
  32. package/npm-shrinkwrap.json +2 -2
  33. package/openclaw.plugin.json +129 -4
  34. package/package.json +13 -5
@@ -1,35 +1,38 @@
1
- import { d as resolveCodexAppServerRuntimeOptions, h as resolveOpenClawExecPolicyForCodexAppServer, i as codexSandboxPolicyForTurn, n as canUseCodexModelBackedApprovalsReviewerForModel, o as isCodexFastServiceTier, p as resolveCodexModelBackedReviewerPolicyContext } from "./config-DJXpBkGf.js";
2
- import { t as isJsonObject } from "./protocol-oeJQu4rs.js";
3
- import { d as resolveCodexAppServerRequestModelSelection, f as resolveCodexBindingModelProviderFallback, t as CODEX_NATIVE_PERSONALITY_NONE } from "./thread-lifecycle-cban34w3.js";
4
- import { a as normalizeCodexAppServerBindingModelProvider, i as isCodexAppServerNativeAuthProfile, l as writeCodexAppServerBinding, n as clearCodexAppServerBinding, o as readCodexAppServerBinding } from "./session-binding-ElbcSq2o.js";
5
- import { n as CODEX_CONTROL_METHODS } from "./plugin-app-cache-key-kIqpGTQj.js";
6
- import { a as resolveCodexAppServerForModelProvider, i as readCodexNotificationTurnId, l as formatCodexDisplayText, r as readCodexNotificationThreadId } from "./notification-correlation-BGoG0N90.js";
7
- import { a as getLeasedSharedCodexAppServerClient, o as releaseLeasedSharedCodexAppServerClient, p as resolveCodexAppServerAuthProfileIdForAgent } from "./shared-client-jFMumCOe.js";
8
- import { n as resolveCodexNativeExecutionBlock, r as resolveCodexNativeSandboxBlock } from "./sandbox-guard-C-Yv9uwY.js";
1
+ import { n as isJsonObject } from "./protocol-dh-ETiNd.js";
2
+ import { B as readCodexNotificationThreadId, V as readCodexNotificationTurnId, d as resolveCodexAppServerRequestModelSelection, p as resolveCodexBindingModelProviderFallback, t as CODEX_NATIVE_PERSONALITY_NONE } from "./thread-lifecycle-CbJqqnEw.js";
3
+ import { d as resolveCodexAppServerRuntimeOptions, h as resolveOpenClawExecPolicyForCodexAppServer, i as codexSandboxPolicyForTurn, n as canUseCodexModelBackedApprovalsReviewerForModel, o as isCodexFastServiceTier, p as resolveCodexModelBackedReviewerPolicyContext } from "./config-BksX0T33.js";
4
+ import { r as assertCodexThreadStartResponse } from "./protocol-validators-B19q5BIX.js";
5
+ import { a as normalizeCodexAppServerBindingModelProvider, i as isCodexAppServerNativeAuthProfile, l as writeCodexAppServerBinding, n as clearCodexAppServerBinding, o as readCodexAppServerBinding } from "./session-binding-BRUi8y6E.js";
6
+ import { r as CODEX_CONTROL_METHODS } from "./plugin-app-cache-key-CN9zBiCG.js";
7
+ import { a as formatCodexDisplayText, t as resolveCodexAppServerForModelProvider } from "./app-server-policy-KpyUye2D.js";
8
+ import { a as getLeasedSharedCodexAppServerClient, o as releaseLeasedSharedCodexAppServerClient, p as resolveCodexAppServerAuthProfileIdForAgent } from "./shared-client-Bg5d7VV9.js";
9
+ import { n as resolveCodexNativeExecutionBlock, r as resolveCodexNativeSandboxBlock } from "./sandbox-guard-3tnjhjFb.js";
10
+ import fs from "node:fs/promises";
11
+ import path from "node:path";
9
12
  import { resolveTimerTimeoutMs, timestampMsToIsoString } from "openclaw/plugin-sdk/number-runtime";
13
+ import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/temp-path";
14
+ import { asOptionalRecord, isRecord, normalizeSingleOrTrimmedStringList } from "openclaw/plugin-sdk/string-coerce-runtime";
10
15
  import os from "node:os";
11
- import path from "node:path";
12
16
  import { resolveSessionAgentIds } from "openclaw/plugin-sdk/agent-runtime";
13
17
  import { loadExecApprovals } from "openclaw/plugin-sdk/exec-approvals-runtime";
14
- import { asOptionalRecord, isRecord, normalizeSingleOrTrimmedStringList } from "openclaw/plugin-sdk/string-coerce-runtime";
15
18
  import { materializeWindowsSpawnProgram, resolveWindowsSpawnProgram } from "openclaw/plugin-sdk/windows-spawn";
16
19
  import { formatErrorMessage, resolveSandboxContext } from "openclaw/plugin-sdk/agent-harness-runtime";
17
20
  import { spawn } from "node:child_process";
18
- import fs from "node:fs/promises";
19
21
  import { loadSessionStore, resolveSessionStoreEntry, resolveStorePath } from "openclaw/plugin-sdk/session-store-runtime";
20
22
  import { fileURLToPath } from "node:url";
21
23
  import process$1 from "node:process";
22
- import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/temp-path";
23
24
  //#region extensions/codex/src/conversation-binding-data.ts
24
25
  const BINDING_DATA_VERSION = 1;
25
26
  function createCodexConversationBindingData(params) {
26
27
  const agentDir = params.agentDir?.trim();
28
+ const agentId = params.agentId?.trim();
27
29
  return {
28
30
  kind: "codex-app-server-session",
29
31
  version: BINDING_DATA_VERSION,
30
32
  sessionFile: params.sessionFile,
31
33
  workspaceDir: params.workspaceDir,
32
- ...agentDir ? { agentDir } : {}
34
+ ...agentDir ? { agentDir } : {},
35
+ ...agentId ? { agentId } : {}
33
36
  };
34
37
  }
35
38
  function createCodexCliNodeConversationBindingData(params) {
@@ -65,7 +68,8 @@ function readCodexConversationBindingDataRecord(data) {
65
68
  version: BINDING_DATA_VERSION,
66
69
  sessionFile: data.sessionFile,
67
70
  workspaceDir: typeof data.workspaceDir === "string" && data.workspaceDir.trim() ? data.workspaceDir : process$1.cwd(),
68
- agentDir: typeof data.agentDir === "string" && data.agentDir.trim() ? data.agentDir : void 0
71
+ agentDir: typeof data.agentDir === "string" && data.agentDir.trim() ? data.agentDir : void 0,
72
+ agentId: typeof data.agentId === "string" && data.agentId.trim() ? data.agentId : void 0
69
73
  };
70
74
  }
71
75
  function resolveCodexDefaultWorkspaceDir(pluginConfig) {
@@ -957,6 +961,11 @@ function formatNodeLabel(node) {
957
961
  //#endregion
958
962
  //#region extensions/codex/src/conversation-binding.ts
959
963
  const DEFAULT_BOUND_TURN_TIMEOUT_MS = 20 * 6e4;
964
+ const DEFAULT_AGENT_ID = "main";
965
+ const VALID_AGENT_ID_PATTERN = /^[a-z0-9][a-z0-9_-]{0,63}$/i;
966
+ const INVALID_AGENT_ID_CHARS_PATTERN = /[^a-z0-9_-]+/g;
967
+ const LEADING_DASH_PATTERN = /^-+/;
968
+ const TRAILING_DASH_PATTERN = /-+$/;
960
969
  const NATIVE_CONVERSATION_INTERACTIVE_APPROVALS_UNAVAILABLE = "OpenClaw native Codex conversation binding cannot route interactive approvals yet; use the Codex harness or explicit /acp spawn codex for that workflow.";
961
970
  async function resolveConversationAppServerRuntime(params) {
962
971
  const execPolicy = resolveConversationExecPolicy({
@@ -983,6 +992,7 @@ async function resolveConversationAppServerRuntime(params) {
983
992
  };
984
993
  }
985
994
  const CODEX_CONVERSATION_GLOBAL_STATE = Symbol.for("openclaw.codex.conversationBinding");
995
+ const CODEX_CONVERSATION_THREAD_DEVELOPER_INSTRUCTIONS = "This Codex thread is bound to an OpenClaw conversation. Answer normally; OpenClaw will deliver your final response back to the conversation.";
986
996
  function getGlobalState() {
987
997
  const globalState = globalThis;
988
998
  globalState[CODEX_CONVERSATION_GLOBAL_STATE] ??= { queues: /* @__PURE__ */ new Map() };
@@ -1013,7 +1023,8 @@ async function startCodexConversationThread(params) {
1013
1023
  sandbox: params.sandbox,
1014
1024
  serviceTier: params.serviceTier,
1015
1025
  config: params.config,
1016
- sessionKey: params.sessionKey
1026
+ sessionKey: params.sessionKey,
1027
+ agentId: params.agentId
1017
1028
  });
1018
1029
  else await createThread({
1019
1030
  pluginConfig: params.pluginConfig,
@@ -1027,12 +1038,14 @@ async function startCodexConversationThread(params) {
1027
1038
  sandbox: params.sandbox,
1028
1039
  serviceTier: params.serviceTier,
1029
1040
  config: params.config,
1030
- sessionKey: params.sessionKey
1041
+ sessionKey: params.sessionKey,
1042
+ agentId: params.agentId
1031
1043
  });
1032
1044
  return createCodexConversationBindingData({
1033
1045
  sessionFile: params.sessionFile,
1034
1046
  workspaceDir,
1035
- ...agentDir ? { agentDir } : {}
1047
+ ...agentDir ? { agentDir } : {},
1048
+ agentId: params.agentId
1036
1049
  });
1037
1050
  }
1038
1051
  async function handleCodexConversationInboundClaim(event, ctx, options = {}) {
@@ -1048,6 +1061,7 @@ async function handleCodexConversationInboundClaim(event, ctx, options = {}) {
1048
1061
  }) : resolveCodexNativeExecutionBlock({
1049
1062
  config: options.config,
1050
1063
  sessionKey: event.sessionKey ?? ctx.sessionKey,
1064
+ agentId: data.agentId,
1051
1065
  surface: "Codex app-server conversation binding"
1052
1066
  });
1053
1067
  if (nativeExecutionBlock) return {
@@ -1174,13 +1188,31 @@ async function resolveThreadBindingRuntime(params) {
1174
1188
  }
1175
1189
  function buildThreadRequestRuntimeOptions(params, resolved) {
1176
1190
  const serviceTier = params.serviceTier ?? resolved.runtime.serviceTier;
1191
+ const sandbox = resolved.execPolicy?.touched ? resolved.runtime.sandbox : params.sandbox ?? resolved.runtime.sandbox;
1177
1192
  return {
1178
1193
  approvalPolicy: resolved.execPolicy?.touched ? resolved.runtime.approvalPolicy : params.approvalPolicy ?? resolved.runtime.approvalPolicy,
1179
1194
  approvalsReviewer: resolved.runtime.approvalsReviewer,
1180
- sandbox: resolved.execPolicy?.touched ? resolved.runtime.sandbox : params.sandbox ?? resolved.runtime.sandbox,
1195
+ ...codexConversationSandboxOrPermissions(resolved.runtime, sandbox),
1181
1196
  ...serviceTier ? { serviceTier } : {}
1182
1197
  };
1183
1198
  }
1199
+ function codexConversationSandboxOrPermissions(runtime, sandbox) {
1200
+ const networkProxy = runtime.networkProxy;
1201
+ if (networkProxy) return { config: networkProxy.configPatch };
1202
+ return { sandbox };
1203
+ }
1204
+ async function requestNewConversationBindingThread(params, resolved) {
1205
+ return await resolved.client.request("thread/start", {
1206
+ cwd: params.workspaceDir,
1207
+ ...resolved.model ? { model: resolved.model } : {},
1208
+ ...resolved.modelProvider ? { modelProvider: resolved.modelProvider } : {},
1209
+ personality: CODEX_NATIVE_PERSONALITY_NONE,
1210
+ ...buildThreadRequestRuntimeOptions(params, resolved),
1211
+ developerInstructions: CODEX_CONVERSATION_THREAD_DEVELOPER_INSTRUCTIONS,
1212
+ experimentalRawEvents: true,
1213
+ persistExtendedHistory: true
1214
+ }, { timeoutMs: resolved.runtime.requestTimeoutMs });
1215
+ }
1184
1216
  async function writeThreadBindingFromResponse(params, resolved, response) {
1185
1217
  const runtimeApprovalPolicy = typeof resolved.runtime.approvalPolicy === "string" ? resolved.runtime.approvalPolicy : void 0;
1186
1218
  await writeCodexAppServerBinding(params.sessionFile, {
@@ -1195,13 +1227,15 @@ async function writeThreadBindingFromResponse(params, resolved, response) {
1195
1227
  }),
1196
1228
  approvalPolicy: resolved.execPolicy?.touched ? runtimeApprovalPolicy : params.approvalPolicy ?? runtimeApprovalPolicy,
1197
1229
  sandbox: resolved.execPolicy?.touched ? resolved.runtime.sandbox : params.sandbox ?? resolved.runtime.sandbox,
1198
- serviceTier: params.serviceTier ?? resolved.runtime.serviceTier
1230
+ serviceTier: params.serviceTier ?? resolved.runtime.serviceTier,
1231
+ networkProxyProfileName: resolved.runtime.networkProxy?.profileName,
1232
+ networkProxyConfigFingerprint: resolved.runtime.networkProxy?.configFingerprint
1199
1233
  }, { ...resolved.agentLookup });
1200
1234
  }
1201
1235
  async function attachExistingThread(params) {
1202
1236
  const resolved = await resolveThreadBindingRuntime(params);
1203
1237
  try {
1204
- await writeThreadBindingFromResponse(params, resolved, await resolved.client.request(CODEX_CONTROL_METHODS.resumeThread, {
1238
+ await writeThreadBindingFromResponse(params, resolved, resolved.runtime.networkProxy ? await requestNewConversationBindingThread(params, resolved) : await resolved.client.request(CODEX_CONTROL_METHODS.resumeThread, {
1205
1239
  threadId: params.threadId,
1206
1240
  ...resolved.model ? { model: resolved.model } : {},
1207
1241
  ...resolved.modelProvider ? { modelProvider: resolved.modelProvider } : {},
@@ -1216,16 +1250,7 @@ async function attachExistingThread(params) {
1216
1250
  async function createThread(params) {
1217
1251
  const resolved = await resolveThreadBindingRuntime(params);
1218
1252
  try {
1219
- await writeThreadBindingFromResponse(params, resolved, await resolved.client.request("thread/start", {
1220
- cwd: params.workspaceDir,
1221
- ...resolved.model ? { model: resolved.model } : {},
1222
- ...resolved.modelProvider ? { modelProvider: resolved.modelProvider } : {},
1223
- personality: CODEX_NATIVE_PERSONALITY_NONE,
1224
- ...buildThreadRequestRuntimeOptions(params, resolved),
1225
- developerInstructions: "This Codex thread is bound to an OpenClaw conversation. Answer normally; OpenClaw will deliver your final response back to the conversation.",
1226
- experimentalRawEvents: true,
1227
- persistExtendedHistory: true
1228
- }, { timeoutMs: resolved.runtime.requestTimeoutMs }));
1253
+ await writeThreadBindingFromResponse(params, resolved, await requestNewConversationBindingThread(params, resolved));
1229
1254
  } finally {
1230
1255
  releaseLeasedSharedCodexAppServerClient(resolved.client);
1231
1256
  }
@@ -1236,8 +1261,8 @@ async function runBoundTurn(params) {
1236
1261
  config: params.config
1237
1262
  });
1238
1263
  const binding = await readCodexAppServerBinding(params.data.sessionFile, agentLookup);
1239
- const threadId = binding?.threadId;
1240
- if (!threadId) throw new Error("bound Codex conversation has no thread binding");
1264
+ if (!binding?.threadId) throw new Error("bound Codex conversation has no thread binding");
1265
+ let threadId = binding.threadId;
1241
1266
  const workspaceDir = binding.cwd || params.data.workspaceDir;
1242
1267
  const reviewerModelProvider = resolveModelBackedReviewerPolicyProvider({
1243
1268
  authProfileId: binding.authProfileId,
@@ -1247,6 +1272,7 @@ async function runBoundTurn(params) {
1247
1272
  const { execPolicy, runtime } = await resolveConversationAppServerRuntime({
1248
1273
  pluginConfig: params.pluginConfig,
1249
1274
  config: params.config,
1275
+ agentId: params.data.agentId,
1250
1276
  sessionKey: params.sessionKey,
1251
1277
  workspaceDir,
1252
1278
  modelProvider: reviewerModelProvider,
@@ -1271,6 +1297,11 @@ async function runBoundTurn(params) {
1271
1297
  const useModelScopedPolicy = execPolicy?.touched === true || modelBackedApprovalsReviewerUnavailable;
1272
1298
  const approvalPolicy = useModelScopedPolicy ? modelScopedRuntime.approvalPolicy : binding.approvalPolicy ?? modelScopedRuntime.approvalPolicy;
1273
1299
  const sandbox = useModelScopedPolicy ? modelScopedRuntime.sandbox : binding.sandbox ?? modelScopedRuntime.sandbox;
1300
+ const permissionProfile = modelScopedRuntime.networkProxy?.profileName;
1301
+ const networkProxyConfigFingerprint = modelScopedRuntime.networkProxy?.configFingerprint;
1302
+ const networkProxyBindingChanged = binding.networkProxyProfileName !== permissionProfile || binding.networkProxyConfigFingerprint !== networkProxyConfigFingerprint;
1303
+ const serviceTier = binding.serviceTier ?? runtime.serviceTier;
1304
+ let useStickyNetworkProfile = permissionProfile !== void 0 && binding.networkProxyProfileName === permissionProfile && binding.networkProxyConfigFingerprint === networkProxyConfigFingerprint;
1274
1305
  assertNativeConversationApprovalPolicySupported({
1275
1306
  execPolicy,
1276
1307
  approvalPolicy,
@@ -1289,30 +1320,65 @@ async function runBoundTurn(params) {
1289
1320
  authProfileId: binding.authProfileId,
1290
1321
  ...agentLookup
1291
1322
  });
1292
- const collector = createCodexConversationTurnCollector(threadId);
1293
- const notificationCleanup = client.addNotificationHandler((notification) => collector.handleNotification(notification));
1294
- const requestCleanup = client.addRequestHandler(async (request) => {
1295
- if (request.method === "item/tool/call") return {
1296
- contentItems: [{
1297
- type: "inputText",
1298
- text: "OpenClaw native Codex conversation binding does not expose dynamic OpenClaw tools yet."
1299
- }],
1300
- success: false
1301
- };
1302
- if (request.method === "item/commandExecution/requestApproval" || request.method === "item/fileChange/requestApproval") return {
1303
- decision: "decline",
1304
- reason: "OpenClaw native Codex conversation binding cannot route interactive approvals yet; use the Codex harness or explicit /acp spawn codex for that workflow."
1305
- };
1306
- if (request.method === "item/permissions/requestApproval") return {
1307
- permissions: {},
1308
- scope: "turn"
1309
- };
1310
- if (request.method.includes("requestApproval")) return {
1311
- decision: "decline",
1312
- reason: "OpenClaw native Codex conversation binding cannot route interactive approvals yet; use the Codex harness or explicit /acp spawn codex for that workflow."
1313
- };
1314
- });
1323
+ let notificationCleanup = () => void 0;
1324
+ let requestCleanup = () => void 0;
1315
1325
  try {
1326
+ if (networkProxyBindingChanged) {
1327
+ const response = assertCodexThreadStartResponse(await client.request("thread/start", {
1328
+ cwd: workspaceDir,
1329
+ ...modelSelection?.model ? { model: modelSelection.model } : {},
1330
+ ...modelSelection?.modelProvider ? { modelProvider: modelSelection.modelProvider } : {},
1331
+ personality: CODEX_NATIVE_PERSONALITY_NONE,
1332
+ approvalPolicy,
1333
+ approvalsReviewer: modelScopedRuntime.approvalsReviewer,
1334
+ ...modelScopedRuntime.networkProxy ? { config: modelScopedRuntime.networkProxy.configPatch } : { sandbox },
1335
+ ...serviceTier ? { serviceTier } : {},
1336
+ developerInstructions: CODEX_CONVERSATION_THREAD_DEVELOPER_INSTRUCTIONS,
1337
+ experimentalRawEvents: true,
1338
+ persistExtendedHistory: true
1339
+ }, { timeoutMs: runtime.requestTimeoutMs }));
1340
+ threadId = response.thread.id;
1341
+ await writeCodexAppServerBinding(params.data.sessionFile, {
1342
+ threadId,
1343
+ cwd: response.thread.cwd ?? workspaceDir,
1344
+ authProfileId: binding.authProfileId,
1345
+ model: response.model ?? modelSelection?.model ?? binding.model,
1346
+ modelProvider: normalizeCodexAppServerBindingModelProvider({
1347
+ authProfileId: binding.authProfileId,
1348
+ modelProvider: response.modelProvider ?? modelSelection?.modelProvider ?? binding.modelProvider,
1349
+ ...agentLookup
1350
+ }),
1351
+ approvalPolicy: typeof approvalPolicy === "string" ? approvalPolicy : void 0,
1352
+ sandbox,
1353
+ serviceTier,
1354
+ networkProxyProfileName: modelScopedRuntime.networkProxy?.profileName,
1355
+ networkProxyConfigFingerprint: modelScopedRuntime.networkProxy?.configFingerprint
1356
+ }, agentLookup);
1357
+ useStickyNetworkProfile = modelScopedRuntime.networkProxy !== void 0;
1358
+ }
1359
+ const collector = createCodexConversationTurnCollector(threadId);
1360
+ notificationCleanup = client.addNotificationHandler((notification) => collector.handleNotification(notification));
1361
+ requestCleanup = client.addRequestHandler(async (request) => {
1362
+ if (request.method === "item/tool/call") return {
1363
+ contentItems: [{
1364
+ type: "inputText",
1365
+ text: "OpenClaw native Codex conversation binding does not expose dynamic OpenClaw tools yet."
1366
+ }],
1367
+ success: false
1368
+ };
1369
+ if (request.method === "item/commandExecution/requestApproval" || request.method === "item/fileChange/requestApproval") return {
1370
+ decision: "decline",
1371
+ reason: "OpenClaw native Codex conversation binding cannot route interactive approvals yet; use the Codex harness or explicit /acp spawn codex for that workflow."
1372
+ };
1373
+ if (request.method === "item/permissions/requestApproval") return {
1374
+ permissions: {},
1375
+ scope: "turn"
1376
+ };
1377
+ if (request.method.includes("requestApproval")) return {
1378
+ decision: "decline",
1379
+ reason: "OpenClaw native Codex conversation binding cannot route interactive approvals yet; use the Codex harness or explicit /acp spawn codex for that workflow."
1380
+ };
1381
+ });
1316
1382
  const turnId = (await client.request("turn/start", {
1317
1383
  threadId,
1318
1384
  input: buildCodexConversationTurnInput({
@@ -1322,10 +1388,10 @@ async function runBoundTurn(params) {
1322
1388
  cwd: workspaceDir,
1323
1389
  approvalPolicy,
1324
1390
  approvalsReviewer: modelScopedRuntime.approvalsReviewer,
1325
- sandboxPolicy: codexSandboxPolicyForTurn(sandbox, workspaceDir),
1391
+ ...useStickyNetworkProfile ? {} : { sandboxPolicy: codexSandboxPolicyForTurn(sandbox, workspaceDir) },
1326
1392
  ...modelSelection?.model ? { model: modelSelection.model } : {},
1327
1393
  personality: CODEX_NATIVE_PERSONALITY_NONE,
1328
- ...binding.serviceTier ?? runtime.serviceTier ? { serviceTier: binding.serviceTier ?? runtime.serviceTier } : {}
1394
+ ...serviceTier ? { serviceTier } : {}
1329
1395
  }, { timeoutMs: runtime.requestTimeoutMs })).turn.id;
1330
1396
  const activeCleanup = trackCodexConversationActiveTurn({
1331
1397
  sessionFile: params.data.sessionFile,
@@ -1355,6 +1421,7 @@ async function runBoundTurnWithMissingThreadRecovery(params) {
1355
1421
  const binding = await readCodexAppServerBinding(params.data.sessionFile, agentLookup);
1356
1422
  const useCurrentRuntimePolicy = resolveConversationExecPolicy({
1357
1423
  config: params.config,
1424
+ agentId: params.data.agentId,
1358
1425
  sessionKey: params.sessionKey
1359
1426
  }).touched;
1360
1427
  await startCodexConversationThread({
@@ -1369,7 +1436,8 @@ async function runBoundTurnWithMissingThreadRecovery(params) {
1369
1436
  sandbox: useCurrentRuntimePolicy ? void 0 : binding?.sandbox,
1370
1437
  serviceTier: binding?.serviceTier,
1371
1438
  config: params.config,
1372
- sessionKey: params.sessionKey
1439
+ sessionKey: params.sessionKey,
1440
+ agentId: params.data.agentId
1373
1441
  });
1374
1442
  return await runBoundTurn(params);
1375
1443
  }
@@ -1393,6 +1461,11 @@ function resolveConversationExecPolicy(params) {
1393
1461
  function readSessionExecOverrides(params) {
1394
1462
  const sessionKey = params.sessionKey?.trim();
1395
1463
  if (!params.config || !sessionKey) return;
1464
+ if (!canReadSessionExecOverrides({
1465
+ config: params.config,
1466
+ agentId: params.agentId,
1467
+ sessionKey
1468
+ })) return;
1396
1469
  const entry = resolveSessionStoreEntry({
1397
1470
  store: loadSessionStore(resolveStorePath(params.config.session?.store, { agentId: params.agentId }), { skipCache: true }),
1398
1471
  sessionKey
@@ -1403,6 +1476,41 @@ function readSessionExecOverrides(params) {
1403
1476
  ask: entry.execAsk
1404
1477
  };
1405
1478
  }
1479
+ function canReadSessionExecOverrides(params) {
1480
+ const agentId = normalizeAgentIdOrDefault(params.agentId);
1481
+ if (!agentId) return true;
1482
+ const sessionAgentId = parseAgentIdFromSessionKey(params.sessionKey);
1483
+ if (!sessionAgentId) return isDefaultAgentSessionKeyForAgent({
1484
+ config: params.config,
1485
+ agentId
1486
+ });
1487
+ return sessionAgentId === agentId;
1488
+ }
1489
+ function parseAgentIdFromSessionKey(sessionKey) {
1490
+ const raw = sessionKey?.trim();
1491
+ if (!raw) return;
1492
+ const parts = raw.toLowerCase().split(":").filter(Boolean);
1493
+ if (parts.length < 3 || parts[0] !== "agent" || !parts[2]) return;
1494
+ return normalizeAgentIdOrDefault(parts[1]);
1495
+ }
1496
+ function isDefaultAgentSessionKeyForAgent(params) {
1497
+ return normalizeAgentId(params.agentId) === resolveDefaultPolicyAgentId(params.config);
1498
+ }
1499
+ function resolveDefaultPolicyAgentId(config) {
1500
+ const agents = (config.agents?.list ?? []).filter((entry) => entry !== null && typeof entry === "object");
1501
+ return normalizeAgentId((agents.find((entry) => entry?.default) ?? agents[0])?.id);
1502
+ }
1503
+ function normalizeAgentIdOrDefault(value) {
1504
+ const normalized = normalizeAgentId(value);
1505
+ return normalized === DEFAULT_AGENT_ID && !(value ?? "").trim() ? void 0 : normalized;
1506
+ }
1507
+ function normalizeAgentId(value) {
1508
+ const trimmed = (value ?? "").trim();
1509
+ if (!trimmed) return DEFAULT_AGENT_ID;
1510
+ const normalized = trimmed.toLowerCase();
1511
+ if (VALID_AGENT_ID_PATTERN.test(trimmed)) return normalized;
1512
+ return normalized.replace(INVALID_AGENT_ID_CHARS_PATTERN, "-").replace(LEADING_DASH_PATTERN, "").replace(TRAILING_DASH_PATTERN, "").slice(0, 64) || DEFAULT_AGENT_ID;
1513
+ }
1406
1514
  function isCodexThreadNotFoundError(error) {
1407
1515
  const message = formatErrorMessage(error);
1408
1516
  return /\bthread not found:/iu.test(message) || /\bbound Codex conversation has no thread binding\b/u.test(message);
@@ -5,6 +5,13 @@ function asRecord(value) {
5
5
  function hasRetiredDynamicToolsProfile(value) {
6
6
  return Object.hasOwn(asRecord(value) ?? {}, "codexDynamicToolsProfile");
7
7
  }
8
+ function hasLegacyPluginDestructivePolicy(value) {
9
+ const codexPlugins = asRecord(value);
10
+ if (!codexPlugins) return false;
11
+ if (codexPlugins.allow_destructive_actions === "on-request") return true;
12
+ const plugins = asRecord(codexPlugins.plugins);
13
+ return Object.values(plugins ?? {}).some((plugin) => asRecord(plugin)?.allow_destructive_actions === "on-request");
14
+ }
8
15
  /** Legacy Codex config keys that doctor should report or repair. */
9
16
  const legacyConfigRules = [{
10
17
  path: [
@@ -15,13 +22,26 @@ const legacyConfigRules = [{
15
22
  ],
16
23
  message: "plugins.entries.codex.config.codexDynamicToolsProfile is retired; Codex app-server always keeps Codex-native workspace tools native. Run \"openclaw doctor --fix\".",
17
24
  match: hasRetiredDynamicToolsProfile
25
+ }, {
26
+ path: [
27
+ "plugins",
28
+ "entries",
29
+ "codex",
30
+ "config",
31
+ "codexPlugins"
32
+ ],
33
+ message: "plugins.entries.codex.config.codexPlugins.allow_destructive_actions=\"on-request\" was renamed to \"auto\". Run \"openclaw doctor --fix\".",
34
+ match: hasLegacyPluginDestructivePolicy
18
35
  }];
19
36
  /**
20
37
  * Removes retired Codex plugin config keys while preserving unrelated config.
21
38
  */
22
39
  function normalizeCompatibilityConfig({ cfg }) {
23
40
  const rawPluginConfig = asRecord(asRecord(cfg.plugins?.entries?.codex)?.config);
24
- if (!rawPluginConfig || !hasRetiredDynamicToolsProfile(rawPluginConfig)) return {
41
+ const rawCodexPlugins = asRecord(rawPluginConfig?.codexPlugins);
42
+ const shouldRemoveDynamicToolsProfile = rawPluginConfig !== null && hasRetiredDynamicToolsProfile(rawPluginConfig);
43
+ const shouldRewriteDestructivePolicy = hasLegacyPluginDestructivePolicy(rawCodexPlugins);
44
+ if (!rawPluginConfig || !shouldRemoveDynamicToolsProfile && !shouldRewriteDestructivePolicy) return {
25
45
  config: cfg,
26
46
  changes: []
27
47
  };
@@ -31,10 +51,24 @@ function normalizeCompatibilityConfig({ cfg }) {
31
51
  config: cfg,
32
52
  changes: []
33
53
  };
34
- delete nextPluginConfig.codexDynamicToolsProfile;
54
+ const changes = [];
55
+ if (shouldRemoveDynamicToolsProfile) {
56
+ delete nextPluginConfig.codexDynamicToolsProfile;
57
+ changes.push("Removed retired plugins.entries.codex.config.codexDynamicToolsProfile; Codex app-server always keeps Codex-native workspace tools native.");
58
+ }
59
+ if (shouldRewriteDestructivePolicy) {
60
+ const nextCodexPlugins = asRecord(nextPluginConfig.codexPlugins);
61
+ if (nextCodexPlugins?.allow_destructive_actions === "on-request") nextCodexPlugins.allow_destructive_actions = "auto";
62
+ const nextPluginPolicies = asRecord(nextCodexPlugins?.plugins);
63
+ for (const plugin of Object.values(nextPluginPolicies ?? {})) {
64
+ const nextPlugin = asRecord(plugin);
65
+ if (nextPlugin?.allow_destructive_actions === "on-request") nextPlugin.allow_destructive_actions = "auto";
66
+ }
67
+ changes.push("Renamed plugins.entries.codex.config.codexPlugins allow_destructive_actions=\"on-request\" values to \"auto\".");
68
+ }
35
69
  return {
36
70
  config: nextConfig,
37
- changes: ["Removed retired plugins.entries.codex.config.codexDynamicToolsProfile; Codex app-server always keeps Codex-native workspace tools native."]
71
+ changes
38
72
  };
39
73
  }
40
74
  /** Session/auth ownership metadata used by doctor route-state checks. */
package/dist/harness.js CHANGED
@@ -32,25 +32,25 @@ function createCodexAppServerAgentHarness(options) {
32
32
  };
33
33
  },
34
34
  runAttempt: async (params) => {
35
- const { runCodexAppServerAttempt } = await import("./run-attempt-D_q-VrpR.js");
35
+ const { runCodexAppServerAttempt } = await import("./run-attempt-DRhB6bTc.js");
36
36
  return runCodexAppServerAttempt(params, {
37
37
  pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig,
38
38
  nativeHookRelay: { enabled: true }
39
39
  });
40
40
  },
41
41
  runSideQuestion: async (params) => {
42
- const { runCodexAppServerSideQuestion } = await import("./side-question-DqKLfWMB.js");
42
+ const { runCodexAppServerSideQuestion } = await import("./side-question-BdYL4kj1.js");
43
43
  return runCodexAppServerSideQuestion(params, {
44
44
  pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig,
45
45
  nativeHookRelay: { enabled: true }
46
46
  });
47
47
  },
48
48
  compact: async (params) => {
49
- const { maybeCompactCodexAppServerSession } = await import("./compact-GEKusemL.js");
49
+ const { maybeCompactCodexAppServerSession } = await import("./compact-CMVlldii.js");
50
50
  return maybeCompactCodexAppServerSession(params, { pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig });
51
51
  },
52
52
  compactAfterContextEngine: async (params) => {
53
- const { maybeCompactCodexAppServerSession } = await import("./compact-GEKusemL.js");
53
+ const { maybeCompactCodexAppServerSession } = await import("./compact-CMVlldii.js");
54
54
  return maybeCompactCodexAppServerSession(params, {
55
55
  pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig,
56
56
  allowNonManualNativeRequest: true
@@ -58,12 +58,12 @@ function createCodexAppServerAgentHarness(options) {
58
58
  },
59
59
  reset: async (params) => {
60
60
  if (params.sessionFile) {
61
- const { clearCodexAppServerBinding } = await import("./session-binding-ElbcSq2o.js").then((n) => n.s);
61
+ const { clearCodexAppServerBinding } = await import("./session-binding-BRUi8y6E.js").then((n) => n.s);
62
62
  await clearCodexAppServerBinding(params.sessionFile);
63
63
  }
64
64
  },
65
65
  dispose: async () => {
66
- const { clearSharedCodexAppServerClientAndWait } = await import("./shared-client-jFMumCOe.js").then((n) => n.c);
66
+ const { clearSharedCodexAppServerClientAndWait } = await import("./shared-client-Bg5d7VV9.js").then((n) => n.c);
67
67
  await clearSharedCodexAppServerClientAndWait();
68
68
  }
69
69
  };