@openclaw/codex 2026.7.2-beta.7 → 2026.8.1-beta.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +2 -0
  2. package/dist/api.js +147 -0
  3. package/dist/app-server-policy-bg5QPSVP.js +25 -0
  4. package/dist/attempt-client-cleanup-URjUlCHg.js +735 -0
  5. package/dist/binding-connection-DAvZwp96.js +45 -0
  6. package/dist/{bounded-turn-D2ZAgZVz.js → bounded-turn-4BjrZEwW.js} +63 -56
  7. package/dist/{capabilities-BFDTVYr4.js → capabilities-CH3K57v4.js} +8 -2
  8. package/dist/cli-metadata.js +1 -1
  9. package/dist/{command-formatters-C336eRVS.js → command-formatters-D0nZ3qtd.js} +18 -18
  10. package/dist/{command-handlers-DAHUSry9.js → command-handlers-DC86lgT4.js} +507 -101
  11. package/dist/command-rpc-xUIIonsO.js +90 -0
  12. package/dist/{compact-D_uvHurS.js → compact-COqgBRny.js} +234 -214
  13. package/dist/{session-binding-BXpo9ymA.js → config-CpNeo5AE.js} +284 -1163
  14. package/dist/context-compaction-activity-BOeJf7yo.js +58 -0
  15. package/dist/{conversation-binding-data-BHRpYbX3.js → conversation-binding-data-CW2GuupV.js} +6 -10
  16. package/dist/doctor-contract-api.js +48 -50
  17. package/dist/{dynamic-tools-D2gYkSBO.js → dynamic-tools-fJZhl4CE.js} +3442 -1433
  18. package/dist/{effective-mcp-catalog-Bbd98Inw.js → effective-mcp-catalog-4YKn51aG.js} +20 -15
  19. package/dist/elicitation-input-DMkeki8d.js +71 -0
  20. package/dist/{event-projector-assistant-message-DTgnPPVF.js → event-projector-assistant-message-BwxV4d6N.js} +11 -23
  21. package/dist/{attempt-notifications-AP-a-Q5k.js → event-projector-usage-CLwNEJqW.js} +113 -29
  22. package/dist/harness-DoKQcF8n.js +258 -0
  23. package/dist/harness.js +2 -160
  24. package/dist/image-payload-sanitizer-CnfoUPCE.js +65 -0
  25. package/dist/index.js +730 -256
  26. package/dist/isolated-completion-DPMtlH9r.js +75 -0
  27. package/dist/local-runtime-attribution-B_2mnqhb.js +19 -0
  28. package/dist/managed-binary-By4FZC6i.js +212 -0
  29. package/dist/media-understanding-provider.js +5 -5
  30. package/dist/model-catalog-CmGoqVKB.js +48 -0
  31. package/dist/{models-BBMKU4jA.js → models-CZw1wClT.js} +12 -17
  32. package/dist/native-subagent-monitor-GGq3RnOo.js +3225 -0
  33. package/dist/node-exec-server.runtime-Bsu1LdFZ.js +192 -0
  34. package/dist/{plugin-app-cache-key-DztPafOA.js → plugin-app-cache-key-DMNQ8Zi8.js} +18 -6
  35. package/dist/plugin-approval-roundtrip-C75Yiiwc.js +95 -0
  36. package/dist/plugin-marketplace-discovery-CSWDkMrP.js +399 -0
  37. package/dist/{computer-use-CYEc8U3w.js → plugin-metadata-cache-BXH5NF-4.js} +109 -6
  38. package/dist/protocol-validators-VAVyEnDp.js +2399 -0
  39. package/dist/{rate-limits-CU-gVCCS.js → rate-limits-BI1dMHDG.js} +17 -35
  40. package/dist/{request-qKh331yu.js → request-DSK0W6YI.js} +3 -3
  41. package/dist/{run-attempt-CY9WlDLc.js → run-attempt-BV3HzuCf.js} +3416 -7194
  42. package/dist/{runtime-artifact-CmtG_t1L.js → runtime-artifact-BvyT1uyd.js} +11 -29
  43. package/dist/{sandbox-guard-NuhpXmPB.js → sandbox-guard-C1qEeZ5C.js} +29 -30
  44. package/dist/session-binding-BTrLf9Qm.js +874 -0
  45. package/dist/{session-catalog-DyOgR4WH.js → session-catalog-ezP_UcRM.js} +1584 -1289
  46. package/dist/session-catalog-home-id-BNwAJ9D7.js +18 -0
  47. package/dist/{session-cli-2PZaFLRh.js → session-cli-B1hKvfkI.js} +20 -7
  48. package/dist/session-retirement-CE4iMiLh.js +36 -0
  49. package/dist/{session-upstream-marker-B6U7tLw5.js → session-upstream-marker-D_2npHlA.js} +1 -1
  50. package/dist/{settled-turn-finalizer-CXY2Z9dT.js → settled-turn-finalizer-Dx1onIqg.js} +40 -28
  51. package/dist/{shared-client-DTbvH-XV.js → shared-client-Dw-rzii0.js} +1315 -469
  52. package/dist/{side-question-_ulBk1AL.js → side-question-DbXkJZzg.js} +140 -69
  53. package/dist/{thread-lifecycle-DF53ogiA.js → thread-lifecycle-DKdrnTMX.js} +927 -768
  54. package/dist/thread-ownership-i2NBwDUL.js +92 -0
  55. package/dist/thread-resume-CdJk2Ehf.js +30 -0
  56. package/dist/transcript-mirror-BU0_LKAL.js +588 -0
  57. package/dist/{transport-stdio-DXgGZ7Ib.js → transport-stdio-DhoGy33Z.js} +13 -2
  58. package/dist/upstream-prompt-provenance-CFmsKwr9.js +39 -0
  59. package/dist/{upstream-session-fork-Dy4Xvuoj.js → upstream-session-fork-BDVJCLAD.js} +14 -8
  60. package/dist/{usage-CQ6GhD5-.js → usage-9dKJCgcy.js} +3 -3
  61. package/dist/{web-search-provider.runtime-CCFhg2z5.js → web-search-provider.runtime-DCdx4DGu.js} +8 -9
  62. package/openclaw.plugin.json +49 -4
  63. package/package.json +6 -5
  64. package/dist/app-server-policy-BSaO2JIT.js +0 -49
  65. package/dist/conversation-control-xsIeXbo4.js +0 -287
  66. package/dist/event-projector-usage-Xp4AlR2k.js +0 -86
  67. package/dist/notification-correlation-CU6_AnOb.js +0 -67
  68. package/dist/transcript-mirror-DzsdNCf5.js +0 -6924
