@openclaw/codex 2026.6.10-beta.2 → 2026.6.11-beta.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/harness.js CHANGED
@@ -32,14 +32,14 @@ function createCodexAppServerAgentHarness(options) {
32
32
  };
33
33
  },
34
34
  runAttempt: async (params) => {
35
- const { runCodexAppServerAttempt } = await import("./run-attempt-DafK4VP9.js");
35
+ const { runCodexAppServerAttempt } = await import("./run-attempt-CXxtFC9d.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-Di5YsbLx.js");
42
+ const { runCodexAppServerSideQuestion } = await import("./side-question-C-DhgJOd.js");
43
43
  return runCodexAppServerSideQuestion(params, {
44
44
  pluginConfig: options?.resolvePluginConfig?.() ?? options?.pluginConfig,
45
45
  nativeHookRelay: { enabled: true }
@@ -1211,6 +1211,7 @@ async function buildDynamicTools(input) {
1211
1211
  ...sessionKeys,
1212
1212
  sessionId: params.sessionId,
1213
1213
  runId: params.runId,
1214
+ approvalReviewerDeviceId: params.approvalReviewerDeviceId,
1214
1215
  agentDir,
1215
1216
  cwd: input.effectiveCwd ?? input.effectiveWorkspace,
1216
1217
  workspaceDir: input.effectiveWorkspace,
@@ -10,7 +10,7 @@ import { n as buildCodexPluginAppCacheKey, r as CODEX_CONTROL_METHODS, t as buil
10
10
  import { a as formatCodexDisplayText, n as resolveCodexAppServerForOpenClawToolPolicy, t as resolveCodexAppServerForModelProvider } from "./app-server-policy-BPTiVNsW.js";
11
11
  import { d as resolveCodexAppServerAuthAccountCacheKey, f as resolveCodexAppServerAuthProfileId, h as resolveCodexAppServerHomeDir, m as resolveCodexAppServerFallbackApiKeyCacheKey, n as clearSharedCodexAppServerClientIfCurrentAndUnclaimed, o as releaseLeasedSharedCodexAppServerClient, p as resolveCodexAppServerAuthProfileIdForAgent, s as retireSharedCodexAppServerClientIfCurrent, t as clearSharedCodexAppServerClientIfCurrent, u as refreshCodexAppServerAuthTokens } from "./shared-client-Dtx5i7Ez.js";
12
12
  import { t as defaultLeasedCodexAppServerClientFactory } from "./client-factory-Bm6HsGob.js";
13
- import { A as CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS, C as resolveCodexMessageToolProvider, D as shouldWarnCodexDynamicToolBuildStageSummary, E as shouldRequireCodexSandboxExecServerEnvironment, F as resolveCodexTurnTerminalIdleTimeoutMs, I as withCodexStartupTimeout, M as resolveCodexStartupTimeoutMs, N as resolveCodexTurnAssistantCompletionIdleTimeoutMs, P as resolveCodexTurnCompletionIdleTimeoutMs, S as resolveCodexExternalSandboxPolicyForOpenClawSandbox, T as shouldEnableCodexAppServerNativeToolSurface, _ as createCodexDynamicToolBuildStageTracker, a as buildCodexNativeHookRelayConfig, b as resolveCodexAppServerExecutionCwd, c as resolveCodexNativeHookRelayEvents, d as handleCodexAppServerElicitationRequest, f as createCodexDynamicToolBridge, g as buildDynamicTools, h as emitDynamicToolTerminalDiagnostic, i as CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS, j as resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs, k as handleCodexAppServerApprovalRequest, l as resolveCodexNativeHookRelayTtlMs, m as emitDynamicToolStartedDiagnostic, o as buildCodexNativeHookRelayDisabledConfig, p as emitDynamicToolErrorDiagnostic, s as createCodexNativeHookRelay, t as resolveCodexProviderWebSearchSupport, u as scheduleCodexNativeHookRelayUnregister, v as disableCodexPluginThreadConfig, w as resolveCodexSandboxEnvironmentSelection, x as resolveCodexAppServerHookChannelId, y as formatCodexDynamicToolBuildStageSummary } from "./provider-capabilities-D-8g7Lb2.js";
13
+ import { A as CODEX_POST_REASONING_REPLY_IDLE_TIMEOUT_MS, C as resolveCodexMessageToolProvider, D as shouldWarnCodexDynamicToolBuildStageSummary, E as shouldRequireCodexSandboxExecServerEnvironment, F as resolveCodexTurnTerminalIdleTimeoutMs, I as withCodexStartupTimeout, M as resolveCodexStartupTimeoutMs, N as resolveCodexTurnAssistantCompletionIdleTimeoutMs, P as resolveCodexTurnCompletionIdleTimeoutMs, S as resolveCodexExternalSandboxPolicyForOpenClawSandbox, T as shouldEnableCodexAppServerNativeToolSurface, _ as createCodexDynamicToolBuildStageTracker, a as buildCodexNativeHookRelayConfig, b as resolveCodexAppServerExecutionCwd, c as resolveCodexNativeHookRelayEvents, d as handleCodexAppServerElicitationRequest, f as createCodexDynamicToolBridge, g as buildDynamicTools, h as emitDynamicToolTerminalDiagnostic, i as CODEX_NATIVE_HOOK_RELAY_TTL_GRACE_MS, j as resolveCodexPostToolRawAssistantCompletionIdleTimeoutMs, k as handleCodexAppServerApprovalRequest, l as resolveCodexNativeHookRelayTtlMs, m as emitDynamicToolStartedDiagnostic, o as buildCodexNativeHookRelayDisabledConfig, p as emitDynamicToolErrorDiagnostic, s as createCodexNativeHookRelay, t as resolveCodexProviderWebSearchSupport, u as scheduleCodexNativeHookRelayUnregister, v as disableCodexPluginThreadConfig, w as resolveCodexSandboxEnvironmentSelection, x as resolveCodexAppServerHookChannelId, y as formatCodexDynamicToolBuildStageSummary } from "./provider-capabilities-D7hnTO76.js";
14
14
  import { t as ensureCodexComputerUse } from "./computer-use-ClrJwoFp.js";
15
15
  import { n as rememberCodexRateLimits, t as readRecentCodexRateLimits } from "./rate-limit-cache-C7qmZ0Jh.js";
16
16
  import fs from "node:fs/promises";
@@ -21,7 +21,7 @@ import { createHash, randomUUID } from "node:crypto";
21
21
  import fsSync from "node:fs";
22
22
  import { markAuthProfileBlockedUntil, resolveAgentDir, resolveAgentWorkspaceDir } from "openclaw/plugin-sdk/agent-runtime";
23
23
  import { loadExecApprovals } from "openclaw/plugin-sdk/exec-approvals-runtime";
24
- import { CODEX_APP_SERVER_CONTEXT_ENGINE_HOST, FAST_MODE_AUTO_PROGRESS_KIND, TOOL_PROGRESS_OUTPUT_MAX_CHARS, acquireSessionWriteLock, appendSessionTranscriptMessage, assembleHarnessContextEngine, assertContextEngineHostSupport, awaitAgentEndSideEffects, bootstrapHarnessContextEngine, buildBootstrapContextForFiles, buildHarnessContextEngineRuntimeContext, buildHarnessContextEngineRuntimeContextFromUsage, classifyAgentHarnessTerminalOutcome, clearActiveEmbeddedRun, embeddedAgentLog, emitAgentEvent, emitSessionTranscriptUpdate, finalizeHarnessContextEngineTurn, formatErrorMessage, formatFastModeAutoProgressText, formatToolAggregate, formatToolProgressOutput, getAgentHarnessHookRunner, getBeforeToolCallPolicyDiagnosticState, inferToolMetaFromArgs, isActiveHarnessContextEngine, loadCodexBundleMcpThreadConfig, normalizeUsage, resolveAgentHarnessBeforePromptBuildResult, resolveBootstrapFilesForRun, resolveContextEngineOwnerPluginId, resolveFastModeForElapsed, resolveSandboxContext, resolveSessionAgentIds as resolveSessionAgentIds$1, resolveSessionWriteLockOptions, resolveUserPath, runAgentCleanupStep, runAgentEndSideEffects, runAgentHarnessAfterCompactionHook, runAgentHarnessAfterToolCallHook, runAgentHarnessBeforeCompactionHook, runAgentHarnessBeforeMessageWriteHook, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
24
+ import { CODEX_APP_SERVER_CONTEXT_ENGINE_HOST, FAST_MODE_AUTO_PROGRESS_KIND, TOOL_PROGRESS_OUTPUT_MAX_CHARS, assembleHarnessContextEngine, assertContextEngineHostSupport, awaitAgentEndSideEffects, bootstrapHarnessContextEngine, buildAgentHarnessUserInputAnswers, buildBootstrapContextForFiles, buildHarnessContextEngineRuntimeContext, buildHarnessContextEngineRuntimeContextFromUsage, classifyAgentHarnessTerminalOutcome, clearActiveEmbeddedRun, deliverAgentHarnessUserInputPrompt, embeddedAgentLog, emitAgentEvent, emptyAgentHarnessUserInputAnswers, finalizeHarnessContextEngineTurn, formatErrorMessage, formatFastModeAutoProgressText, formatToolAggregate, formatToolProgressOutput, getAgentHarnessHookRunner, getBeforeToolCallPolicyDiagnosticState, inferToolMetaFromArgs, isActiveHarnessContextEngine, loadCodexBundleMcpThreadConfig, normalizeUsage, resolveAgentHarnessBeforePromptBuildResult, resolveBootstrapFilesForRun, resolveContextEngineOwnerPluginId, resolveFastModeForElapsed, resolveSandboxContext, resolveSessionAgentIds as resolveSessionAgentIds$1, resolveUserPath, runAgentCleanupStep, runAgentEndSideEffects, runAgentHarnessAfterCompactionHook, runAgentHarnessAfterToolCallHook, runAgentHarnessBeforeCompactionHook, runAgentHarnessBeforeMessageWriteHook, runAgentHarnessLlmInputHook, runAgentHarnessLlmOutputHook, runHarnessContextEngineMaintenance, setActiveEmbeddedRun, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
25
25
  import { buildMemorySystemPromptAddition } from "openclaw/plugin-sdk/core";
26
26
  import { spawn } from "node:child_process";
27
27
  import { once } from "node:events";
@@ -31,6 +31,7 @@ import { createDiagnosticTraceContextFromActiveScope, emitTrustedDiagnosticEvent
31
31
  import { appendRegularFile, pathExists } from "openclaw/plugin-sdk/security-runtime";
32
32
  import { MESSAGE_TOOL_DELIVERY_HINTS } from "openclaw/plugin-sdk/message-tool-delivery-hints";
33
33
  import { buildSessionContext, migrateSessionEntries, parseSessionEntries } from "openclaw/plugin-sdk/agent-sessions";
34
+ import { publishSessionTranscriptUpdateByIdentity, resolveSessionTranscriptTarget, withSessionTranscriptWriteLock } from "openclaw/plugin-sdk/session-transcript-runtime";
34
35
  import { isIP } from "node:net";
35
36
  import { SsrFBlockedError, isBlockedHostnameOrIp } from "openclaw/plugin-sdk/ssrf-runtime";
36
37
  import { generatedImageAssetFromBase64 } from "openclaw/plugin-sdk/image-generation";
@@ -146,22 +147,30 @@ async function retireCodexAppServerClientAfterTimedOutTurn(client, params) {
146
147
  * Reads OpenClaw session history for Codex transcript mirroring and sanitizes
147
148
  * image payloads before replaying messages into the app-server projector.
148
149
  */
149
- function isMissingFileError(error) {
150
- return Boolean(error && typeof error === "object" && "code" in error && error.code === "ENOENT");
151
- }
152
150
  /** Returns sanitized session-context messages for a Codex mirrored session file. */
153
- async function readCodexMirroredSessionHistoryMessages(sessionFile) {
151
+ async function readCodexMirroredSessionHistoryMessages(target) {
154
152
  try {
155
- const entries = parseSessionEntries(await fs.readFile(sessionFile, "utf-8"));
153
+ await resolveSessionTranscriptTarget(resolveCodexHistoryTranscriptTarget(target));
154
+ const entries = parseSessionEntries(await fs.readFile(target.sessionFile, "utf-8"));
155
+ if (entries.length === 0) return [];
156
156
  const firstEntry = entries[0];
157
157
  if (firstEntry?.type !== "session" || typeof firstEntry.id !== "string") return;
158
158
  migrateSessionEntries(entries);
159
- return sanitizeCodexHistoryImagePayloads(buildSessionContext(entries.filter((entry) => entry.type !== "session")).messages, "codex mirrored history");
160
- } catch (error) {
161
- if (isMissingFileError(error)) return [];
159
+ return sanitizeCodexHistoryImagePayloads(buildSessionContext(entries.filter((entry) => {
160
+ return entry !== null && typeof entry === "object" && !Array.isArray(entry) && entry.type !== "session";
161
+ })).messages, "codex mirrored history");
162
+ } catch {
162
163
  return;
163
164
  }
164
165
  }
166
+ function resolveCodexHistoryTranscriptTarget(target) {
167
+ return {
168
+ ...target.agentId ? { agentId: target.agentId } : {},
169
+ sessionFile: target.sessionFile,
170
+ sessionId: target.sessionId,
171
+ sessionKey: target.sessionKey ?? ""
172
+ };
173
+ }
165
174
  //#endregion
166
175
  //#region extensions/codex/src/app-server/attempt-context.ts
167
176
  /**
@@ -189,9 +198,9 @@ const CODEX_BOOTSTRAP_CONTEXT_ORDER = new Map([
189
198
  ["heartbeat.md", 70]
190
199
  ]);
191
200
  /** Reads mirrored Codex session history for harness hooks. */
192
- async function readMirroredSessionHistoryMessages(sessionFile) {
193
- const messages = await readCodexMirroredSessionHistoryMessages(sessionFile);
194
- if (!messages) embeddedAgentLog.warn("failed to read mirrored session history for codex harness hooks", { sessionFile });
201
+ async function readMirroredSessionHistoryMessages(params) {
202
+ const messages = await readCodexMirroredSessionHistoryMessages(params);
203
+ if (!messages) embeddedAgentLog.warn("failed to read mirrored session history for codex harness hooks", { sessionFile: params.sessionFile });
195
204
  return messages;
196
205
  }
197
206
  /** Reads a valid thread-bootstrap projection request from context-engine output. */
@@ -3644,14 +3653,14 @@ function buildMirrorDedupeIdentity(message) {
3644
3653
  async function mirrorCodexAppServerTranscript(params) {
3645
3654
  const messages = params.messages.filter((message) => message.role === "user" || message.role === "assistant" || message.role === "toolResult");
3646
3655
  if (messages.length === 0) return { userMessagesPresent: [] };
3647
- const lock = await acquireSessionWriteLock({
3648
- sessionFile: params.sessionFile,
3649
- ...resolveSessionWriteLockOptions(params.config)
3650
- });
3651
- const appendedUpdates = [];
3652
- const userMessagesPresent = [];
3653
- try {
3654
- const mirrorState = await readTranscriptMirrorState(params.sessionFile);
3656
+ const transcriptTarget = resolveCodexMirrorTranscriptTarget(params);
3657
+ const { appendedUpdates, userMessagesPresent } = await withSessionTranscriptWriteLock({
3658
+ ...transcriptTarget,
3659
+ config: params.config
3660
+ }, async (transcript) => {
3661
+ const nextAppendedUpdates = [];
3662
+ const nextUserMessagesPresent = [];
3663
+ const mirrorState = readTranscriptMirrorState(await transcript.readEvents());
3655
3664
  let nextMessageSeq = mirrorState.messageCount;
3656
3665
  for (const message of messages) {
3657
3666
  const dedupeIdentity = buildMirrorDedupeIdentity(message);
@@ -3662,7 +3671,7 @@ async function mirrorCodexAppServerTranscript(params) {
3662
3671
  };
3663
3672
  if (idempotencyKey && mirrorState.idempotencyKeys.has(idempotencyKey)) {
3664
3673
  const persistedUserMessage = mirrorState.userMessagesByIdempotencyKey.get(idempotencyKey);
3665
- if (persistedUserMessage) userMessagesPresent.push(persistedUserMessage);
3674
+ if (persistedUserMessage) nextUserMessagesPresent.push(persistedUserMessage);
3666
3675
  continue;
3667
3676
  }
3668
3677
  const nextMessage = runAgentHarnessBeforeMessageWriteHook({
@@ -3675,65 +3684,61 @@ async function mirrorCodexAppServerTranscript(params) {
3675
3684
  ...nextMessage,
3676
3685
  idempotencyKey
3677
3686
  } : nextMessage;
3678
- const { messageId, message: appendedMessage } = await appendSessionTranscriptMessage({
3679
- transcriptPath: params.sessionFile,
3687
+ const appended = await transcript.appendMessage({
3680
3688
  message: messageToAppend,
3681
3689
  idempotencyLookup: idempotencyKey ? "caller-checked" : "scan",
3682
- sessionId: params.sessionId,
3683
- cwd: params.cwd,
3684
- config: params.config
3690
+ cwd: params.cwd
3685
3691
  });
3692
+ if (!appended) continue;
3693
+ const { messageId, message: appendedMessage } = appended;
3686
3694
  if (appendedMessage.role === "user") {
3687
- userMessagesPresent.push(appendedMessage);
3695
+ nextUserMessagesPresent.push(appendedMessage);
3688
3696
  if (idempotencyKey) mirrorState.userMessagesByIdempotencyKey.set(idempotencyKey, appendedMessage);
3689
3697
  }
3690
3698
  nextMessageSeq += 1;
3691
- appendedUpdates.push({
3699
+ nextAppendedUpdates.push({
3692
3700
  messageId,
3693
3701
  message: appendedMessage,
3694
3702
  messageSeq: nextMessageSeq
3695
3703
  });
3696
3704
  if (idempotencyKey) mirrorState.idempotencyKeys.add(idempotencyKey);
3697
3705
  }
3698
- } finally {
3699
- await lock.release();
3700
- }
3701
- for (const update of appendedUpdates) emitSessionTranscriptUpdate({
3702
- sessionFile: params.sessionFile,
3703
- ...params.sessionKey ? { sessionKey: params.sessionKey } : {},
3704
- ...params.agentId ? { agentId: params.agentId } : {},
3705
- message: update.message,
3706
- messageId: update.messageId,
3707
- messageSeq: update.messageSeq
3706
+ return {
3707
+ appendedUpdates: nextAppendedUpdates,
3708
+ userMessagesPresent: nextUserMessagesPresent
3709
+ };
3710
+ });
3711
+ for (const update of appendedUpdates) await publishSessionTranscriptUpdateByIdentity({
3712
+ ...transcriptTarget,
3713
+ update: {
3714
+ ...params.sessionKey ? { sessionKey: params.sessionKey } : {},
3715
+ ...params.agentId ? { agentId: params.agentId } : {},
3716
+ message: update.message,
3717
+ messageId: update.messageId,
3718
+ messageSeq: update.messageSeq
3719
+ }
3708
3720
  });
3709
3721
  return { userMessagesPresent };
3710
3722
  }
3711
- async function readTranscriptMirrorState(sessionFile) {
3723
+ function resolveCodexMirrorTranscriptTarget(params) {
3724
+ return {
3725
+ ...params.agentId ? { agentId: params.agentId } : {},
3726
+ sessionFile: params.sessionFile,
3727
+ sessionId: params.sessionId,
3728
+ sessionKey: params.sessionKey ?? ""
3729
+ };
3730
+ }
3731
+ function readTranscriptMirrorState(events) {
3712
3732
  const idempotencyKeys = /* @__PURE__ */ new Set();
3713
3733
  const userMessagesByIdempotencyKey = /* @__PURE__ */ new Map();
3714
3734
  let messageCount = 0;
3715
- let raw;
3716
- try {
3717
- raw = await fs.readFile(sessionFile, "utf8");
3718
- } catch (error) {
3719
- if (error.code !== "ENOENT") throw error;
3720
- return {
3721
- idempotencyKeys,
3722
- messageCount,
3723
- userMessagesByIdempotencyKey
3724
- };
3725
- }
3726
- for (const line of raw.split(/\r?\n/)) {
3727
- if (!line.trim()) continue;
3728
- try {
3729
- const parsed = JSON.parse(line);
3730
- if (parsed.type === "message") messageCount += 1;
3731
- if (typeof parsed.message?.idempotencyKey === "string") {
3732
- idempotencyKeys.add(parsed.message.idempotencyKey);
3733
- if (parsed.message.role === "user") userMessagesByIdempotencyKey.set(parsed.message.idempotencyKey, parsed.message);
3734
- }
3735
- } catch {
3736
- continue;
3735
+ for (const event of events) {
3736
+ if (!event || typeof event !== "object" || Array.isArray(event)) continue;
3737
+ const parsed = event;
3738
+ if (parsed.type === "message") messageCount += 1;
3739
+ if (typeof parsed.message?.idempotencyKey === "string") {
3740
+ idempotencyKeys.add(parsed.message.idempotencyKey);
3741
+ if (parsed.message.role === "user") userMessagesByIdempotencyKey.set(parsed.message.idempotencyKey, parsed.message);
3737
3742
  }
3738
3743
  }
3739
3744
  return {
@@ -3830,7 +3835,6 @@ var CodexAppServerEventProjector = class {
3830
3835
  this.toolTrajectoryNamesById = /* @__PURE__ */ new Map();
3831
3836
  this.toolTrajectoryItemsById = /* @__PURE__ */ new Map();
3832
3837
  this.transcriptToolProgressCallIds = /* @__PURE__ */ new Set();
3833
- this.nativeGeneratedMediaUrls = /* @__PURE__ */ new Set();
3834
3838
  this.nativeGeneratedMediaItemIds = /* @__PURE__ */ new Set();
3835
3839
  this.nativeGeneratedMediaUrlsByItemId = /* @__PURE__ */ new Map();
3836
3840
  this.diagnosticToolStartedAtByItem = /* @__PURE__ */ new Map();
@@ -3838,6 +3842,7 @@ var CodexAppServerEventProjector = class {
3838
3842
  this.assistantStarted = false;
3839
3843
  this.reasoningStarted = false;
3840
3844
  this.reasoningEnded = false;
3845
+ this.streamedPartialAssistantItemReplaceable = false;
3841
3846
  this.promptErrorSource = null;
3842
3847
  this.synthesizedMissingToolResultError = null;
3843
3848
  this.aborted = false;
@@ -4053,10 +4058,28 @@ var CodexAppServerEventProjector = class {
4053
4058
  itemId,
4054
4059
  text
4055
4060
  });
4056
- else if (this.shouldStreamAssistantPartial(itemId)) await this.params.onPartialReply?.({
4057
- text,
4058
- delta
4059
- });
4061
+ else {
4062
+ const knownFinalAnswer = this.shouldStreamAssistantPartial(itemId);
4063
+ const replace = this.streamedPartialAssistantItemId !== void 0 && this.streamedPartialAssistantItemId !== itemId;
4064
+ if (replace && (!knownFinalAnswer || this.streamedPartialAssistantItemReplaceable)) this.streamedPartialAssistantItemReplaceable = true;
4065
+ else if (this.streamedPartialAssistantItemId === void 0) this.streamedPartialAssistantItemReplaceable = !knownFinalAnswer;
4066
+ this.streamedPartialAssistantItemId = itemId;
4067
+ const replaceable = this.streamedPartialAssistantItemReplaceable;
4068
+ const replacement = replace && replaceable;
4069
+ const streamPayload = {
4070
+ text,
4071
+ delta: replacement ? "" : delta,
4072
+ ...replacement ? { replace: true } : {}
4073
+ };
4074
+ this.emitAgentEvent({
4075
+ stream: "assistant",
4076
+ data: {
4077
+ ...streamPayload,
4078
+ ...replaceable ? { replaceable: true } : {}
4079
+ }
4080
+ });
4081
+ if (knownFinalAnswer && !replaceable) await this.params.onPartialReply?.(streamPayload);
4082
+ }
4060
4083
  }
4061
4084
  async handleReasoningDelta(method, params) {
4062
4085
  const itemId = readString$5(params, "itemId") ?? readString$5(params, "id") ?? "reasoning";
@@ -4456,7 +4479,8 @@ var CodexAppServerEventProjector = class {
4456
4479
  const saved = await saveMediaBuffer(asset.buffer, asset.mimeType, GENERATED_IMAGE_MEDIA_SUBDIR, maxBytes, asset.fileName);
4457
4480
  this.recordNativeGeneratedMediaUrl({
4458
4481
  itemId,
4459
- mediaUrl: saved.path
4482
+ mediaUrl: saved.path,
4483
+ replaceExisting: true
4460
4484
  });
4461
4485
  } catch (error) {
4462
4486
  embeddedAgentLog.warn("codex app-server raw image generation result save failed", {
@@ -4466,17 +4490,16 @@ var CodexAppServerEventProjector = class {
4466
4490
  }
4467
4491
  }
4468
4492
  recordNativeGeneratedMediaUrl(params) {
4469
- if (this.nativeGeneratedMediaUrlsByItemId.has(params.itemId)) {
4493
+ if (this.nativeGeneratedMediaUrlsByItemId.has(params.itemId) && params.replaceExisting !== true) {
4470
4494
  this.nativeGeneratedMediaItemIds.add(params.itemId);
4471
4495
  return;
4472
4496
  }
4473
4497
  this.nativeGeneratedMediaUrlsByItemId.set(params.itemId, params.mediaUrl);
4474
- this.nativeGeneratedMediaUrls.add(params.mediaUrl);
4475
4498
  this.nativeGeneratedMediaItemIds.add(params.itemId);
4476
4499
  }
4477
4500
  buildToolMediaUrls(toolTelemetry) {
4478
4501
  const mediaUrls = new Set(toolTelemetry.toolMediaUrls?.map((url) => url.trim()).filter(Boolean) ?? []);
4479
- if ((toolTelemetry.messagingToolSentMediaUrls?.length ?? 0) === 0) for (const mediaUrl of this.nativeGeneratedMediaUrls) mediaUrls.add(mediaUrl);
4502
+ if ((toolTelemetry.messagingToolSentMediaUrls?.length ?? 0) === 0) for (const mediaUrl of this.nativeGeneratedMediaUrlsByItemId.values()) mediaUrls.add(mediaUrl);
4480
4503
  return mediaUrls.size > 0 ? [...mediaUrls] : toolTelemetry.toolMediaUrls;
4481
4504
  }
4482
4505
  async maybeEndReasoning() {
@@ -5007,7 +5030,12 @@ var CodexAppServerEventProjector = class {
5007
5030
  }
5008
5031
  }
5009
5032
  async readMirroredSessionMessages() {
5010
- return await readCodexMirroredSessionHistoryMessages(this.params.sessionFile) ?? [];
5033
+ return await readCodexMirroredSessionHistoryMessages({
5034
+ agentId: this.params.agentId,
5035
+ sessionFile: this.params.sessionFile,
5036
+ sessionId: this.params.sessionId,
5037
+ sessionKey: this.params.sessionKey
5038
+ }) ?? [];
5011
5039
  }
5012
5040
  createAssistantMessage(text) {
5013
5041
  const attribution = resolveCodexLocalRuntimeAttribution(this.params);
@@ -6018,6 +6046,7 @@ const DEFAULT_COMPLETION_DELIVERY_RETRY_DELAYS_MS = [
6018
6046
  ];
6019
6047
  const DEFAULT_TASK_ROW_RECONCILE_INTERVAL_MS = 1e4;
6020
6048
  const RECENT_TERMINAL_TASK_RECONCILE_GRACE_MS = 6e4;
6049
+ const CODEX_ROLLOUT_FILENAME_RE = /^rollout-\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}-(.+)\.jsonl$/u;
6021
6050
  const defaultRuntime = {
6022
6051
  createAgentHarnessTaskRuntime,
6023
6052
  deliverAgentHarnessTaskCompletion
@@ -6689,8 +6718,9 @@ async function findTranscriptCompletion(params) {
6689
6718
  async function findTranscriptPaths(params) {
6690
6719
  const sessionsDir = path.join(params.codexHome, "sessions");
6691
6720
  const found = /* @__PURE__ */ new Map();
6721
+ const remaining = new Set(params.childThreadIds);
6692
6722
  const stack = [sessionsDir];
6693
- while (stack.length > 0 && found.size < params.childThreadIds.size) {
6723
+ while (stack.length > 0 && remaining.size > 0) {
6694
6724
  const dir = stack.pop();
6695
6725
  let entries;
6696
6726
  try {
@@ -6705,7 +6735,17 @@ async function findTranscriptPaths(params) {
6705
6735
  continue;
6706
6736
  }
6707
6737
  if (!entry.isFile() || !entry.name.endsWith(".jsonl")) continue;
6708
- for (const childThreadId of params.childThreadIds) if (!found.has(childThreadId) && entry.name.includes(childThreadId)) found.set(childThreadId, entryPath);
6738
+ const rolloutMatch = entry.name.match(CODEX_ROLLOUT_FILENAME_RE);
6739
+ if (rolloutMatch) {
6740
+ const childThreadId = rolloutMatch[1];
6741
+ if (remaining.delete(childThreadId)) found.set(childThreadId, entryPath);
6742
+ continue;
6743
+ }
6744
+ for (const childThreadId of remaining) if (entry.name.includes(childThreadId)) {
6745
+ found.set(childThreadId, entryPath);
6746
+ remaining.delete(childThreadId);
6747
+ break;
6748
+ }
6709
6749
  }
6710
6750
  }
6711
6751
  return found;
@@ -6726,7 +6766,8 @@ async function findTranscriptPath(params) {
6726
6766
  stack.push(entryPath);
6727
6767
  continue;
6728
6768
  }
6729
- if (entry.isFile() && entry.name.endsWith(".jsonl") && entry.name.includes(params.childThreadId)) return entryPath;
6769
+ const rolloutMatch = entry.name.match(CODEX_ROLLOUT_FILENAME_RE);
6770
+ if (entry.isFile() && entry.name.endsWith(".jsonl") && (rolloutMatch ? rolloutMatch[1] === params.childThreadId : entry.name.includes(params.childThreadId))) return entryPath;
6730
6771
  }
6731
6772
  }
6732
6773
  }
@@ -7520,69 +7561,16 @@ function readOption(value) {
7520
7561
  } : void 0;
7521
7562
  }
7522
7563
  async function deliverUserInputPrompt(params, questions) {
7523
- const text = formatUserInputPrompt(questions);
7524
- if (params.onBlockReply) {
7525
- await params.onBlockReply({ text });
7526
- return;
7527
- }
7528
- await params.onPartialReply?.({ text });
7529
- }
7530
- function formatUserInputPrompt(questions) {
7531
- const lines = ["Codex needs input:"];
7532
- questions.forEach((question, index) => {
7533
- if (questions.length > 1) lines.push("", `${index + 1}. ${formatCodexDisplayText(question.header)}`, formatCodexDisplayText(question.question));
7534
- else lines.push("", formatCodexDisplayText(question.header), formatCodexDisplayText(question.question));
7535
- if (question.isSecret) lines.push("This channel may show your reply to other participants.");
7536
- question.options?.forEach((option, optionIndex) => {
7537
- lines.push(`${optionIndex + 1}. ${formatCodexDisplayText(option.label)}${option.description ? ` - ${formatCodexDisplayText(option.description)}` : ""}`);
7538
- });
7539
- if (question.isOther) lines.push("Other: reply with your own answer.");
7564
+ await deliverAgentHarnessUserInputPrompt(params, questions, {
7565
+ formatText: formatCodexDisplayText,
7566
+ intro: "Codex needs input:"
7540
7567
  });
7541
- return lines.join("\n");
7542
7568
  }
7543
7569
  function buildUserInputResponse(questions, inputText) {
7544
- const answers = {};
7545
- if (questions.length === 1) {
7546
- const question = questions[0];
7547
- if (question) {
7548
- const answer = normalizeAnswer(inputText, question);
7549
- answers[question.id] = { answers: answer ? [answer] : [] };
7550
- }
7551
- return { answers };
7552
- }
7553
- const keyed = parseKeyedAnswers(inputText);
7554
- const fallbackLines = inputText.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
7555
- questions.forEach((question, index) => {
7556
- const answer = keyed.get(question.id.toLowerCase()) ?? keyed.get(question.header.toLowerCase()) ?? keyed.get(question.question.toLowerCase()) ?? keyed.get(String(index + 1)) ?? fallbackLines[index] ?? "";
7557
- const normalized = answer ? normalizeAnswer(answer, question) : void 0;
7558
- answers[question.id] = { answers: normalized ? [normalized] : [] };
7559
- });
7560
- return { answers };
7561
- }
7562
- function normalizeAnswer(answer, question) {
7563
- const trimmed = answer.trim();
7564
- const options = question.options ?? [];
7565
- const optionIndex = /^\d+$/.test(trimmed) ? Number(trimmed) - 1 : -1;
7566
- const indexed = optionIndex >= 0 ? options[optionIndex] : void 0;
7567
- if (indexed) return indexed.label;
7568
- const exact = options.find((option) => option.label.toLowerCase() === trimmed.toLowerCase());
7569
- if (exact) return exact.label;
7570
- if (options.length > 0 && !question.isOther) return;
7571
- return trimmed || void 0;
7572
- }
7573
- function parseKeyedAnswers(inputText) {
7574
- const answers = /* @__PURE__ */ new Map();
7575
- for (const line of inputText.split(/\r?\n/)) {
7576
- const match = line.match(/^\s*([^:=-]+?)\s*[:=-]\s*(.+?)\s*$/);
7577
- if (!match) continue;
7578
- const key = match[1]?.trim().toLowerCase();
7579
- const value = match[2]?.trim();
7580
- if (key && value) answers.set(key, value);
7581
- }
7582
- return answers;
7570
+ return buildAgentHarnessUserInputAnswers(questions, inputText);
7583
7571
  }
7584
7572
  function emptyUserInputResponse() {
7585
- return { answers: {} };
7573
+ return emptyAgentHarnessUserInputAnswers();
7586
7574
  }
7587
7575
  function readString(record, key) {
7588
7576
  const value = record[key];
@@ -8041,7 +8029,13 @@ async function runCodexAppServerAttempt(params, options = {}) {
8041
8029
  }
8042
8030
  });
8043
8031
  const hadSessionFile = await pathExists(activeSessionFile);
8044
- let historyMessages = await readMirroredSessionHistoryMessages(activeSessionFile) ?? [];
8032
+ const activeTranscriptTarget = {
8033
+ agentId: sessionAgentId,
8034
+ sessionFile: activeSessionFile,
8035
+ sessionId: activeSessionId,
8036
+ sessionKey: contextSessionKey
8037
+ };
8038
+ let historyMessages = !activeContextEngine && initialStartupBindingHadInactiveThreadBootstrap ? [] : await readMirroredSessionHistoryMessages(activeTranscriptTarget) ?? [];
8045
8039
  const hookContextWindowFields = {
8046
8040
  ...params.contextWindowInfo?.tokens ? { contextTokenBudget: params.contextWindowInfo.tokens } : params.contextTokenBudget ? { contextTokenBudget: params.contextTokenBudget } : {},
8047
8041
  ...params.contextWindowInfo?.source ? { contextWindowSource: params.contextWindowInfo.source } : {},
@@ -8087,7 +8081,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
8087
8081
  config: params.config,
8088
8082
  warn: (message) => embeddedAgentLog.warn(message)
8089
8083
  });
8090
- historyMessages = await readMirroredSessionHistoryMessages(activeSessionFile) ?? historyMessages;
8084
+ historyMessages = await readMirroredSessionHistoryMessages(activeTranscriptTarget) ?? historyMessages;
8091
8085
  }
8092
8086
  const workspaceBootstrapContext = await buildCodexWorkspaceBootstrapContext({
8093
8087
  params,
@@ -9437,6 +9431,8 @@ async function runCodexAppServerAttempt(params, options = {}) {
9437
9431
  }
9438
9432
  turnIdRef.current = turn.turn.id;
9439
9433
  const activeTurnId = turn.turn.id;
9434
+ let assistantStreamEventEmitted = false;
9435
+ let assistantStreamNeedsTerminalSnapshot = false;
9440
9436
  emitExecutionPhaseOnce("turn_accepted", { phase: "turn_accepted" });
9441
9437
  userInputBridgeRef.current = createCodexUserInputBridge({
9442
9438
  paramsForRun: params,
@@ -9450,7 +9446,16 @@ async function runCodexAppServerAttempt(params, options = {}) {
9450
9446
  prompt: codexTurnPromptText,
9451
9447
  imagesCount: params.images?.length ?? 0
9452
9448
  });
9453
- projectorRef.current = new CodexAppServerEventProjector(dynamicToolParams, thread.threadId, activeTurnId, {
9449
+ projectorRef.current = new CodexAppServerEventProjector({
9450
+ ...dynamicToolParams,
9451
+ onAgentEvent: (event) => {
9452
+ if (event.stream === "assistant" && typeof event.data.delta === "string") {
9453
+ assistantStreamEventEmitted = true;
9454
+ assistantStreamNeedsTerminalSnapshot ||= event.data.replaceable === true;
9455
+ }
9456
+ return dynamicToolParams.onAgentEvent?.(event);
9457
+ }
9458
+ }, thread.threadId, activeTurnId, {
9454
9459
  nativePostToolUseRelayEnabled: nativeHookRelay?.allowedEvents.includes("post_tool_use") === true && nativeHookRelay.shouldRelayEvent("post_tool_use"),
9455
9460
  trajectoryRecorder,
9456
9461
  onNativeToolResultRecorded: maybeAnnounceFastModeAutoOff
@@ -9629,7 +9634,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
9629
9634
  turnId: activeTurnId
9630
9635
  });
9631
9636
  const terminalAssistantText = collectTerminalAssistantText(result);
9632
- if (terminalAssistantText && !finalAborted && !finalPromptError) emitCodexAppServerEvent(params, {
9637
+ if (terminalAssistantText && (!assistantStreamEventEmitted || assistantStreamNeedsTerminalSnapshot) && !finalAborted && !finalPromptError) emitCodexAppServerEvent(params, {
9633
9638
  stream: "assistant",
9634
9639
  data: { text: terminalAssistantText }
9635
9640
  });
@@ -9643,7 +9648,7 @@ async function runCodexAppServerAttempt(params, options = {}) {
9643
9648
  });
9644
9649
  if (activeContextEngine) {
9645
9650
  const activeContextEnginePluginIdLocal = resolveContextEngineOwnerPluginId(activeContextEngine);
9646
- const finalMessages = await readMirroredSessionHistoryMessages(activeSessionFile) ?? historyMessages.concat(result.messagesSnapshot);
9651
+ const finalMessages = await readMirroredSessionHistoryMessages(activeTranscriptTarget) ?? historyMessages.concat(result.messagesSnapshot);
9647
9652
  await finalizeHarnessContextEngineTurn({
9648
9653
  contextEngine: activeContextEngine,
9649
9654
  promptError: Boolean(finalPromptError),
@@ -8,7 +8,7 @@ import { i as isCodexAppServerNativeAuthProfile, o as readCodexAppServerBinding
8
8
  import { t as resolveCodexAppServerForModelProvider } from "./app-server-policy-BPTiVNsW.js";
9
9
  import { a as getLeasedSharedCodexAppServerClient, o as releaseLeasedSharedCodexAppServerClient, u as refreshCodexAppServerAuthTokens } from "./shared-client-Dtx5i7Ez.js";
10
10
  import { n as resolveCodexNativeExecutionBlock } from "./sandbox-guard-3tnjhjFb.js";
11
- import { C as resolveCodexMessageToolProvider, O as filterToolsForVisionInputs, T as shouldEnableCodexAppServerNativeToolSurface, a as buildCodexNativeHookRelayConfig, d as handleCodexAppServerElicitationRequest, f as createCodexDynamicToolBridge, h as emitDynamicToolTerminalDiagnostic, k as handleCodexAppServerApprovalRequest, m as emitDynamicToolStartedDiagnostic, n as resolveCodexProviderWebSearchSupportForClient, o as buildCodexNativeHookRelayDisabledConfig, p as emitDynamicToolErrorDiagnostic, r as CODEX_NATIVE_HOOK_RELAY_EVENTS } from "./provider-capabilities-D-8g7Lb2.js";
11
+ import { C as resolveCodexMessageToolProvider, O as filterToolsForVisionInputs, T as shouldEnableCodexAppServerNativeToolSurface, a as buildCodexNativeHookRelayConfig, d as handleCodexAppServerElicitationRequest, f as createCodexDynamicToolBridge, h as emitDynamicToolTerminalDiagnostic, k as handleCodexAppServerApprovalRequest, m as emitDynamicToolStartedDiagnostic, n as resolveCodexProviderWebSearchSupportForClient, o as buildCodexNativeHookRelayDisabledConfig, p as emitDynamicToolErrorDiagnostic, r as CODEX_NATIVE_HOOK_RELAY_EVENTS } from "./provider-capabilities-D7hnTO76.js";
12
12
  import { n as rememberCodexRateLimits, t as readRecentCodexRateLimits } from "./rate-limit-cache-C7qmZ0Jh.js";
13
13
  import { loadExecApprovals } from "openclaw/plugin-sdk/exec-approvals-runtime";
14
14
  import { buildAgentHookContextChannelFields, embeddedAgentLog, formatErrorMessage, registerNativeHookRelay, resolveAgentDir, resolveAttemptSpawnWorkspaceDir, resolveModelAuthMode, resolveSandboxContext, resolveSessionAgentIds, supportsModelTools } from "openclaw/plugin-sdk/agent-harness-runtime";
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@openclaw/codex",
3
- "version": "2026.6.10-beta.2",
3
+ "version": "2026.6.11-beta.2",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@openclaw/codex",
9
- "version": "2026.6.10-beta.2",
9
+ "version": "2026.6.11-beta.2",
10
10
  "dependencies": {
11
11
  "@openai/codex": "0.139.0",
12
12
  "typebox": "1.1.39",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/codex",
3
- "version": "2026.6.10-beta.2",
3
+ "version": "2026.6.11-beta.2",
4
4
  "description": "OpenClaw Codex app-server harness and model provider plugin with a Codex-managed GPT catalog.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -34,10 +34,10 @@
34
34
  ]
35
35
  },
36
36
  "compat": {
37
- "pluginApi": ">=2026.6.10-beta.2"
37
+ "pluginApi": ">=2026.6.11-beta.2"
38
38
  },
39
39
  "build": {
40
- "openclawVersion": "2026.6.10-beta.2"
40
+ "openclawVersion": "2026.6.11-beta.2"
41
41
  },
42
42
  "release": {
43
43
  "publishToClawHub": true,
@@ -55,7 +55,7 @@
55
55
  "README.md"
56
56
  ],
57
57
  "peerDependencies": {
58
- "openclaw": ">=2026.6.10-beta.2"
58
+ "openclaw": ">=2026.6.11-beta.2"
59
59
  },
60
60
  "peerDependenciesMeta": {
61
61
  "openclaw": {