@openclaw/codex 2026.5.16-beta.4 → 2026.5.16-beta.5

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.
@@ -4,11 +4,11 @@ import { t as isJsonObject } from "./protocol-C9UWI98H.js";
4
4
  import { i as describeControlFailure, r as CODEX_CONTROL_METHODS, t as requestCodexAppServerJson } from "./request-XPjLayGw.js";
5
5
  import { a as formatComputerUseStatus, c as formatThreads, i as formatCodexStatus, l as readString$1, n as formatAccount, o as formatList, p as summarizeCodexAccountUsage, r as formatCodexDisplayText, s as formatModels, t as buildHelp } from "./command-formatters-BRW7_Nu7.js";
6
6
  import { i as readCodexAppServerBinding, o as writeCodexAppServerBinding, t as clearCodexAppServerBinding } from "./session-binding-DqApZIgD.js";
7
- import { _ as steerCodexConversationTurn, b as readCodexConversationBindingData, d as parseCodexFastModeArg, f as parseCodexPermissionsModeArg, g as setCodexConversationPermissions, h as setCodexConversationModel, l as startCodexConversationThread, m as setCodexConversationFastMode, p as readCodexConversationActiveTurn, r as formatCodexCliSessions, u as formatPermissionsMode, v as stopCodexConversationTurn, x as resolveCodexDefaultWorkspaceDir, y as createCodexCliNodeConversationBindingData } from "./node-cli-sessions-BKhlcAB9.js";
7
+ import { _ as steerCodexConversationTurn, b as readCodexConversationBindingData, d as parseCodexFastModeArg, f as parseCodexPermissionsModeArg, g as setCodexConversationPermissions, h as setCodexConversationModel, l as startCodexConversationThread, m as setCodexConversationFastMode, p as readCodexConversationActiveTurn, r as formatCodexCliSessions, u as formatPermissionsMode, v as stopCodexConversationTurn, x as resolveCodexDefaultWorkspaceDir, y as createCodexCliNodeConversationBindingData } from "./node-cli-sessions-C9rlYMPw.js";
8
8
  import { n as installCodexComputerUse, r as readCodexComputerUseStatus } from "./computer-use-UJ3dxrXF.js";
9
9
  import { n as rememberCodexRateLimits } from "./rate-limit-cache-dvhq-4pi.js";
10
10
  import crypto from "node:crypto";
11
- import { ensureAuthProfileStore, findNormalizedProviderValue, resolveAuthProfileEligibility, resolveAuthProfileOrder, resolveDefaultAgentDir, resolveProfileUnusableUntilForDisplay } from "openclaw/plugin-sdk/agent-runtime";
11
+ import { ensureAuthProfileStore, findNormalizedProviderValue, resolveAgentDir, resolveAuthProfileEligibility, resolveAuthProfileOrder, resolveDefaultAgentDir, resolveProfileUnusableUntilForDisplay, resolveSessionAgentIds } from "openclaw/plugin-sdk/agent-runtime";
12
12
  //#region extensions/codex/src/command-account.ts
13
13
  const OPENAI_PROVIDER_ID = "openai";
14
14
  const OPENAI_CODEX_PROVIDER_ID = "openai-codex";
@@ -308,6 +308,7 @@ async function codexControlRequest(pluginConfig, method, requestParams, options
308
308
  startOptions: runtime.start,
309
309
  config: options.config,
310
310
  authProfileId: options.authProfileId,
311
+ agentDir: options.agentDir,
311
312
  isolated: options.isolated
312
313
  });
313
314
  }