@@ -1,23 +1,34 @@
1
- import { W as isJsonObject, a as getLeasedSharedCodexAppServerClient, l as releaseLeasedSharedCodexAppServerClient, v as CodexAppServerRpcError } from "./shared-client-DTbvH-XV.js";
2
- import { d as sessionBindingIdentity, t as CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS } from "./session-binding-BXpo9ymA.js";
3
- import { _ as readCodexNotificationItem } from "./attempt-notifications-AP-a-Q5k.js";
4
- import { n as resolveCodexNativeExecutionBlock } from "./sandbox-guard-NuhpXmPB.js";
5
- import { a as resolveCodexBindingAppServerConnection, n as readCodexNotificationThreadId, r as readCodexNotificationTurnId } from "./notification-correlation-CU6_AnOb.js";
1
+ import { B as CodexAppServerRpcError, U as consumeCodexAppServerLiveThread, Y as retainCodexAppServerLiveThread, a as getLeasedSharedCodexAppServerClient, l as releaseLeasedSharedCodexAppServerClient, ut as isJsonObject } from "./shared-client-Dw-rzii0.js";
2
+ import { d as sessionBindingIdentity, t as CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS } from "./session-binding-BTrLf9Qm.js";
3
+ import { _ as readCodexNotificationTurnId, a as closeCodexStartupClientBestEffort, d as unsubscribeCodexThreadBestEffort, g as readCodexNotificationThreadId, r as CodexAppServerUnsafeSubscriptionError, s as isCodexAlreadyTerminalInterruptError } from "./attempt-client-cleanup-URjUlCHg.js";
4
+ import { i as readCodexThreadContextSnapshot, x as readCodexNotificationItem } from "./event-projector-usage-CLwNEJqW.js";
5
+ import { t as isIncognitoSessionKey } from "./incognito-session-ET_ufDH-.js";
6
+ import { t as resumeCodexAppServerThread } from "./thread-resume-CdJk2Ehf.js";
7
+ import { n as resolveCodexNativeExecutionBlock } from "./sandbox-guard-C1qEeZ5C.js";
8
+ import { t as isSameCodexAppServerThreadOwner } from "./thread-ownership-i2NBwDUL.js";
9
+ import { n as resolveCodexBindingAppServerConnection } from "./binding-connection-DAvZwp96.js";
10
+ import { t as persistCodexContextCompactionActivity } from "./context-compaction-activity-BOeJf7yo.js";
11
+ import { asOptionalRecord } from "openclaw/plugin-sdk/string-coerce-runtime";
12
+ import { createDeferred } from "openclaw/plugin-sdk/extension-shared";
6
13
  import { embeddedAgentLog, resolveCompactionTimeoutMs } from "openclaw/plugin-sdk/agent-harness-runtime";
7
- import { resolveAgentDir as resolveAgentDir$1, resolveDefaultAgentId } from "openclaw/plugin-sdk/agent-runtime";
14
+ import { resolveAgentDir as resolveAgentDir$1 } from "openclaw/plugin-sdk/agent-runtime";
15
+ import { resolveDefaultAgentId as resolveDefaultAgentId$1 } from "openclaw/plugin-sdk/agent-scope-runtime";
16
+ import { AsyncLocalStorage } from "node:async_hooks";
17
+ import { coerceErrorMessage } from "openclaw/plugin-sdk/error-runtime";
18
+ import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
19
+ import { createDedupeCache } from "openclaw/plugin-sdk/dedupe-runtime";
8
20
  //#region extensions/codex/src/app-server/compact.ts
9
21
  /**
10
22
  * Native Codex app-server compaction bridge for bound OpenClaw sessions.
11
23
  */
12
- const warnedIgnoredCompactionOverrides = /* @__PURE__ */ new Set();
13
- const codexNativeCompactionQueues = /* @__PURE__ */ new Map();
24
+ const warnedIgnoredCompactionOverrides = createDedupeCache({
25
+ ttlMs: 0,
26
+ maxSize: 4096
27
+ });
28
+ const codexNativeCompactionQueue = new KeyedAsyncQueue();
14
29
  const CODEX_NATIVE_COMPACTION_INTERRUPT_GRACE_MS = 3e4;
