@openclaw/codex 2026.5.7 → 2026.5.10-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.
@@ -1,13 +1,15 @@
1
- import { n as codexSandboxPolicyForTurn } from "./config-ByrA30No.js";
2
- import { n as assertCodexThreadStartResponse, t as assertCodexThreadResumeResponse } from "./protocol-validators-Dky2yV4W.js";
1
+ import { l as resolveCodexPluginsPolicy, r as codexSandboxPolicyForTurn } from "./config-CT01BBDc.js";
2
+ import { n as assertCodexThreadStartResponse, t as assertCodexThreadResumeResponse } from "./protocol-validators-CbqWfY5M.js";
3
3
  import { t as isJsonObject } from "./protocol-C9UWI98H.js";
4
4
  import { CODEX_GPT5_HEARTBEAT_PROMPT_OVERLAY, renderCodexPromptOverlay } from "./prompt-overlay.js";
5
5
  import { isModernCodexModel } from "./provider.js";
6
- import { i as isCodexAppServerConnectionClosedError } from "./client-BGbqC7jk.js";
7
- import { i as readCodexAppServerBinding, n as isCodexAppServerNativeAuthProfile, o as writeCodexAppServerBinding, t as clearCodexAppServerBinding } from "./session-binding-DuJYTJQy.js";
6
+ import { i as isCodexAppServerConnectionClosedError } from "./client-CTzy3Y6M.js";
7
+ import { i as readCodexAppServerBinding, n as isCodexAppServerNativeAuthProfile, o as writeCodexAppServerBinding, t as clearCodexAppServerBinding } from "./session-binding-B44KIZM2.js";
8
+ import { i as defaultCodexAppInventoryCache, n as readCodexPluginInventory, t as ensureCodexPluginActivation } from "./plugin-activation-CweAZa7r.js";
9
+ import crypto from "node:crypto";
8
10
  import { HEARTBEAT_RESPONSE_TOOL_NAME, createAgentToolResultMiddlewareRunner, createCodexAppServerToolResultExtensionRunner, embeddedAgentLog, extractToolResultMediaArtifact, filterToolResultMediaUrls, isMessagingTool, isMessagingToolSendAction, isToolWrappedWithBeforeToolCallHook, normalizeHeartbeatToolResponse, runAgentHarnessAfterToolCallHook, wrapToolWithBeforeToolCallHook } from "openclaw/plugin-sdk/agent-harness-runtime";
9
11
  //#region extensions/codex/src/app-server/dynamic-tool-profile.ts