@@ -466,20 +467,28 @@ async function bindConversation(deps, ctx, pluginConfig, args) {
466
467
  const parsed = parseBindArgs(args);
467
468
  if (parsed.help) return { text: "Usage: /codex bind [thread-id] [--cwd <path>] [--model <model>] [--provider <provider>]" };
468
469
  if (!ctx.sessionFile) return { text: "Cannot bind Codex because this command did not include an OpenClaw session file." };
470
+ const scope = resolveCodexConversationControlScope(ctx);
469
471
  const workspaceDir = parsed.cwd ?? deps.resolveCodexDefaultWorkspaceDir(pluginConfig);
470
- const authProfileId = (await deps.readCodexAppServerBinding(ctx.sessionFile))?.authProfileId;
472
+ const authProfileId = (await deps.readCodexAppServerBinding(ctx.sessionFile, {
473
+ agentDir: scope.agentDir,
474
+ config: ctx.config
475
+ }))?.authProfileId;
471
476
  const startParams = {
472
477
  pluginConfig,
473
478
  config: ctx.config,
474
479
  sessionFile: ctx.sessionFile,
475
480
  workspaceDir,
481
+ agentDir: scope.agentDir,
476
482
  threadId: parsed.threadId,
477
483
  model: parsed.model,
478
484
  modelProvider: parsed.provider
479
485
  };
480
486
  if (authProfileId) startParams.authProfileId = authProfileId;
481
487
  const data = await deps.startCodexConversationThread(startParams);
482
- const threadId = (await deps.readCodexAppServerBinding(ctx.sessionFile))?.threadId ?? parsed.threadId ?? "new thread";
488
+ const threadId = (await deps.readCodexAppServerBinding(ctx.sessionFile, {
489
+ agentDir: scope.agentDir,
490
+ config: ctx.config
491
+ }))?.threadId ?? parsed.threadId ?? "new thread";
483
492
  const summary = `Codex app-server thread ${formatCodexDisplayText(threadId)} in ${formatCodexDisplayText(workspaceDir)}`;
484
493
  let request;
485
494
  try {
@@ -516,7 +525,10 @@ async function describeConversationBinding(deps, ctx) {
516
525
  `- Workspace: ${formatCodexDisplayText(data.cwd ?? "unknown")}`,
517
526
  "- Active run: not tracked"
518
527
  ].join("\n");
519
- const threadBinding = await deps.readCodexAppServerBinding(data.sessionFile);
528
+ const threadBinding = await deps.readCodexAppServerBinding(data.sessionFile, {
529
+ agentDir: data.agentDir,
530
+ config: ctx.config
531
+ });
520
532
  const active = deps.readCodexConversationActiveTurn(data.sessionFile);
521
533
  return [
522
534
  "Codex conversation binding:",
@@ -590,67 +602,98 @@ async function bindCodexCliNodeSession(deps, ctx, parsed) {
590
602
  return formatCodexDisplayText(request.message);
591
603
  }
592
604
  async function stopConversationTurn(deps, ctx, pluginConfig) {
593
- const sessionFile = await resolveControlSessionFile(ctx);
594
- if (!sessionFile) return "Cannot stop Codex because this command did not include an OpenClaw session file.";
605
+ const target = await resolveControlTarget(ctx);
606
+ if (!target) return "Cannot stop Codex because this command did not include an OpenClaw session file.";
595
607
  return (await deps.stopCodexConversationTurn({
596
- sessionFile,
597
- pluginConfig
608
+ sessionFile: target.sessionFile,
609
+ pluginConfig,
610
+ agentDir: target.agentDir,
611
+ config: ctx.config
598
612
  })).message;
599
613
  }
600
614
  async function steerConversationTurn(deps, ctx, pluginConfig, message) {
601
- const sessionFile = await resolveControlSessionFile(ctx);
602
- if (!sessionFile) return "Cannot steer Codex because this command did not include an OpenClaw session file.";
615
+ const target = await resolveControlTarget(ctx);
616
+ if (!target) return "Cannot steer Codex because this command did not include an OpenClaw session file.";
603
617
  return (await deps.steerCodexConversationTurn({
604
- sessionFile,
618
+ sessionFile: target.sessionFile,
605
619
  pluginConfig,
606
- message
620
+ message,
621
+ agentDir: target.agentDir,
622
+ config: ctx.config
607
623
  })).message;
608
624
  }
609
625
  async function setConversationModel(deps, ctx, pluginConfig, args) {
610
626
  if (args.length > 1) return "Usage: /codex model <model>";
611
- const sessionFile = await resolveControlSessionFile(ctx);
612
- if (!sessionFile) return "Cannot set Codex model because this command did not include an OpenClaw session file.";
627
+ const target = await resolveControlTarget(ctx);
628
+ if (!target) return "Cannot set Codex model because this command did not include an OpenClaw session file.";
613
629
  const [model = ""] = args;
614
630
  const normalized = model.trim();
615
631
  if (!normalized) {
616
- const binding = await deps.readCodexAppServerBinding(sessionFile);
632
+ const binding = await deps.readCodexAppServerBinding(target.sessionFile, {
633
+ agentDir: target.agentDir,
634
+ config: ctx.config
635
+ });
617
636
  return binding?.model ? `Codex model: ${formatCodexDisplayText(binding.model)}` : "Usage: /codex model <model>";
618
637
  }
619
638
  return await deps.setCodexConversationModel({
620
- sessionFile,
639
+ sessionFile: target.sessionFile,
621
640
  pluginConfig,
622
- model: normalized
641
+ model: normalized,
642
+ agentDir: target.agentDir,
643
+ config: ctx.config
623
644
  });
624
645
  }
625
646
  async function setConversationFastMode(deps, ctx, pluginConfig, args) {
626
647
  if (args.length > 1) return "Usage: /codex fast [on|off|status]";
627
- const sessionFile = await resolveControlSessionFile(ctx);
628
- if (!sessionFile) return "Cannot set Codex fast mode because this command did not include an OpenClaw session file.";
648
+ const target = await resolveControlTarget(ctx);
649
+ if (!target) return "Cannot set Codex fast mode because this command did not include an OpenClaw session file.";
629
650
  const value = args[0];
630
651
  const parsed = parseCodexFastModeArg(value);
631
652
  if (value && parsed == null && value.trim().toLowerCase() !== "status") return "Usage: /codex fast [on|off|status]";
632
653
  return await deps.setCodexConversationFastMode({
633
- sessionFile,
654
+ sessionFile: target.sessionFile,
634
655
  pluginConfig,
635
- enabled: parsed
656
+ enabled: parsed,
657
+ agentDir: target.agentDir,
658
+ config: ctx.config
636
659
  });
637
660
  }
638
661
  async function setConversationPermissions(deps, ctx, pluginConfig, args) {
639
662
  if (args.length > 1) return "Usage: /codex permissions [default|yolo|status]";
640
- const sessionFile = await resolveControlSessionFile(ctx);
641
- if (!sessionFile) return "Cannot set Codex permissions because this command did not include an OpenClaw session file.";
663
+ const target = await resolveControlTarget(ctx);
664
+ if (!target) return "Cannot set Codex permissions because this command did not include an OpenClaw session file.";
642
665
  const value = args[0];
643
666
  const parsed = parseCodexPermissionsModeArg(value);
644
667
  if (value && !parsed && value.trim().toLowerCase() !== "status") return "Usage: /codex permissions [default|yolo|status]";
645
668
  return await deps.setCodexConversationPermissions({
646
- sessionFile,
669
+ sessionFile: target.sessionFile,
647
670
  pluginConfig,
648
- mode: parsed
671
+ mode: parsed,
672
+ agentDir: target.agentDir,
673
+ config: ctx.config
649
674
  });
650
675
  }
651
- async function resolveControlSessionFile(ctx) {
676
+ async function resolveControlTarget(ctx) {
652
677
  const data = readCodexConversationBindingData(await ctx.getCurrentConversationBinding());
653
- return data?.kind === "codex-app-server-session" ? data.sessionFile : ctx.sessionFile;
678
+ const scope = resolveCodexConversationControlScope(ctx);
679
+ if (data?.kind === "codex-app-server-session") return {
680
+ sessionFile: data.sessionFile,
681
+ agentDir: data.agentDir ?? scope.agentDir
682
+ };
683
+ return ctx.sessionFile ? {
684
+ sessionFile: ctx.sessionFile,
685
+ agentDir: scope.agentDir
686
+ } : void 0;
687
+ }
688
+ async function resolveControlSessionFile(ctx) {
689
+ return (await resolveControlTarget(ctx))?.sessionFile;
690
+ }
691
+ function resolveCodexConversationControlScope(ctx) {
692
+ const { sessionAgentId } = resolveSessionAgentIds({
693
+ sessionKey: ctx.sessionKey,
694
+ config: ctx.config
695
+ });
696
+ return { agentDir: resolveAgentDir(ctx.config, sessionAgentId) };
654
697
  }
655
698
  async function handleCodexDiagnosticsFeedback(deps, ctx, pluginConfig, args, commandPrefix) {
656
699
  if (ctx.senderIsOwner !== true) return { text: "Only an owner can send Codex diagnostics." };
@@ -1120,15 +1163,26 @@ function normalizeCodexDiagnosticsScopeField(value) {
1120
1163
  }
1121
1164
  async function startThreadAction(deps, ctx, pluginConfig, method, label, args) {
1122
1165
  if (args.length > 0) return `Usage: /codex ${label === "compaction" ? "compact" : label}`;
1123
- const sessionFile = await resolveControlSessionFile(ctx);
1124
- if (!sessionFile) return `Cannot start Codex ${label} because this command did not include an OpenClaw session file.`;
1125
- const binding = await deps.readCodexAppServerBinding(sessionFile);
1166
+ const target = await resolveControlTarget(ctx);
1167
+ if (!target) return `Cannot start Codex ${label} because this command did not include an OpenClaw session file.`;
1168
+ const binding = await deps.readCodexAppServerBinding(target.sessionFile, {
1169
+ agentDir: target.agentDir,
1170
+ config: ctx.config
1171
+ });
1126
1172
  if (!binding?.threadId) return `No Codex thread is attached to this OpenClaw session yet.`;
1127
1173
  if (method === CODEX_CONTROL_METHODS.review) await deps.codexControlRequest(pluginConfig, method, {
1128
1174
  threadId: binding.threadId,
1129
1175
  target: { type: "uncommittedChanges" }
1176
+ }, {
1177
+ agentDir: target.agentDir,
1178
+ authProfileId: binding.authProfileId,
1179
+ config: ctx.config
1180
+ });
1181
+ else await deps.codexControlRequest(pluginConfig, method, { threadId: binding.threadId }, {
1182
+ agentDir: target.agentDir,
1183
+ authProfileId: binding.authProfileId,
1184
+ config: ctx.config
1130
1185
  });
1131
- else await deps.codexControlRequest(pluginConfig, method, { threadId: binding.threadId });
1132
1186
  return `Started Codex ${label} for thread ${formatCodexDisplayText(binding.threadId)}.`;
1133
1187
  }
1134
1188
  function splitArgs(value) {
package/dist/harness.js CHANGED
@@ -18,15 +18,18 @@ function createCodexAppServerAgentHarness(options) {
18
18
  };
19
19
  },
20
20
  runAttempt: async (params) => {
21
- const { runCodexAppServerAttempt } = await import("./run-attempt-DMKAwtUV.js");
21
+ const { runCodexAppServerAttempt } = await import("./run-attempt-Bssnu2uw.js");
22
22
  return runCodexAppServerAttempt(params, {
23
23
  pluginConfig: options?.pluginConfig,
24
24
  nativeHookRelay: { enabled: true }
25
25
  });
26
26
  },
27
27
  runSideQuestion: async (params) => {
28
- const { runCodexAppServerSideQuestion } = await import("./side-question-BYYJZq23.js");
29
- return runCodexAppServerSideQuestion(params, { pluginConfig: options?.pluginConfig });
28
+ const { runCodexAppServerSideQuestion } = await import("./side-question-DgVgwmjR.js");
29
+ return runCodexAppServerSideQuestion(params, {
30
+ pluginConfig: options?.pluginConfig,
31
+ nativeHookRelay: { enabled: true }
32
+ });
30
33
  },
31
34
  compact: async (params) => {
32
35
  const { maybeCompactCodexAppServerSession } = await import("./compact-UKyG6Pw2.js");
package/dist/index.js CHANGED
@@ -5,7 +5,7 @@ import { buildCodexProvider } from "./provider.js";
5
5
  import { i as describeControlFailure, n as buildCodexPluginAppCacheKey, t as requestCodexAppServerJson } from "./request-XPjLayGw.js";
6
6
  import { r as formatCodexDisplayText } from "./command-formatters-BRW7_Nu7.js";
7
7
  import { c as resolveCodexAppServerAuthAccountCacheKey, d as resolveCodexAppServerEnvApiKeyCacheKey, i as getSharedCodexAppServerClient, n as clearSharedCodexAppServerClientIfCurrentAndWait, u as resolveCodexAppServerAuthProfileIdForAgent } from "./shared-client-DlvmoLBJ.js";
8
- import { a as resolveCodexCliSessionForBindingOnNode, c as handleCodexConversationInboundClaim, i as listCodexCliSessionsOnNode, n as createCodexCliSessionNodeInvokePolicies, o as resumeCodexCliSessionOnNode, s as handleCodexConversationBindingResolved, t as createCodexCliSessionNodeHostCommands } from "./node-cli-sessions-BKhlcAB9.js";
8
+ import { a as resolveCodexCliSessionForBindingOnNode, c as handleCodexConversationInboundClaim, i as listCodexCliSessionsOnNode, n as createCodexCliSessionNodeInvokePolicies, o as resumeCodexCliSessionOnNode, s as handleCodexConversationBindingResolved, t as createCodexCliSessionNodeHostCommands } from "./node-cli-sessions-C9rlYMPw.js";
9
9
  import { a as defaultCodexAppInventoryCache, n as pluginReadParams, t as ensureCodexPluginActivation } from "./plugin-activation-B49xb7pI.js";
10
10
  import { resolveLivePluginConfigObject } from "openclaw/plugin-sdk/plugin-config-runtime";
11
11
  import { definePluginEntry } from "openclaw/plugin-sdk/plugin-entry";
@@ -38,7 +38,7 @@ async function handleCodexCommand(ctx, options = {}) {
38
38
  }
39
39
  }
40
40
  async function loadDefaultCodexSubcommandHandler() {
41
- const { handleCodexSubcommand } = await import("./command-handlers-jZV_1Ks9.js");
41
+ const { handleCodexSubcommand } = await import("./command-handlers-DcoFMn4e.js");
42
42
  return handleCodexSubcommand;
43
43
  }
44
44
  //#endregion
@@ -16,11 +16,13 @@ import { resolvePreferredOpenClawTmpDir } from "openclaw/plugin-sdk/temp-path";
16
16
  //#region extensions/codex/src/conversation-binding-data.ts
17
17
  const BINDING_DATA_VERSION = 1;
18
18
  function createCodexConversationBindingData(params) {
19
+ const agentDir = params.agentDir?.trim();
19
20
  return {
20
21
  kind: "codex-app-server-session",
21
22
  version: BINDING_DATA_VERSION,
22
23
  sessionFile: params.sessionFile,
23
- workspaceDir: params.workspaceDir
24
+ workspaceDir: params.workspaceDir,
25
+ ...agentDir ? { agentDir } : {}
24
26
  };
25
27
  }
26
28
  function createCodexCliNodeConversationBindingData(params) {
@@ -55,7 +57,8 @@ function readCodexConversationBindingDataRecord(data) {
55
57
  kind: "codex-app-server-session",
56
58
  version: BINDING_DATA_VERSION,
57
59
  sessionFile: data.sessionFile,
58
- workspaceDir: typeof data.workspaceDir === "string" && data.workspaceDir.trim() ? data.workspaceDir : process.cwd()
60
+ workspaceDir: typeof data.workspaceDir === "string" && data.workspaceDir.trim() ? data.workspaceDir : process.cwd(),
61
+ agentDir: typeof data.agentDir === "string" && data.agentDir.trim() ? data.agentDir : void 0
59
62
  };
60
63
  }
61
64
  function resolveCodexDefaultWorkspaceDir(pluginConfig) {
@@ -93,11 +96,13 @@ async function stopCodexConversationTurn(params) {
93
96
  message: "No active Codex run to stop."
94
97
  };
95
98
  const runtime = resolveCodexAppServerRuntimeOptions({ pluginConfig: params.pluginConfig });
96
- const binding = await readCodexAppServerBinding(params.sessionFile);
99
+ const lookup = buildBindingLookup(params);
100
+ const binding = await readCodexAppServerBinding(params.sessionFile, lookup);
97
101
  await (await getSharedCodexAppServerClient({
98
102
  startOptions: runtime.start,
99
103
  timeoutMs: runtime.requestTimeoutMs,
100
- authProfileId: binding?.authProfileId
104
+ authProfileId: binding?.authProfileId,
105
+ ...lookup
101
106
  })).request("turn/interrupt", {
102
107
  threadId: active.threadId,
103
108
  turnId: active.turnId
@@ -119,11 +124,13 @@ async function steerCodexConversationTurn(params) {
119
124
  message: "No active Codex run to steer."
120
125
  };
121
126
  const runtime = resolveCodexAppServerRuntimeOptions({ pluginConfig: params.pluginConfig });
122
- const binding = await readCodexAppServerBinding(params.sessionFile);
127
+ const lookup = buildBindingLookup(params);
128
+ const binding = await readCodexAppServerBinding(params.sessionFile, lookup);
123
129
  await (await getSharedCodexAppServerClient({
124
130
  startOptions: runtime.start,
125
131
  timeoutMs: runtime.requestTimeoutMs,
126
- authProfileId: binding?.authProfileId
132
+ authProfileId: binding?.authProfileId,
133
+ ...lookup
127
134
  })).request("turn/steer", {
128
135
  threadId: active.threadId,
129
136
  expectedTurnId: active.turnId,
@@ -141,12 +148,14 @@ async function steerCodexConversationTurn(params) {
141
148
  async function setCodexConversationModel(params) {
142
149
  const model = params.model.trim();
143
150
  if (!model) return "Usage: /codex model <model>";
144
- const binding = await requireThreadBinding(params.sessionFile);
151
+ const lookup = buildBindingLookup(params);
152
+ const binding = await requireThreadBinding(params.sessionFile, lookup);
145
153
  const runtime = resolveCodexAppServerRuntimeOptions({ pluginConfig: params.pluginConfig });
146
154
  const response = await resumeThreadWithOverrides({
147
155
  pluginConfig: params.pluginConfig,
148
156
  threadId: binding.threadId,
149
157
  authProfileId: binding.authProfileId,
158
+ ...lookup,
150
159
  model
151
160
  });
152
161
  await writeCodexAppServerBinding(params.sessionFile, {
@@ -157,28 +166,30 @@ async function setCodexConversationModel(params) {
157
166
  approvalPolicy: binding.approvalPolicy,
158
167
  sandbox: binding.sandbox,
159
168
  serviceTier: binding.serviceTier ?? runtime.serviceTier
160
- });
169
+ }, lookup);
161
170
  return `Codex model set to ${formatCodexDisplayText(response.model ?? model)}.`;
162
171
  }
163
172
  async function setCodexConversationFastMode(params) {
164
- const binding = await requireThreadBinding(params.sessionFile);
173
+ const lookup = buildBindingLookup(params);
174
+ const binding = await requireThreadBinding(params.sessionFile, lookup);
165
175
  if (params.enabled == null) return `Codex fast mode: ${isCodexFastServiceTier(binding.serviceTier) ? "on" : "off"}.`;
166
176
  const serviceTier = params.enabled ? "priority" : "flex";
167
177
  await writeCodexAppServerBinding(params.sessionFile, {
168
178
  ...binding,
169
179
  serviceTier
170
- });
180
+ }, lookup);
171
181
  return `Codex fast mode ${params.enabled ? "enabled" : "disabled"}.`;
172
182
  }
173
183
  async function setCodexConversationPermissions(params) {
174
- const binding = await requireThreadBinding(params.sessionFile);
184
+ const lookup = buildBindingLookup(params);
185
+ const binding = await requireThreadBinding(params.sessionFile, lookup);
175
186
  if (!params.mode) return `Codex permissions: ${formatPermissionsMode(binding)}.`;
176
187
  const policy = permissionsForMode(params.mode);
177
188
  await writeCodexAppServerBinding(params.sessionFile, {
178
189
  ...binding,
179
190
  approvalPolicy: policy.approvalPolicy,
180
191
  sandbox: policy.sandbox
181
- });
192
+ }, lookup);
182
193
  return `Codex permissions set to ${params.mode === "yolo" ? "full access" : "default"}.`;
183
194
  }
184
195
  function parseCodexFastModeArg(arg) {
@@ -196,8 +207,8 @@ function parseCodexPermissionsModeArg(arg) {
196
207
  function formatPermissionsMode(binding) {
197
208
  return binding.approvalPolicy === "never" && binding.sandbox === "danger-full-access" ? "full access" : "default";
198
209
  }
199
- async function requireThreadBinding(sessionFile) {
200
- const binding = await readCodexAppServerBinding(sessionFile);
210
+ async function requireThreadBinding(sessionFile, lookup = {}) {
211
+ const binding = await readCodexAppServerBinding(sessionFile, lookup);
201
212
  if (!binding?.threadId) throw new Error("No Codex thread is attached to this OpenClaw session yet.");
202
213
  return binding;
203
214
  }
@@ -206,7 +217,8 @@ async function resumeThreadWithOverrides(params) {
206
217
  return await (await getSharedCodexAppServerClient({
207
218
  startOptions: runtime.start,
208
219
  timeoutMs: runtime.requestTimeoutMs,
209
- authProfileId: params.authProfileId
220
+ authProfileId: params.authProfileId,
221
+ ...buildBindingLookup(params)
210
222
  })).request(CODEX_CONTROL_METHODS.resumeThread, {
211
223
  threadId: params.threadId,
212
224
  ...params.model ? { model: params.model } : {},
@@ -217,6 +229,13 @@ async function resumeThreadWithOverrides(params) {
217
229
  persistExtendedHistory: true
218
230
  }, { timeoutMs: runtime.requestTimeoutMs });
219
231
  }
232
+ function buildBindingLookup(params) {
233
+ const agentDir = params.agentDir?.trim();
234
+ return {
235
+ ...agentDir ? { agentDir } : {},
236
+ ...params.config ? { config: params.config } : {}
237
+ };
238
+ }
220
239
  function permissionsForMode(mode) {
221
240
  return mode === "yolo" ? {
222
241
  approvalPolicy: "never",
@@ -438,16 +457,22 @@ function getGlobalState() {
438
457
  }
439
458
  async function startCodexConversationThread(params) {
440
459
  const workspaceDir = params.workspaceDir?.trim() || resolveCodexDefaultWorkspaceDir(params.pluginConfig);
441
- const existingBinding = await readCodexAppServerBinding(params.sessionFile, { config: params.config });
460
+ const agentDir = params.agentDir?.trim();
461
+ const agentLookup = buildAgentLookup({
462
+ agentDir,
463
+ config: params.config
464
+ });
465
+ const existingBinding = await readCodexAppServerBinding(params.sessionFile, { ...agentLookup });
442
466
  const authProfileId = resolveCodexAppServerAuthProfileIdForAgent({
443
467
  authProfileId: params.authProfileId ?? existingBinding?.authProfileId,
444
- config: params.config
468
+ ...agentLookup
445
469
  });
446
470
  if (params.threadId?.trim()) await attachExistingThread({
447
471
  pluginConfig: params.pluginConfig,
448
472
  sessionFile: params.sessionFile,
449
473
  threadId: params.threadId.trim(),
450
474
  workspaceDir,
475
+ ...agentDir ? { agentDir } : {},
451
476
  model: params.model,
452
477
  modelProvider: params.modelProvider,
453
478
  authProfileId,
@@ -460,6 +485,7 @@ async function startCodexConversationThread(params) {
460
485
  pluginConfig: params.pluginConfig,
461
486
  sessionFile: params.sessionFile,
462
487
  workspaceDir,
488
+ ...agentDir ? { agentDir } : {},
463
489
  model: params.model,
464
490
  modelProvider: params.modelProvider,
465
491
  authProfileId,
@@ -470,7 +496,8 @@ async function startCodexConversationThread(params) {
470
496
  });
471
497
  return createCodexConversationBindingData({
472
498
  sessionFile: params.sessionFile,
473
- workspaceDir
499
+ workspaceDir,
500
+ ...agentDir ? { agentDir } : {}
474
501
  });
475
502
  }
476
503
  async function handleCodexConversationInboundClaim(event, ctx, options = {}) {
@@ -531,15 +558,20 @@ async function handleCodexConversationBindingResolved(event) {
531
558
  }
532
559
  async function attachExistingThread(params) {
533
560
  const runtime = resolveCodexAppServerRuntimeOptions({ pluginConfig: params.pluginConfig });
561
+ const agentLookup = buildAgentLookup({
562
+ agentDir: params.agentDir,
563
+ config: params.config
564
+ });
534
565
  const modelProvider = resolveThreadRequestModelProvider({
535
566
  authProfileId: params.authProfileId,
536
567
  modelProvider: params.modelProvider,
537
- config: params.config
568
+ ...agentLookup
538
569
  });
539
570
  const response = await (await getSharedCodexAppServerClient({
540
571
  startOptions: runtime.start,
541
572
  timeoutMs: runtime.requestTimeoutMs,
542
- authProfileId: params.authProfileId
573
+ authProfileId: params.authProfileId,
574
+ ...agentLookup
543
575
  })).request(CODEX_CONTROL_METHODS.resumeThread, {
544
576
  threadId: params.threadId,
545
577
  ...params.model ? { model: params.model } : {},
@@ -558,26 +590,31 @@ async function attachExistingThread(params) {
558
590
  authProfileId: params.authProfileId,
559
591
  model: response.model ?? params.model,
560
592
  modelProvider: normalizeCodexAppServerBindingModelProvider({
561
- config: params.config,
562
593
  authProfileId: params.authProfileId,
563
- modelProvider: response.modelProvider ?? params.modelProvider
594
+ modelProvider: response.modelProvider ?? params.modelProvider,
595
+ ...agentLookup
564
596
  }),
565
597
  approvalPolicy: params.approvalPolicy ?? runtimeApprovalPolicy,
566
598
  sandbox: params.sandbox ?? runtime.sandbox,
567
599
  serviceTier: params.serviceTier ?? runtime.serviceTier
568
- }, { config: params.config });
600
+ }, { ...agentLookup });
569
601
  }
570
602
  async function createThread(params) {
571
603
  const runtime = resolveCodexAppServerRuntimeOptions({ pluginConfig: params.pluginConfig });
604
+ const agentLookup = buildAgentLookup({
605
+ agentDir: params.agentDir,
606
+ config: params.config
607
+ });
572
608
  const modelProvider = resolveThreadRequestModelProvider({
573
609
  authProfileId: params.authProfileId,
574
610
  modelProvider: params.modelProvider,
575
- config: params.config
611
+ ...agentLookup
576
612
  });
577
613
  const response = await (await getSharedCodexAppServerClient({
578
614
  startOptions: runtime.start,
579
615
  timeoutMs: runtime.requestTimeoutMs,
580
- authProfileId: params.authProfileId
616
+ authProfileId: params.authProfileId,
617
+ ...agentLookup
581
618
  })).request("thread/start", {
582
619
  cwd: params.workspaceDir,
583
620
  ...params.model ? { model: params.model } : {},
@@ -597,24 +634,26 @@ async function createThread(params) {
597
634
  authProfileId: params.authProfileId,
598
635
  model: response.model ?? params.model,
599
636
  modelProvider: normalizeCodexAppServerBindingModelProvider({
600
- config: params.config,
601
637
  authProfileId: params.authProfileId,
602
- modelProvider: response.modelProvider ?? params.modelProvider
638
+ modelProvider: response.modelProvider ?? params.modelProvider,
639
+ ...agentLookup
603
640
  }),
604
641
  approvalPolicy: params.approvalPolicy ?? runtimeApprovalPolicy,
605
642
  sandbox: params.sandbox ?? runtime.sandbox,
606
643
  serviceTier: params.serviceTier ?? runtime.serviceTier
607
- }, { config: params.config });
644
+ }, { ...agentLookup });
608
645
  }
609
646
  async function runBoundTurn(params) {
610
647
  const runtime = resolveCodexAppServerRuntimeOptions({ pluginConfig: params.pluginConfig });
611
- const binding = await readCodexAppServerBinding(params.data.sessionFile);
648
+ const agentLookup = buildAgentLookup({ agentDir: params.data.agentDir });
649
+ const binding = await readCodexAppServerBinding(params.data.sessionFile, agentLookup);
612
650
  const threadId = binding?.threadId;
613
651
  if (!threadId) throw new Error("bound Codex conversation has no thread binding");
614
652
  const client = await getSharedCodexAppServerClient({
615
653
  startOptions: runtime.start,
616
654
  timeoutMs: runtime.requestTimeoutMs,
617
- authProfileId: binding.authProfileId
655
+ authProfileId: binding.authProfileId,
656
+ ...agentLookup
618
657
  });
619
658
  const collector = createCodexConversationTurnCollector(threadId);
620
659
  const notificationCleanup = client.addNotificationHandler((notification) => collector.handleNotification(notification));
@@ -670,11 +709,13 @@ async function runBoundTurnWithMissingThreadRecovery(params) {
670
709
  return await runBoundTurn(params);
671
710
  } catch (error) {
672
711
  if (!isCodexThreadNotFoundError(error)) throw error;
673
- const binding = await readCodexAppServerBinding(params.data.sessionFile);
712
+ const agentLookup = buildAgentLookup({ agentDir: params.data.agentDir });
713
+ const binding = await readCodexAppServerBinding(params.data.sessionFile, agentLookup);
674
714
  await startCodexConversationThread({
675
715
  pluginConfig: params.pluginConfig,
676
716
  sessionFile: params.data.sessionFile,
677
717
  workspaceDir: binding?.cwd || params.data.workspaceDir,
718
+ ...agentLookup,
678
719
  model: binding?.model,
679
720
  modelProvider: binding?.modelProvider,
680
721
  authProfileId: binding?.authProfileId,
@@ -704,6 +745,13 @@ function resolveThreadRequestModelProvider(params) {
704
745
  if (isCodexAppServerNativeAuthProfile(params) && (modelProvider.toLowerCase() === "openai" || modelProvider.toLowerCase() === "openai-codex")) return;
705
746
  return modelProvider.toLowerCase() === "openai-codex" ? "openai" : modelProvider;
706
747
  }
748
+ function buildAgentLookup(params) {
749
+ const agentDir = params.agentDir?.trim();
750
+ return {
751
+ ...agentDir ? { agentDir } : {},
752
+ ...params.config ? { config: params.config } : {}
753
+ };
754
+ }
707
755
  //#endregion
708
756
  //#region extensions/codex/src/node-cli-sessions.ts
709
757
  const CODEX_CLI_SESSIONS_LIST_COMMAND = "codex.cli.sessions.list";