15
- const CODEX_NO_ACTIVE_TURN_ERROR_CODE = -32600;
16
- const CODEX_NO_ACTIVE_TURN_ERROR_MESSAGE = "no active turn to interrupt";
17
- function isAlreadyTerminalInterruptError(error) {
18
- return error instanceof CodexAppServerRpcError && error.code === CODEX_NO_ACTIVE_TURN_ERROR_CODE && error.message === CODEX_NO_ACTIVE_TURN_ERROR_MESSAGE;
19
- }
20
30
  function watchCodexNativeCompactionCompletion(params) {
31
+ const runOutsideBindingLease = AsyncLocalStorage.snapshot();
21
32
  let settled = false;
22
33
  let requestStarted = false;
23
34
  let abortRequested = false;
@@ -26,10 +37,8 @@ function watchCodexNativeCompactionCompletion(params) {
26
37
  let compactionTurnId;
27
38
  let compactionItemId;
28
39
  let compactionItemCompleted = false;
29
- let resolveCompletion = (_result) => {};
30
- const completion = new Promise((resolve) => {
31
- resolveCompletion = resolve;
32
- });
40
+ let tokensAfter;
41
+ const { promise: completion, resolve: resolveCompletion } = createDeferred();
33
42
  let removeNotificationHandler = () => {};
34
43
  let removeCloseHandler = () => {};
35
44
  let removeAbortHandler = () => {};
@@ -45,17 +54,24 @@ function watchCodexNativeCompactionCompletion(params) {
45
54
  clearTimeout(interruptGraceTimeout);
46
55
  resolveCompletion(result);
47
56
  };
57
+ const complete = () => finish({
58
+ completed: true,
59
+ ...compactionTurnId ? { turnId: compactionTurnId } : {},
60
+ ...compactionItemId ? { itemId: compactionItemId } : {},
61
+ ...tokensAfter !== void 0 ? { tokensAfter } : {}
62
+ });
63
+ const fail = (reason) => finish({
64
+ completed: false,
65
+ reason
66
+ });
48
67
  const retireUnconfirmed = (reason) => {
49
68
  if (settled || retirementStarted) return;
50
69
  retirementStarted = true;
51
- params.retireUnconfirmed().then(() => finish({
52
- completed: false,
53
- reason
54
- })).catch((error) => {
70
+ runOutsideBindingLease(() => params.retireUnconfirmed()).then(() => fail(reason)).catch((error) => {
55
71
  embeddedAgentLog.error("failed to retire unconfirmed codex app-server compaction", {
56
72
  threadId: params.threadId,
57
73
  turnId: compactionTurnId,
58
- reason: formatCompactionError(error)
74
+ reason: coerceErrorMessage(error)
59
75
  });
60
76
  });
61
77
  };
@@ -65,23 +81,19 @@ function watchCodexNativeCompactionCompletion(params) {
65
81
  params.client.request("turn/interrupt", {
66
82
  threadId: params.threadId,
67
83
  turnId: compactionTurnId
68
- }, { timeoutMs: Math.max(1, params.interruptGraceMs) }).then(() => {
69
- finish({
70
- completed: false,
71
- reason: "codex app-server confirmed native compaction interruption"
72
- });
73
- }).catch((error) => {
74
- if (isAlreadyTerminalInterruptError(error)) {
75
- finish(compactionItemCompleted ? { completed: true } : {
76
- completed: false,
77
- reason: "codex app-server compaction reached terminal state without a completed compaction item"
78
- });
84
+ }, { timeoutMs: Math.max(1, params.interruptGraceMs) }).catch((error) => {
85
+ if (isCodexAlreadyTerminalInterruptError(error)) {
86
+ if (compactionItemCompleted) {
87
+ complete();
88
+ return;
89
+ }
90
+ fail("codex app-server compaction reached terminal state without a completed compaction item");
79
91
  return;
80
92
  }
81
93
  embeddedAgentLog.warn("codex app-server compaction interrupt request failed", {
82
94
  threadId: params.threadId,
83
95
  turnId: compactionTurnId,
84
- reason: formatCompactionError(error)
96
+ reason: coerceErrorMessage(error)
85
97
  });
86
98
  });
87
99
  };
@@ -121,6 +133,10 @@ function watchCodexNativeCompactionCompletion(params) {
121
133
  return;
122
134
  }
123
135
  if (compactionTurnId && notificationTurnId !== compactionTurnId) return;
136
+ if (notification.method === "thread/tokenUsage/updated") {
137
+ tokensAfter = readCodexThreadContextSnapshot(notification.params).activeContextTokens ?? tokensAfter;
138
+ return;
139
+ }
124
140
  const item = readCodexNotificationItem(notification.params);
125
141
  if (item?.type === "contextCompaction") {
126
142
  if (notification.method === "item/started") {
@@ -138,27 +154,15 @@ function watchCodexNativeCompactionCompletion(params) {
138
154
  const turn = isJsonObject(notification.params.turn) ? notification.params.turn : void 0;
139
155
  const status = typeof turn?.status === "string" ? turn.status : void 0;
140
156
  if (status !== "completed") {
141
- finish({
142
- completed: false,
143
- reason: `codex app-server compaction turn ended with status ${status ?? "unknown"}`
144
- });
157
+ fail(`codex app-server compaction turn ended with status ${status ?? "unknown"}`);
145
158
  return;
146
159
  }
147
- if (!compactionItemId) {
148
- finish({
149
- completed: false,
150
- reason: "codex app-server compaction turn completed without a compaction item"
151
- });
160
+ const incompleteReason = !compactionItemId ? "codex app-server compaction turn completed without a compaction item" : !compactionItemCompleted ? "codex app-server compaction turn completed before its compaction item" : void 0;
161
+ if (incompleteReason) {
162
+ fail(incompleteReason);
152
163
  return;
153
164
  }
154
- if (!compactionItemCompleted) {
155
- finish({
156
- completed: false,
157
- reason: "codex app-server compaction turn completed before its compaction item"
158
- });
159
- return;
160
- }
161
- finish({ completed: true });
165
+ complete();
162
166
  });
163
167
  removeCloseHandler = params.client.addCloseHandler(() => {
164
168
  retireUnconfirmed("codex app-server closed before native compaction completed");
@@ -179,57 +183,35 @@ function watchCodexNativeCompactionCompletion(params) {
179
183
  beginCompletionTimeout();
180
184
  if (abortRequested) beginInterruptGrace();
181
185
  },
182
- confirmRequestRejected: () => finish({
183
- completed: false,
184
- reason: "codex app-server rejected the compaction request"
185
- }),
186
+ confirmRequestRejected: () => fail("codex app-server rejected the compaction request"),
186
187
  retireUnconfirmedRequest: async (reason) => {
187
188
  retireUnconfirmed(reason);
188
189
  return await completion;
189
190
  },
190
191
  cancel: () => {
191
- if (!requestStarted) finish({
192
- completed: false,
193
- reason: "compaction request did not start"
194
- });
192
+ if (!requestStarted) fail("compaction request did not start");
195
193
  }
196
194
  };
197
195
  }
198
196
  async function runExclusiveCodexNativeCompaction(threadId, signal, run) {
199
- const previous = codexNativeCompactionQueues.get(threadId) ?? Promise.resolve();
200
- let releaseCurrent;
201
- const current = new Promise((resolve) => {
202
- releaseCurrent = resolve;
203
- });
204
- const queued = previous.then(() => current, () => current);
205
- codexNativeCompactionQueues.set(threadId, queued);
206
- try {
207
- await waitForCodexNativeCompactionQueue(previous, signal);
197
+ signal?.throwIfAborted();
198
+ let started = false;
199
+ const queued = codexNativeCompactionQueue.enqueue(threadId, async () => {
200
+ started = true;
208
201
  signal?.throwIfAborted();
209
- return await run();
210
- } finally {
211
- releaseCurrent();
212
- queued.then(() => {
213
- if (codexNativeCompactionQueues.get(threadId) === queued) codexNativeCompactionQueues.delete(threadId);
214
- });
215
- }
216
- }
217
- async function waitForCodexNativeCompactionQueue(previous, signal) {
218
- if (!signal) {
219
- await previous.catch(() => void 0);
220
- return;
221
- }
222
- signal.throwIfAborted();
202
+ return run();
203
+ });
204
+ if (!signal) return queued;
223
205
  let removeAbortListener = () => {};
224
206
  const aborted = new Promise((_, reject) => {
225
207
  const onAbort = () => {
226
- reject(signal.reason instanceof Error ? signal.reason : /* @__PURE__ */ new Error("compaction aborted"));
208
+ if (!started) reject(signal.reason instanceof Error ? signal.reason : /* @__PURE__ */ new Error("compaction aborted"));
227
209
  };
228
210
  removeAbortListener = () => signal.removeEventListener("abort", onAbort);
229
211
  signal.addEventListener("abort", onAbort, { once: true });
230
212
  });
231
213
  try {
232
- await Promise.race([previous.catch(() => void 0), aborted]);
214
+ return await Promise.race([queued, aborted]);
233
215
  } finally {
234
216
  removeAbortListener();
235
217
  }
@@ -246,8 +228,7 @@ function warnIfIgnoringOpenClawCompactionOverrides(params) {
246
228
  const ignoredConfig = readIgnoredCompactionOverridePaths(params);
247
229
  if (ignoredConfig.length === 0) return;
248
230
  const warningKey = ignoredConfig.join("\0");
249
- if (warnedIgnoredCompactionOverrides.has(warningKey)) return;
250
- warnedIgnoredCompactionOverrides.add(warningKey);
231
+ if (warnedIgnoredCompactionOverrides.check(warningKey)) return;
251
232
  embeddedAgentLog.warn("ignoring OpenClaw compaction overrides for Codex app-server compaction; Codex uses native server-side compaction", {
252
233
  sessionId: params.sessionId,
253
234
  sessionKey: params.sessionKey,
@@ -258,34 +239,19 @@ function readIgnoredCompactionOverridePaths(params) {
258
239
  const ignored = /* @__PURE__ */ new Set();
259
240
  for (const entry of readCompactionOverrideEntries(params)) {
260
241
  const localProvider = typeof entry.record.provider === "string" ? entry.record.provider.trim() : "";
261
- const inheritedProvider = !localProvider && typeof entry.inheritedRecord?.provider === "string" ? entry.inheritedRecord.provider.trim() : "";
262
- const providerPath = localProvider ? `${entry.path}.compaction.provider` : inheritedProvider && entry.inheritedPath ? `${entry.inheritedPath}.compaction.provider` : void 0;
263
242
  if (typeof entry.record.model === "string" && entry.record.model.trim()) ignored.add(`${entry.path}.compaction.model`);
264
243
  if (typeof entry.record.thinkingLevel === "string" && entry.record.thinkingLevel.trim()) ignored.add(`${entry.path}.compaction.thinkingLevel`);
265
- if (providerPath) ignored.add(providerPath);
244
+ if (localProvider) ignored.add(`${entry.path}.compaction.provider`);
266
245
  }
267
246
  return [...ignored];
268
247
  }
269
248
  function readCompactionOverrideEntries(params) {
270
249
  const entries = [];
271
- const defaultCompaction = readRecord(readRecord(params.config?.agents)?.defaults)?.compaction;
272
- const defaultRecord = readRecord(defaultCompaction);
250
+ const defaultRecord = asOptionalRecord(params.config?.agents?.defaults?.compaction);
273
251
  if (defaultRecord) entries.push({
274
252
  path: "agents.defaults",
275
253
  record: defaultRecord
276
254
  });
277
- const agentId = readAgentIdFromSessionKey(params.sessionKey ?? params.sandboxSessionKey);
278
- if (!agentId) return entries;
279
- const agentCompaction = readRecord((Array.isArray(params.config?.agents?.list) ? params.config.agents.list : []).find((agent) => {
280
- return (typeof agent?.id === "string" ? agent.id.trim().toLowerCase() : "") === agentId;
281
- }))?.compaction;
282
- const agentRecord = readRecord(agentCompaction);
283
- if (agentRecord) entries.push({
284
- path: `agents.list.${agentId}`,
285
- record: agentRecord,
286
- inheritedRecord: defaultRecord,
287
- inheritedPath: "agents.defaults"
288
- });
289
255
  return entries;
290
256
  }
291
257
  function readAgentIdFromSessionKey(sessionKey) {
@@ -293,9 +259,6 @@ function readAgentIdFromSessionKey(sessionKey) {
293
259
  if (parts.length < 3 || parts[0] !== "agent") return;
294
260
  return parts[1]?.trim() || void 0;
295
261
  }
296
- function readRecord(value) {
297
- return value && typeof value === "object" && !Array.isArray(value) ? value : void 0;
298
- }
299
262
  async function compactCodexNativeThread(params, options) {
300
263
  if (params.trigger !== "manual" && !options.allowNonManualNativeRequest) {
301
264
  embeddedAgentLog.info("skipping codex app-server compaction for non-manual trigger", {
@@ -303,27 +266,24 @@ async function compactCodexNativeThread(params, options) {
303
266
  sessionKey: params.sessionKey,
304
267
  trigger: params.trigger
305
268
  });
306
- return {
307
- ok: true,
269
+ return codexNativeCompactionResult(params, {
308
270
  compacted: false,
309
271
  reason: "codex app-server owns automatic compaction",
310
- result: {
311
- summary: "",
312
- firstKeptEntryId: "",
313
- tokensBefore: params.currentTokenCount ?? 0,
314
- details: {
315
- backend: "codex-app-server",
316
- skipped: true,
317
- reason: "non_manual_trigger",
318
- trigger: params.trigger ?? "unknown"
319
- }
272
+ details: {
273
+ backend: "codex-app-server",
274
+ skipped: true,
275
+ reason: "non_manual_trigger",
276
+ trigger: params.trigger ?? "unknown"
320
277
  }
321
- };
278
+ });
322
279
  }
280
+ const sandbox = params.sandbox;
323
281
  const nativeExecutionBlock = resolveCodexNativeExecutionBlock({
324
282
  config: params.config,
325
283
  sessionKey: params.sandboxSessionKey ?? params.sessionKey,
326
284
  sessionId: params.sessionId,
285
+ agentId: params.agentId,
286
+ sandbox,
327
287
  surface: "native compaction"
328
288
  });
329
289
  if (nativeExecutionBlock) return {
@@ -342,12 +302,22 @@ async function compactCodexNativeThread(params, options) {
342
302
  reason: "no codex app-server thread binding",
343
303
  recovery: "missing_thread_binding"
344
304
  });
305
+ if (params.nativeToolSurface === "host-isolated" || initialBinding.nativeToolPolicyRestricted === true || initialBinding.ringZeroConfigFingerprint !== void 0) return codexNativeCompactionResult(params, {
306
+ compacted: false,
307
+ reason: "native compaction is unavailable for a host-isolated Codex session",
308
+ details: {
309
+ backend: "codex-app-server",
310
+ skipped: true,
311
+ reason: "native_tool_policy_restricted",
312
+ expectedThreadId: initialBinding.threadId
313
+ }
314
+ });
345
315
  let binding = initialBinding;
346
316
  const requestedAuthProfileId = params.authProfileId?.trim() || void 0;
347
317
  let connection;
348
318
  try {
349
319
  const config = params.config ?? {};
350
- const agentId = params.agentId ?? readAgentIdFromSessionKey(params.sessionKey) ?? resolveDefaultAgentId(config);
320
+ const agentId = params.agentId ?? readAgentIdFromSessionKey(params.sessionKey) ?? resolveDefaultAgentId$1(config);
351
321
  connection = resolveCodexBindingAppServerConnection({
352
322
  binding,
353
323
  authProfileId: requestedAuthProfileId ?? binding.authProfileId,
@@ -359,7 +329,7 @@ async function compactCodexNativeThread(params, options) {
359
329
  return {
360
330
  ok: false,
361
331
  compacted: false,
362
- reason: formatCompactionError(error)
332
+ reason: coerceErrorMessage(error)
363
333
  };
364
334
  }
365
335
  const { appServer, usesSupervisionConnection } = connection;
@@ -389,6 +359,19 @@ async function compactCodexNativeThread(params, options) {
389
359
  agentDir: params.agentDir,
390
360
  config: params.config
391
361
  });
362
+ let releaseThreadSubscription;
363
+ let retainedThreadOwnership;
364
+ let compactionSucceeded = false;
365
+ let compactionRequestDefinitelyRejected = false;
366
+ let tokensAfter;
367
+ const releaseCompactionThread = async (threadId) => {
368
+ if (await unsubscribeCodexThreadBestEffort(client, {
369
+ threadId,
370
+ timeoutMs: 5e3
371
+ })) return;
372
+ await closeCodexStartupClientBestEffort(client);
373
+ throw new CodexAppServerUnsafeSubscriptionError(`Codex compaction thread subscription could not be released: ${threadId}`);
374
+ };
392
375
  const completionWatch = watchCodexNativeCompactionCompletion({
393
376
  client,
394
377
  threadId: binding.threadId,
@@ -396,6 +379,7 @@ async function compactCodexNativeThread(params, options) {
396
379
  timeoutMs: options.nativeCompletionTimeoutMs ?? resolveCompactionTimeoutMs(params.config),
397
380
  interruptGraceMs: options.nativeInterruptGraceMs ?? CODEX_NATIVE_COMPACTION_INTERRUPT_GRACE_MS,
398
381
  retireUnconfirmed: async () => {
382
+ releaseThreadSubscription = void 0;
399
383
  const transportStopped = await client.closeAndWait({
400
384
  exitTimeoutMs: 5e3,
401
385
  forceKillDelayMs: 250
@@ -413,84 +397,98 @@ async function compactCodexNativeThread(params, options) {
413
397
  throw new Error("failed to detach unconfirmed codex app-server thread binding");
414
398
  }
415
399
  });
416
- const beginNativeCompactionRequest = async (timeoutMs) => {
417
- completionWatch.beginRequest();
418
- const requestParams = { threadId: binding.threadId };
419
- if (timeoutMs === void 0) await client.request("thread/compact/start", requestParams);
420
- else await client.request("thread/compact/start", requestParams, { timeoutMs });
421
- };
422
- const settleNativeCompactionRequestError = async (error) => {
423
- if (error instanceof CodexAppServerRpcError) completionWatch.confirmRequestRejected();
424
- else await completionWatch.retireUnconfirmedRequest(`codex app-server compaction start was unconfirmed: ${formatCompactionError(error)}`);
400
+ const acquireThreadSubscription = async (timeoutMs) => {
401
+ if (!isIncognitoSessionKey(params.sessionKey)) {
402
+ retainedThreadOwnership = await consumeCodexAppServerLiveThread(client, binding.threadId);
403
+ if (!retainedThreadOwnership) await resumeCodexAppServerThread({
404
+ client,
405
+ abandonClient: async () => closeCodexStartupClientBestEffort(client),
406
+ request: {
407
+ threadId: binding.threadId,
408
+ excludeTurns: true
409
+ },
410
+ timeoutMs: timeoutMs ?? appServer.requestTimeoutMs,
411
+ ...params.abortSignal ? { signal: params.abortSignal } : {}
412
+ });
413
+ releaseThreadSubscription = async () => releaseCompactionThread(binding.threadId);
414
+ }
425
415
  };
426
416
  try {
427
- if (options.allowNonManualNativeRequest) {
428
- const guardedResult = await options.bindingStore.withLease(bindingIdentity, async () => {
429
- const currentBinding = await options.bindingStore.read(bindingIdentity);
430
- if (params.abortSignal?.aborted) return {
417
+ const guardedResult = await options.bindingStore.withLease(bindingIdentity, async () => {
418
+ const currentBinding = await options.bindingStore.read(bindingIdentity);
419
+ if (params.abortSignal?.aborted) {
420
+ if (!options.allowNonManualNativeRequest) params.abortSignal.throwIfAborted();
421
+ return {
431
422
  started: false,
432
423
  result: skippedCodexNativeCompactionResult(params, {
433
424
  reason: "codex app-server compaction aborted before native compaction",
434
425
  code: "aborted_before_native_compaction",
426
+ request: options.nativeCompactionRequest ?? "after_context_engine",
435
427
  expectedThreadId: binding.threadId,
436
428
  currentThreadId: currentBinding?.threadId
437
429
  })
438
430
  };
439
- if (!currentBinding || !isSameNativeCompactionBinding(currentBinding, binding)) {
440
- embeddedAgentLog.warn("skipping codex app-server compaction because the thread binding changed", {
441
- sessionId: params.sessionId,
442
- sessionKey: params.sessionKey,
443
- expectedThreadId: binding.threadId,
444
- currentThreadId: currentBinding?.threadId
445
- });
446
- return {
447
- started: false,
448
- result: skippedCodexNativeCompactionResult(params, {
449
- reason: "codex app-server binding changed before native compaction",
450
- code: "binding_changed_before_native_compaction",
451
- expectedThreadId: binding.threadId,
452
- currentThreadId: currentBinding?.threadId
453
- })
454
- };
455
- }
456
- binding = currentBinding;
457
- await clearContextEngineProjectionBeforeNativeCompaction({
431
+ }
432
+ if (!currentBinding || !isSameNativeCompactionBinding(currentBinding, binding)) {
433
+ embeddedAgentLog.warn("codex app-server compaction could not use the thread binding because it changed", {
458
434
  sessionId: params.sessionId,
459
- bindingStore: options.bindingStore,
460
- identity: bindingIdentity,
461
- binding
435
+ sessionKey: params.sessionKey,
436
+ expectedThreadId: binding.threadId,
437
+ currentThreadId: currentBinding?.threadId
462
438
  });
463
- try {
464
- await beginNativeCompactionRequest(Math.min(appServer.requestTimeoutMs, CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS));
465
- return {
466
- started: true,
467
- accepted: true
468
- };
469
- } catch (error) {
439
+ const isRequiredPreflight = options.nativeCompactionRequest === "required_preflight";
440
+ return {
441
+ started: false,
442
+ result: options.allowNonManualNativeRequest && !isRequiredPreflight ? skippedCodexNativeCompactionResult(params, {
443
+ reason: "codex app-server binding changed before native compaction",
444
+ code: "binding_changed_before_native_compaction",
445
+ request: options.nativeCompactionRequest ?? "after_context_engine",
446
+ expectedThreadId: binding.threadId,
447
+ currentThreadId: currentBinding?.threadId
448
+ }) : failedCodexThreadBindingCompactionResult(params, {
449
+ threadId: currentBinding?.threadId ?? binding.threadId,
450
+ reason: "codex app-server binding changed before native compaction",
451
+ recovery: "stale_thread_binding"
452
+ })
453
+ };
454
+ }
455
+ binding = currentBinding;
456
+ const guardedRequestTimeoutMs = options.allowNonManualNativeRequest ? Math.min(appServer.requestTimeoutMs, CODEX_APP_SERVER_BINDING_GUARDED_REQUEST_TIMEOUT_MS) : void 0;
457
+ await acquireThreadSubscription(guardedRequestTimeoutMs);
458
+ await clearContextEngineProjectionBeforeNativeCompaction({
459
+ sessionId: params.sessionId,
460
+ bindingStore: options.bindingStore,
461
+ identity: bindingIdentity,
462
+ binding
463
+ });
464
+ try {
465
+ completionWatch.beginRequest();
466
+ if (guardedRequestTimeoutMs === void 0) await client.request("thread/compact/start", { threadId: binding.threadId });
467
+ else await client.request("thread/compact/start", { threadId: binding.threadId }, { timeoutMs: guardedRequestTimeoutMs });
468
+ return {
469
+ started: true,
470
+ accepted: true
471
+ };
472
+ } catch (error) {
473
+ if (error instanceof CodexAppServerRpcError) {
470
474
  await options.bindingStore.mutate(bindingIdentity, {
471
475
  kind: "set",
472
476
  binding
473
477
  });
474
- return {
475
- started: true,
476
- accepted: false,
477
- error
478
- };
478
+ compactionRequestDefinitelyRejected = !isCodexThreadNotFoundError(error);
479
479
  }
480
- });
481
- if (!guardedResult.started) return guardedResult.result;
482
- if (!guardedResult.accepted) {
483
- await settleNativeCompactionRequestError(guardedResult.error);
484
- throw guardedResult.error;
485
- }
486
- } else {
487
- params.abortSignal?.throwIfAborted();
488
- try {
489
- await beginNativeCompactionRequest();
490
- } catch (error) {
491
- await settleNativeCompactionRequestError(error);
492
- throw error;
480
+ return {
481
+ started: true,
482
+ accepted: false,
483
+ error
484
+ };
493
485
  }
486
+ });
487
+ if (!guardedResult.started) return guardedResult.result;
488
+ if (!guardedResult.accepted) {
489
+ if (guardedResult.error instanceof CodexAppServerRpcError) completionWatch.confirmRequestRejected();
490
+ else await completionWatch.retireUnconfirmedRequest(`codex app-server compaction start was unconfirmed: ${coerceErrorMessage(guardedResult.error)}`);
491
+ throw guardedResult.error;
494
492
  }
495
493
  embeddedAgentLog.info("started codex app-server compaction", {
496
494
  sessionId: params.sessionId,
@@ -498,58 +496,76 @@ async function compactCodexNativeThread(params, options) {
498
496
  });
499
497
  const completion = await completionWatch.completion;
500
498
  if (!completion.completed) throw new Error(completion.reason);
499
+ tokensAfter = completion.tokensAfter;
500
+ if (completion.turnId && completion.itemId) await persistCodexContextCompactionActivity({
501
+ sessionTarget: params.sessionTarget,
502
+ config: params.config,
503
+ cwd: params.workspaceDir,
504
+ runId: params.runId,
505
+ threadId: binding.threadId,
506
+ turnId: completion.turnId,
507
+ itemId: completion.itemId,
508
+ timestamp: Date.now()
509
+ });
501
510
  embeddedAgentLog.info("completed codex app-server compaction", {
502
511
  sessionId: params.sessionId,
503
512
  threadId: binding.threadId
504
513
  });
514
+ compactionSucceeded = true;
505
515
  } catch (error) {
506
516
  if (isCodexThreadNotFoundError(error)) return failedCodexThreadBindingCompactionResult(params, {
507
517
  threadId: binding.threadId,
508
- reason: formatCompactionError(error),
518
+ reason: coerceErrorMessage(error),
509
519
  recovery: "stale_thread_binding"
510
520
  });
511
521
  embeddedAgentLog.warn("codex app-server compaction failed", {
512
522
  sessionId: params.sessionId,
513
523
  sessionKey: params.sessionKey,
514
524
  threadId: binding.threadId,
515
- reason: formatCompactionError(error)
525
+ reason: coerceErrorMessage(error)
516
526
  });
517
527
  return {
518
528
  ok: false,
519
529
  compacted: false,
520
- reason: formatCompactionError(error)
530
+ reason: coerceErrorMessage(error)
521
531
  };
522
532
  } finally {
523
533
  completionWatch.cancel();
524
- if (shouldReleaseDefaultLease) releaseLeasedSharedCodexAppServerClient(client);
534
+ try {
535
+ if ((compactionSucceeded || compactionRequestDefinitelyRejected) && retainedThreadOwnership) {
536
+ const ownership = retainedThreadOwnership;
537
+ if (!(isSameCodexAppServerThreadOwner(await options.bindingStore.read(bindingIdentity), binding) && await options.bindingStore.withLease(bindingIdentity, async () => {
538
+ if (!isSameCodexAppServerThreadOwner(await options.bindingStore.read(bindingIdentity), binding)) return false;
539
+ return await retainCodexAppServerLiveThread(client, binding.threadId, ownership.release, ownership.configFingerprint, ownership.serviceTier);
540
+ }))) await releaseThreadSubscription?.();
541
+ } else await releaseThreadSubscription?.();
542
+ } finally {
543
+ if (shouldReleaseDefaultLease) releaseLeasedSharedCodexAppServerClient(client);
544
+ }
525
545
  }
526
- const resultDetails = {
546
+ const details = {
527
547
  backend: "codex-app-server",
528
548
  threadId: binding.threadId,
529
549
  signal: "thread/compact/start",
530
550
  pending: false,
531
551
  completed: true,
532
552
  ...options.allowNonManualNativeRequest ? {
533
- request: "after_context_engine",
553
+ request: options.nativeCompactionRequest ?? "after_context_engine",
534
554
  trigger: params.trigger ?? "unknown"
535
555
  } : {}
536
556
  };
537
- return {
538
- ok: true,
557
+ return codexNativeCompactionResult(params, {
539
558
  compacted: true,
540
- result: {
541
- summary: "",
542
- firstKeptEntryId: "",
543
- tokensBefore: params.currentTokenCount ?? 0,
544
- details: resultDetails
545
- }
546
- };
559
+ tokensAfter,
560
+ details
561
+ });
547
562
  });
548
563
  } catch (error) {
549
564
  if (params.abortSignal?.aborted) {
550
565
  if (options.allowNonManualNativeRequest) return skippedCodexNativeCompactionResult(params, {
551
566
  reason: "codex app-server compaction aborted before native compaction",
552
567
  code: "aborted_before_native_compaction",
568
+ request: options.nativeCompactionRequest ?? "after_context_engine",
553
569
  expectedThreadId: initialBinding.threadId,
554
570
  currentThreadId: binding.threadId
555
571
  });
@@ -562,27 +578,35 @@ async function compactCodexNativeThread(params, options) {
562
578
  throw error;
563
579
  }
564
580
  }
565
- function skippedCodexNativeCompactionResult(params, skipped) {
581
+ function codexNativeCompactionResult(params, outcome) {
566
582
  return {
567
583
  ok: true,
568
- compacted: false,
569
- reason: skipped.reason,
584
+ compacted: outcome.compacted,
585
+ ...outcome.reason ? { reason: outcome.reason } : {},
570
586
  result: {
571
587
  summary: "",
572
588
  firstKeptEntryId: "",
573
589
  tokensBefore: params.currentTokenCount ?? 0,
574
- details: {
575
- backend: "codex-app-server",
576
- skipped: true,
577
- reason: skipped.code,
578
- request: "after_context_engine",
579
- trigger: params.trigger ?? "unknown",
580
- ...skipped.expectedThreadId ? { expectedThreadId: skipped.expectedThreadId } : {},
581
- ...skipped.currentThreadId ? { currentThreadId: skipped.currentThreadId } : {}
582
- }
590
+ ...outcome.tokensAfter !== void 0 ? { tokensAfter: outcome.tokensAfter } : {},
591
+ details: outcome.details
583
592
  }
584
593
  };
585
594
  }
595
+ function skippedCodexNativeCompactionResult(params, skipped) {
596
+ return codexNativeCompactionResult(params, {
597
+ compacted: false,
598
+ reason: skipped.reason,
599
+ details: {
600
+ backend: "codex-app-server",
601
+ skipped: true,
602
+ reason: skipped.code,
603
+ request: skipped.request ?? "after_context_engine",
604
+ trigger: params.trigger ?? "unknown",
605
+ ...skipped.expectedThreadId ? { expectedThreadId: skipped.expectedThreadId } : {},
606
+ ...skipped.currentThreadId ? { currentThreadId: skipped.currentThreadId } : {}
607
+ }
608
+ });
609
+ }
586
610
  function failedCodexThreadBindingCompactionResult(params, recovery) {
587
611
  embeddedAgentLog.warn("codex app-server compaction could not use thread binding", {
588
612
  sessionId: params.sessionId,
@@ -620,14 +644,10 @@ async function clearContextEngineProjectionBeforeNativeCompaction(params) {
620
644
  });
621
645
  }
622
646
  function isSameNativeCompactionBinding(current, expected) {
623
- return current.threadId === expected.threadId && current.authProfileId === expected.authProfileId && current.contextEngine?.engineId === expected.contextEngine?.engineId && current.contextEngine?.policyFingerprint === expected.contextEngine?.policyFingerprint && current.contextEngine?.projection?.mode === expected.contextEngine?.projection?.mode && current.contextEngine?.projection?.epoch === expected.contextEngine?.projection?.epoch && current.contextEngine?.projection?.fingerprint === expected.contextEngine?.projection?.fingerprint;
647
+ return isSameCodexAppServerThreadOwner(current, expected) && current.authProfileId === expected.authProfileId && current.contextEngine?.engineId === expected.contextEngine?.engineId && current.contextEngine?.policyFingerprint === expected.contextEngine?.policyFingerprint && current.contextEngine?.projection?.mode === expected.contextEngine?.projection?.mode && current.contextEngine?.projection?.epoch === expected.contextEngine?.projection?.epoch && current.contextEngine?.projection?.fingerprint === expected.contextEngine?.projection?.fingerprint;
624
648
  }
625
649
  function isCodexThreadNotFoundError(error) {
626
- return formatCompactionError(error).toLowerCase().includes("thread not found");
627
- }
628
- function formatCompactionError(error) {
629
- if (error instanceof Error) return error.message;
630
- return String(error);
650
+ return coerceErrorMessage(error).toLowerCase().includes("thread not found");
631
651
  }
632
652
  //#endregion
633
653
  export { maybeCompactCodexAppServerSession };