10
- const CODEX_NATIVE_FIRST_DYNAMIC_TOOL_EXCLUDES = [
12
+ const CODEX_APP_SERVER_OWNED_DYNAMIC_TOOL_EXCLUDES = [
11
13
  "read",
12
14
  "write",
13
15
  "edit",
@@ -16,17 +18,27 @@ const CODEX_NATIVE_FIRST_DYNAMIC_TOOL_EXCLUDES = [
16
18
  "process",
17
19
  "update_plan"
18
20
  ];
19
- function applyCodexDynamicToolProfile(tools, config) {
21
+ const DYNAMIC_TOOL_NAME_ALIASES = {
22
+ bash: "exec",
23
+ "apply-patch": "apply_patch"
24
+ };
25
+ function normalizeCodexDynamicToolName(name) {
26
+ const normalized = name.trim().toLowerCase();
27
+ return DYNAMIC_TOOL_NAME_ALIASES[normalized] ?? normalized;
28
+ }
29
+ function filterCodexDynamicTools(tools, config) {
20
30
  const excludes = /* @__PURE__ */ new Set();
21
- if ((config.codexDynamicToolsProfile ?? "native-first") === "native-first") for (const name of CODEX_NATIVE_FIRST_DYNAMIC_TOOL_EXCLUDES) excludes.add(name);
31
+ for (const name of CODEX_APP_SERVER_OWNED_DYNAMIC_TOOL_EXCLUDES) excludes.add(name);
22
32
  for (const name of config.codexDynamicToolsExclude ?? []) {
23
- const trimmed = name.trim();
33
+ const trimmed = normalizeCodexDynamicToolName(name);
24
34
  if (trimmed) excludes.add(trimmed);
25
35
  }
26
- return excludes.size === 0 ? tools : tools.filter((tool) => !excludes.has(tool.name));
36
+ return excludes.size === 0 ? tools : tools.filter((tool) => !excludes.has(normalizeCodexDynamicToolName(tool.name)));
27
37
  }
28
38
  //#endregion
29
39
  //#region extensions/codex/src/app-server/dynamic-tools.ts
40
+ const CODEX_OPENCLAW_DYNAMIC_TOOL_NAMESPACE = "openclaw";
41
+ const ALWAYS_DIRECT_DYNAMIC_TOOL_NAMES = new Set(["sessions_yield"]);
30
42
  function createCodexDynamicToolBridge(params) {
31
43
  const toolResultHookContext = toToolResultHookContext(params.hookContext);
32
44
  const tools = params.tools.map((tool) => isToolWrappedWithBeforeToolCallHook(tool) ? tool : wrapToolWithBeforeToolCallHook(tool, params.hookContext));
@@ -44,11 +56,12 @@ function createCodexDynamicToolBridge(params) {
44
56
  ...toolResultHookContext
45
57
  });
46
58
  const legacyExtensionRunner = createCodexAppServerToolResultExtensionRunner(toolResultHookContext);
59
+ const directToolNames = new Set([...ALWAYS_DIRECT_DYNAMIC_TOOL_NAMES, ...params.directToolNames ?? []]);
47
60
  return {
48
- specs: tools.map((tool) => ({
49
- name: tool.name,
50
- description: tool.description,
51
- inputSchema: toJsonValue(tool.parameters)
61
+ specs: tools.map((tool) => createCodexDynamicToolSpec({
62
+ tool,
63
+ loading: params.loading ?? "searchable",
64
+ directToolNames
52
65
  })),
53
66
  telemetry,
54
67
  handleToolCall: async (call, options) => {
@@ -138,6 +151,19 @@ function createCodexDynamicToolBridge(params) {
138
151
  }
139
152
  };
140
153
  }
154
+ function createCodexDynamicToolSpec(params) {
155
+ const base = {
156
+ name: params.tool.name,
157
+ description: params.tool.description,
158
+ inputSchema: toJsonValue(params.tool.parameters)
159
+ };
160
+ if (params.loading === "direct" || params.directToolNames.has(params.tool.name)) return base;
161
+ return {
162
+ ...base,
163
+ namespace: CODEX_OPENCLAW_DYNAMIC_TOOL_NAMESPACE,
164
+ deferLoading: true
165
+ };
166
+ }
141
167
  function toToolResultHookContext(ctx) {
142
168
  const { agentId, sessionId, sessionKey, runId } = ctx ?? {};
143
169
  return {
@@ -271,15 +297,274 @@ function isCronAddAction(args) {
271
297
  return typeof action === "string" && action.trim().toLowerCase() === "add";
272
298
  }
273
299
  //#endregion
300
+ //#region extensions/codex/src/app-server/plugin-thread-config.ts
301
+ const CODEX_PLUGIN_THREAD_CONFIG_INPUT_FINGERPRINT_VERSION = 1;
302
+ const CODEX_PLUGIN_THREAD_CONFIG_FINGERPRINT_VERSION = 1;
303
+ function shouldBuildCodexPluginThreadConfig(pluginConfig) {
304
+ return resolveCodexPluginsPolicy(pluginConfig).configured;
305
+ }
306
+ function buildCodexPluginThreadConfigInputFingerprint(params) {
307
+ return fingerprintJson({
308
+ version: CODEX_PLUGIN_THREAD_CONFIG_INPUT_FINGERPRINT_VERSION,
309
+ policy: policyFingerprint(resolveCodexPluginsPolicy(params.pluginConfig)),
310
+ appCacheKey: params.appCacheKey ?? null
311
+ });
312
+ }
313
+ async function buildCodexPluginThreadConfig(params) {
314
+ const appCache = params.appCache ?? defaultCodexAppInventoryCache;
315
+ let inputFingerprint = buildCodexPluginThreadConfigInputFingerprint({
316
+ pluginConfig: params.pluginConfig,
317
+ appCacheKey: params.appCacheKey
318
+ });
319
+ const policy = resolveCodexPluginsPolicy(params.pluginConfig);
320
+ if (!policy.enabled) return emptyPluginThreadConfig({
321
+ enabled: false,
322
+ inputFingerprint,
323
+ configPatch: buildDisabledAppsConfigPatch()
324
+ });
325
+ let inventory = await readCodexPluginInventory({
326
+ pluginConfig: params.pluginConfig,
327
+ policy,
328
+ request: params.request,
329
+ appCache,
330
+ appCacheKey: params.appCacheKey,
331
+ nowMs: params.nowMs
332
+ });
333
+ if (shouldWaitForInitialAppInventory(params, policy, inventory)) {
334
+ await refreshAppInventoryNow(params, appCache);
335
+ inventory = await readCodexPluginInventory({
336
+ pluginConfig: params.pluginConfig,
337
+ policy,
338
+ request: params.request,
339
+ appCache,
340
+ appCacheKey: params.appCacheKey,
341
+ nowMs: params.nowMs
342
+ });
343
+ inputFingerprint = buildCodexPluginThreadConfigInputFingerprint({
344
+ pluginConfig: params.pluginConfig,
345
+ appCacheKey: params.appCacheKey
346
+ });
347
+ }
348
+ const activationDiagnostics = [];
349
+ const activationResults = [];
350
+ for (const record of inventory.records) {
351
+ if (!record.activationRequired) continue;
352
+ const activation = await ensureCodexPluginActivation({
353
+ identity: record.policy,
354
+ request: params.request,
355
+ appCache,
356
+ appCacheKey: params.appCacheKey
357
+ });
358
+ activationResults.push(activation);
359
+ if (!activation.ok) activationDiagnostics.push({
360
+ code: "plugin_activation_failed",
361
+ plugin: record.policy,
362
+ message: activation.diagnostics.map((item) => item.message).join(" ") || activation.reason
363
+ });
364
+ }
365
+ if (activationResults.some((activation) => activation.ok && activation.installAttempted)) {
366
+ await refreshAppInventoryNow(params, appCache, { forceRefetch: true });
367
+ inventory = await readCodexPluginInventory({
368
+ pluginConfig: params.pluginConfig,
369
+ policy,
370
+ request: params.request,
371
+ appCache,
372
+ appCacheKey: params.appCacheKey,
373
+ nowMs: params.nowMs
374
+ });
375
+ inputFingerprint = buildCodexPluginThreadConfigInputFingerprint({
376
+ pluginConfig: params.pluginConfig,
377
+ appCacheKey: params.appCacheKey
378
+ });
379
+ }
380
+ const diagnostics = [...inventory.diagnostics, ...activationDiagnostics];
381
+ const apps = { _default: {
382
+ enabled: false,
383
+ destructive_enabled: false,
384
+ open_world_enabled: false
385
+ } };
386
+ const policyApps = {};
387
+ const pluginAppIds = {};
388
+ for (const record of inventory.records) {
389
+ if (record.activationRequired) {
390
+ if (!activationResults.find((item) => item.identity.configKey === record.policy.configKey)?.ok) continue;
391
+ }
392
+ if (record.appOwnership !== "proven") continue;
393
+ pluginAppIds[record.policy.configKey] = [...record.ownedAppIds].toSorted();
394
+ for (const app of record.apps) {
395
+ if (!app.accessible || !app.enabled) {
396
+ diagnostics.push({
397
+ code: "app_not_ready",
398
+ plugin: record.policy,
399
+ message: `${app.id} is not accessible or enabled for ${record.policy.pluginName}.`
400
+ });
401
+ continue;
402
+ }
403
+ const appConfig = {
404
+ enabled: true,
405
+ destructive_enabled: record.policy.allowDestructiveActions,
406
+ open_world_enabled: true,
407
+ default_tools_approval_mode: "prompt"
408
+ };
409
+ apps[app.id] = appConfig;
410
+ policyApps[app.id] = {
411
+ configKey: record.policy.configKey,
412
+ marketplaceName: record.policy.marketplaceName,
413
+ pluginName: record.policy.pluginName,
414
+ allowDestructiveActions: record.policy.allowDestructiveActions,
415
+ mcpServerNames: [...record.detail?.mcpServers ?? []].toSorted()
416
+ };
417
+ }
418
+ }
419
+ const configPatch = { apps };
420
+ const policyContext = buildPluginAppPolicyContext(policyApps, pluginAppIds);
421
+ return {
422
+ enabled: true,
423
+ configPatch,
424
+ fingerprint: fingerprintJson({
425
+ version: CODEX_PLUGIN_THREAD_CONFIG_FINGERPRINT_VERSION,
426
+ inputFingerprint,
427
+ configPatch,
428
+ policyContext
429
+ }),
430
+ inputFingerprint,
431
+ policyContext,
432
+ inventory,
433
+ diagnostics
434
+ };
435
+ }
436
+ function mergeCodexThreadConfigs(...configs) {
437
+ let merged;
438
+ for (const config of configs) {
439
+ if (!config) continue;
440
+ merged = mergeJsonObjects(merged ?? {}, config);
441
+ }
442
+ return merged && Object.keys(merged).length > 0 ? merged : void 0;
443
+ }
444
+ function isCodexPluginThreadBindingStale(params) {
445
+ if (!params.codexPluginsEnabled) return Boolean(params.bindingFingerprint || params.bindingInputFingerprint || params.hasBindingPolicyContext);
446
+ if (!params.bindingFingerprint || !params.bindingInputFingerprint || !params.hasBindingPolicyContext) return true;
447
+ return params.bindingInputFingerprint !== params.currentInputFingerprint;
448
+ }
449
+ function emptyPluginThreadConfig(params) {
450
+ const policyContext = buildPluginAppPolicyContext({}, {});
451
+ return {
452
+ enabled: params.enabled,
453
+ fingerprint: fingerprintJson({
454
+ version: CODEX_PLUGIN_THREAD_CONFIG_FINGERPRINT_VERSION,
455
+ inputFingerprint: params.inputFingerprint,
456
+ configPatch: params.configPatch ?? null,
457
+ policyContext
458
+ }),
459
+ inputFingerprint: params.inputFingerprint,
460
+ ...params.configPatch ? { configPatch: params.configPatch } : {},
461
+ policyContext,
462
+ diagnostics: []
463
+ };
464
+ }
465
+ function buildDisabledAppsConfigPatch() {
466
+ return { apps: { _default: {
467
+ enabled: false,
468
+ destructive_enabled: false,
469
+ open_world_enabled: false
470
+ } } };
471
+ }
472
+ function buildPluginAppPolicyContext(apps, pluginAppIds) {
473
+ return {
474
+ fingerprint: fingerprintJson({
475
+ version: 1,
476
+ apps,
477
+ pluginAppIds
478
+ }),
479
+ apps,
480
+ pluginAppIds
481
+ };
482
+ }
483
+ function shouldWaitForInitialAppInventory(params, policy, inventory) {
484
+ return Boolean(params.appCacheKey && policy.pluginPolicies.some((plugin) => plugin.enabled) && inventory.appInventory?.state === "missing");
485
+ }
486
+ async function refreshAppInventoryNow(params, appCache, options = {}) {
487
+ const appCacheKey = params.appCacheKey;
488
+ if (!appCacheKey) return;
489
+ const request = async (method, requestParams) => await params.request(method, requestParams);
490
+ try {
491
+ await appCache.refreshNow({
492
+ key: appCacheKey,
493
+ request,
494
+ nowMs: params.nowMs,
495
+ forceRefetch: options.forceRefetch
496
+ });
497
+ } catch {}
498
+ }
499
+ function policyFingerprint(policy) {
500
+ return {
501
+ enabled: policy.enabled,
502
+ allowDestructiveActions: policy.allowDestructiveActions,
503
+ plugins: policy.pluginPolicies.map((plugin) => ({
504
+ configKey: plugin.configKey,
505
+ marketplaceName: plugin.marketplaceName,
506
+ pluginName: plugin.pluginName,
507
+ enabled: plugin.enabled,
508
+ allowDestructiveActions: plugin.allowDestructiveActions
509
+ }))
510
+ };
511
+ }
512
+ function mergeJsonObjects(left, right) {
513
+ const merged = { ...left };
514
+ for (const [key, value] of Object.entries(right)) {
515
+ const existing = merged[key];
516
+ merged[key] = isPlainJsonObject(existing) && isPlainJsonObject(value) ? mergeJsonObjects(existing, value) : value;
517
+ }
518
+ return merged;
519
+ }
520
+ function isPlainJsonObject(value) {
521
+ return Boolean(value && typeof value === "object" && !Array.isArray(value));
522
+ }
523
+ function fingerprintJson(value) {
524
+ return crypto.createHash("sha256").update(stableStringify(value)).digest("hex");
525
+ }
526
+ function stableStringify(value) {
527
+ if (Array.isArray(value)) return `[${value.map((item) => stableStringify(item)).join(",")}]`;
528
+ if (value && typeof value === "object") return `{${Object.entries(value).toSorted(([left], [right]) => left.localeCompare(right)).map(([key, item]) => `${JSON.stringify(key)}:${stableStringify(item)}`).join(",")}}`;
529
+ return JSON.stringify(value);
530
+ }
531
+ //#endregion
274
532
  //#region extensions/codex/src/app-server/thread-lifecycle.ts
275
533
  async function startOrResumeThread(params) {
276
534
  const dynamicToolsFingerprint = fingerprintDynamicTools(params.dynamicTools);
277
- const binding = await readCodexAppServerBinding(params.params.sessionFile, {
535
+ let binding = await readCodexAppServerBinding(params.params.sessionFile, {
278
536
  authProfileStore: params.params.authProfileStore,
279
537
  agentDir: params.params.agentDir,
280
538
  config: params.params.config
281
539
  });
282
540
  let preserveExistingBinding = false;
541
+ let prebuiltPluginThreadConfig;
542
+ if (binding?.threadId) {
543
+ let pluginBindingStale = isCodexPluginThreadBindingStale({
544
+ codexPluginsEnabled: params.pluginThreadConfig?.enabled ?? false,
545
+ bindingFingerprint: binding.pluginAppsFingerprint,
546
+ bindingInputFingerprint: binding.pluginAppsInputFingerprint,
547
+ currentInputFingerprint: params.pluginThreadConfig?.inputFingerprint,
548
+ hasBindingPolicyContext: Boolean(binding.pluginAppPolicyContext)
549
+ });
550
+ if (!pluginBindingStale && shouldRecheckRecoverablePluginBinding({
551
+ binding,
552
+ pluginThreadConfig: params.pluginThreadConfig
553
+ })) try {
554
+ prebuiltPluginThreadConfig = await params.pluginThreadConfig?.build();
555
+ pluginBindingStale = prebuiltPluginThreadConfig?.fingerprint !== binding.pluginAppsFingerprint;
556
+ } catch (error) {
557
+ embeddedAgentLog.warn("codex app-server plugin app config recovery check failed", {
558
+ error,
559
+ threadId: binding.threadId
560
+ });
561
+ }
562
+ if (pluginBindingStale) {
563
+ embeddedAgentLog.debug("codex app-server plugin app config changed; starting a new thread", { threadId: binding.threadId });
564
+ await clearCodexAppServerBinding(params.params.sessionFile);
565
+ binding = void 0;
566
+ }
567
+ }
283
568
  if (binding?.threadId) if (binding.dynamicToolsFingerprint && !areDynamicToolFingerprintsCompatible(binding.dynamicToolsFingerprint, dynamicToolsFingerprint)) {
284
569
  preserveExistingBinding = shouldStartTransientNoToolThread({
285
570
  previous: binding.dynamicToolsFingerprint,
@@ -314,6 +599,9 @@ async function startOrResumeThread(params) {
314
599
  model: params.params.modelId,
315
600
  modelProvider: response.modelProvider ?? fallbackModelProvider,
316
601
  dynamicToolsFingerprint,
602
+ pluginAppsFingerprint: binding.pluginAppsFingerprint,
603
+ pluginAppsInputFingerprint: binding.pluginAppsInputFingerprint,
604
+ pluginAppPolicyContext: binding.pluginAppPolicyContext,
317
605
  createdAt: binding.createdAt
318
606
  }, {
319
607
  authProfileStore: params.params.authProfileStore,
@@ -327,19 +615,24 @@ async function startOrResumeThread(params) {
327
615
  authProfileId: boundAuthProfileId,
328
616
  model: params.params.modelId,
329
617
  modelProvider: response.modelProvider ?? fallbackModelProvider,
330
- dynamicToolsFingerprint
618
+ dynamicToolsFingerprint,
619
+ pluginAppsFingerprint: binding.pluginAppsFingerprint,
620
+ pluginAppsInputFingerprint: binding.pluginAppsInputFingerprint,
621
+ pluginAppPolicyContext: binding.pluginAppPolicyContext
331
622
  };
332
623
  } catch (error) {
333
624
  if (isCodexAppServerConnectionClosedError(error)) throw error;
334
625
  embeddedAgentLog.warn("codex app-server thread resume failed; starting a new thread", { error });
335
626
  await clearCodexAppServerBinding(params.params.sessionFile);
336
627
  }
628
+ const pluginThreadConfig = params.pluginThreadConfig?.enabled ? prebuiltPluginThreadConfig ?? await params.pluginThreadConfig.build() : void 0;
629
+ const config = mergeCodexThreadConfigs(params.config, pluginThreadConfig?.configPatch);
337
630
  const response = assertCodexThreadStartResponse(await params.client.request("thread/start", buildThreadStartParams(params.params, {
338
631
  cwd: params.cwd,
339
632
  dynamicTools: params.dynamicTools,
340
633
  appServer: params.appServer,
341
634
  developerInstructions: params.developerInstructions,
342
- config: params.config
635
+ config
343
636
  })));
344
637
  const modelProvider = resolveCodexAppServerModelProvider({
345
638
  provider: params.params.provider,
@@ -356,6 +649,9 @@ async function startOrResumeThread(params) {
356
649
  model: response.model ?? params.params.modelId,
357
650
  modelProvider: response.modelProvider ?? modelProvider,
358
651
  dynamicToolsFingerprint,
652
+ pluginAppsFingerprint: pluginThreadConfig?.fingerprint,
653
+ pluginAppsInputFingerprint: pluginThreadConfig?.inputFingerprint,
654
+ pluginAppPolicyContext: pluginThreadConfig?.policyContext,
359
655
  createdAt
360
656
  }, {
361
657
  authProfileStore: params.params.authProfileStore,
@@ -371,10 +667,21 @@ async function startOrResumeThread(params) {
371
667
  model: response.model ?? params.params.modelId,
372
668
  modelProvider: response.modelProvider ?? modelProvider,
373
669
  dynamicToolsFingerprint,
670
+ pluginAppsFingerprint: pluginThreadConfig?.fingerprint,
671
+ pluginAppsInputFingerprint: pluginThreadConfig?.inputFingerprint,
672
+ pluginAppPolicyContext: pluginThreadConfig?.policyContext,
374
673
  createdAt,
375
674
  updatedAt: createdAt
376
675
  };
377
676
  }
677
+ function shouldRecheckRecoverablePluginBinding(params) {
678
+ if (!params.pluginThreadConfig?.enabled) return false;
679
+ if (!params.binding.pluginAppsFingerprint || !params.binding.pluginAppsInputFingerprint || params.binding.pluginAppsInputFingerprint !== params.pluginThreadConfig.inputFingerprint) return false;
680
+ const policyContext = params.binding.pluginAppPolicyContext;
681
+ if (!policyContext) return false;
682
+ const expectedPluginConfigKeys = params.pluginThreadConfig.enabledPluginConfigKeys ?? [];
683
+ return Object.keys(policyContext.apps).length === 0 || expectedPluginConfigKeys.length > 0;
684
+ }
378
685
  function buildThreadStartParams(params, options) {
379
686
  const modelProvider = resolveCodexAppServerModelProvider({
380
687
  provider: params.provider,
@@ -445,7 +752,11 @@ function buildTurnCollaborationMode(params) {
445
752
  };
446
753
  }
447
754
  function buildHeartbeatCollaborationInstructions() {
448
- return ["This is an OpenClaw heartbeat turn. Apply these instructions only to this heartbeat wake; ordinary chat turns should stay in Codex Default mode.", CODEX_GPT5_HEARTBEAT_PROMPT_OVERLAY].join("\n\n");
755
+ return [
756
+ "This is an OpenClaw heartbeat turn. Apply these instructions only to this heartbeat wake; ordinary chat turns should stay in Codex Default mode.",
757
+ "When you are ready to end the heartbeat, prefer the structured `heartbeat_respond` tool so OpenClaw can record the wake outcome and notification decision. If `heartbeat_respond` is not already available and `tool_search` is available, search for `heartbeat_respond`, load it, then call it. Use `notify=false` when nothing should visibly interrupt the user.",
758
+ CODEX_GPT5_HEARTBEAT_PROMPT_OVERLAY
759
+ ].join("\n\n");
449
760
  }
450
761
  function codexDynamicToolsFingerprint(dynamicTools) {
451
762
  return fingerprintDynamicTools(dynamicTools);
@@ -535,4 +846,4 @@ function resolveReasoningEffort(thinkLevel, modelId) {
535
846
  return null;
536
847
  }
537
848
  //#endregion
538
- export { buildTurnStartParams as a, createCodexDynamicToolBridge as c, buildThreadStartParams as i, applyCodexDynamicToolProfile as l, buildDeveloperInstructions as n, codexDynamicToolsFingerprint as o, buildThreadResumeParams as r, startOrResumeThread as s, areCodexDynamicToolFingerprintsCompatible as t };
849
+ export { buildTurnStartParams as a, buildCodexPluginThreadConfig as c, createCodexDynamicToolBridge as d, filterCodexDynamicTools as f, buildThreadStartParams as i, buildCodexPluginThreadConfigInputFingerprint as l, buildDeveloperInstructions as n, codexDynamicToolsFingerprint as o, normalizeCodexDynamicToolName as p, buildThreadResumeParams as r, startOrResumeThread as s, areCodexDynamicToolFingerprintsCompatible as t, shouldBuildCodexPluginThreadConfig as u };
@@ -15,7 +15,7 @@
15
15
  }
16
16
  }
17
17
  },
18
- "providerDiscoveryEntry": "./provider-discovery.ts",
18
+ "providerCatalogEntry": "./provider-discovery.ts",
19
19
  "syntheticAuthRefs": ["codex"],
20
20
  "nonSecretAuthMarkers": ["codex-app-server"],
21
21
  "activation": {
@@ -33,10 +33,10 @@
33
33
  "type": "object",
34
34
  "additionalProperties": false,
35
35
  "properties": {
36
- "codexDynamicToolsProfile": {
36
+ "codexDynamicToolsLoading": {
37
37
  "type": "string",
38
- "enum": ["native-first", "openclaw-compat"],
39
- "default": "native-first"
38
+ "enum": ["searchable", "direct"],
39
+ "default": "searchable"
40
40
  },
41
41
  "codexDynamicToolsExclude": {
42
42
  "type": "array",
@@ -91,6 +91,42 @@
91
91
  }
92
92
  }
93
93
  },
94
+ "codexPlugins": {
95
+ "type": "object",
96
+ "additionalProperties": false,
97
+ "properties": {
98
+ "enabled": {
99
+ "type": "boolean",
100
+ "default": false
101
+ },
102
+ "allow_destructive_actions": {
103
+ "type": "boolean",
104
+ "default": false
105
+ },
106
+ "plugins": {
107
+ "type": "object",
108
+ "additionalProperties": {
109
+ "type": "object",
110
+ "additionalProperties": false,
111
+ "properties": {
112
+ "enabled": {
113
+ "type": "boolean"
114
+ },
115
+ "marketplaceName": {
116
+ "type": "string",
117
+ "enum": ["openai-curated"]
118
+ },
119
+ "pluginName": {
120
+ "type": "string"
121
+ },
122
+ "allow_destructive_actions": {
123
+ "type": "boolean"
124
+ }
125
+ }
126
+ }
127
+ }
128
+ }
129
+ },
94
130
  "appServer": {
95
131
  "type": "object",
96
132
  "additionalProperties": false,
@@ -130,6 +166,11 @@
130
166
  "minimum": 1,
131
167
  "default": 60000
132
168
  },
169
+ "turnCompletionIdleTimeoutMs": {
170
+ "type": "number",
171
+ "minimum": 1,
172
+ "default": 60000
173
+ },
133
174
  "approvalPolicy": {
134
175
  "type": "string",
135
176
  "enum": ["never", "on-request", "on-failure", "untrusted"]
@@ -142,7 +183,7 @@
142
183
  "type": "string",
143
184
  "enum": ["user", "auto_review", "guardian_subagent"]
144
185
  },
145
- "serviceTier": { "type": ["string", "null"], "enum": ["fast", "flex", null] },
186
+ "serviceTier": { "type": ["string", "null"] },
146
187
  "defaultWorkspaceDir": {
147
188
  "type": "string"
148
189
  }
@@ -151,9 +192,9 @@
151
192
  }
152
193
  },
153
194
  "uiHints": {
154
- "codexDynamicToolsProfile": {
155
- "label": "Dynamic Tools Profile",
156
- "help": "Select which OpenClaw dynamic tools are exposed to Codex app-server. native-first omits tools Codex already owns.",
195
+ "codexDynamicToolsLoading": {
196
+ "label": "Dynamic Tools Loading",
197
+ "help": "Use searchable to defer OpenClaw dynamic tools behind Codex tool search, or direct to expose them in the initial context.",
157
198
  "advanced": true
158
199
  },
159
200
  "codexDynamicToolsExclude": {
@@ -219,6 +260,26 @@
219
260
  "help": "MCP server name exposed by the Computer Use plugin.",
220
261
  "advanced": true
221
262
  },
263
+ "codexPlugins": {
264
+ "label": "Native Codex Plugins",
265
+ "help": "Controls native Codex plugin availability for Codex harness turns.",
266
+ "advanced": true
267
+ },
268
+ "codexPlugins.enabled": {
269
+ "label": "Enable Native Plugins",
270
+ "help": "Expose explicit migrated Codex plugin entries to Codex harness turns.",
271
+ "advanced": true
272
+ },
273
+ "codexPlugins.allow_destructive_actions": {
274
+ "label": "Allow Destructive Plugin Actions",
275
+ "help": "Default policy for plugin app write or destructive action elicitations. Defaults to false.",
276
+ "advanced": true
277
+ },
278
+ "codexPlugins.plugins": {
279
+ "label": "Migrated Plugin Entries",
280
+ "help": "Explicit migration-authored plugin entries. The wildcard key * is not supported.",
281
+ "advanced": true
282
+ },
222
283
  "appServer": {
223
284
  "label": "App Server",
224
285
  "help": "Runtime controls for connecting to Codex app-server.",
@@ -270,6 +331,11 @@
270
331
  "help": "Maximum time to wait for Codex app-server control-plane requests.",
271
332
  "advanced": true
272
333
  },
334
+ "appServer.turnCompletionIdleTimeoutMs": {
335
+ "label": "Turn Completion Idle Timeout",
336
+ "help": "Maximum quiet time after a turn-scoped Codex app-server request before OpenClaw interrupts the turn while waiting for turn/completed.",
337
+ "advanced": true
338
+ },
273
339
  "appServer.approvalPolicy": {
274
340
  "label": "Approval Policy",
275
341
  "help": "Codex native approval policy sent to thread start, resume, and turns.",
@@ -287,7 +353,7 @@
287
353
  },
288
354
  "appServer.serviceTier": {
289
355
  "label": "Service Tier",
290
- "help": "Optional Codex app-server service tier. Use fast, flex, or null.",
356
+ "help": "Optional Codex app-server service tier. Use priority, flex, or null. Legacy fast is accepted as priority.",
291
357
  "advanced": true
292
358
  },
293
359
  "appServer.defaultWorkspaceDir": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/codex",
3
- "version": "2026.5.7",
3
+ "version": "2026.5.10-beta.1",
4
4
  "description": "OpenClaw Codex harness and model provider plugin",
5
5
  "repository": {
6
6
  "type": "git",
@@ -8,11 +8,10 @@
8
8
  },
9
9
  "type": "module",
10
10
  "dependencies": {
11
- "@mariozechner/pi-coding-agent": "0.73.0",
12
- "@openai/codex": "0.128.0",
11
+ "@mariozechner/pi-coding-agent": "0.73.1",
12
+ "@openai/codex": "0.130.0",
13
13
  "ajv": "^8.20.0",
14
- "ws": "^8.20.0",
15
- "zod": "^4.4.3"
14
+ "ws": "^8.20.0"
16
15
  },
17
16
  "devDependencies": {
18
17
  "@openclaw/plugin-sdk": "workspace:*"
@@ -27,10 +26,10 @@
27
26
  "minHostVersion": ">=2026.5.1-beta.1"
28
27
  },
29
28
  "compat": {
30
- "pluginApi": ">=2026.5.7"
29
+ "pluginApi": ">=2026.5.10-beta.1"
31
30
  },
32
31
  "build": {
33
- "openclawVersion": "2026.5.7"
32
+ "openclawVersion": "2026.5.10-beta.1"
34
33
  },
35
34
  "release": {
36
35
  "publishToClawHub": true,
@@ -45,7 +44,7 @@
45
44
  "openclaw.plugin.json"
46
45
  ],
47
46
  "peerDependencies": {
48
- "openclaw": ">=2026.5.7"
47
+ "openclaw": ">=2026.5.10-beta.1"
49
48
  },
50
49
  "peerDependenciesMeta": {
51
50
  "openclaw": {