@openclaw/codex 2026.8.1-beta.2 → 2026.9.1-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/dist/api.js +147 -0
  2. package/dist/{attempt-client-cleanup-DMLXUfa8.js → attempt-client-cleanup-bfsmcQ6m.js} +21 -2
  3. package/dist/{binding-connection-I5Bo-AsX.js → binding-connection-BMvPX73o.js} +15 -3
  4. package/dist/{bounded-turn-qgZmzy_4.js → bounded-turn-B7iBUcuP.js} +22 -16
  5. package/dist/{capabilities-CybGI1oz.js → capabilities-BRMh0aIq.js} +1 -1
  6. package/dist/cli-metadata.js +1 -1
  7. package/dist/{command-formatters-B1AEz8ZA.js → command-formatters-DEsIufkt.js} +2 -2
  8. package/dist/{command-handlers-Db8pu_ds.js → command-handlers-D_-1_qRp.js} +65 -37
  9. package/dist/command-rpc-CCeCkf_v.js +90 -0
  10. package/dist/{compact-LspQaGfl.js → compact-BglNFZrQ.js} +35 -29
  11. package/dist/{session-binding-DPxIvMgE.js → config-giW8X0QA.js} +108 -914
  12. package/dist/context-compaction-activity-BOeJf7yo.js +58 -0
  13. package/dist/doctor-contract-api.js +23 -21
  14. package/dist/{dynamic-tools-BVdyWkUD.js → dynamic-tools-Dnlfa--w.js} +1345 -1424
  15. package/dist/{effective-mcp-catalog-DIIhAtOZ.js → effective-mcp-catalog-CTeGrnfO.js} +2 -2
  16. package/dist/elicitation-input-DMkeki8d.js +71 -0
  17. package/dist/{event-projector-assistant-message-BwxV4d6N.js → event-projector-assistant-message-C5-Ds8mA.js} +18 -1
  18. package/dist/{event-projector-usage-e5huIQWu.js → event-projector-usage-Bk1I90Bg.js} +18 -18
  19. package/dist/harness-Csz0F-DK.js +258 -0
  20. package/dist/harness.js +2 -226
  21. package/dist/index.js +262 -181
  22. package/dist/{isolated-completion-C58NbL40.js → isolated-completion-Cv6FqygM.js} +4 -4
  23. package/dist/managed-binary-DFYK4DWq.js +248 -0
  24. package/dist/media-understanding-provider.js +2 -2
  25. package/dist/model-catalog-i9rNBthX.js +48 -0
  26. package/dist/{models-BFlpn1Ex.js → models-TS3HBU-q.js} +4 -3
  27. package/dist/{native-subagent-monitor-DyTGmTUx.js → native-subagent-monitor-4Mfq2HDs.js} +354 -83
  28. package/dist/node-exec-server.runtime-BpWqJO1V.js +192 -0
  29. package/dist/{plugin-app-cache-key-C3H2CVp6.js → plugin-app-cache-key-C1CAdfcP.js} +19 -4
  30. package/dist/plugin-approval-roundtrip-bUm777tR.js +95 -0
  31. package/dist/{plugin-marketplace-discovery-CzrGJdCR.js → plugin-marketplace-discovery-B9DvaAG-.js} +59 -54
  32. package/dist/{plugin-metadata-cache-CNJPj4_b.js → plugin-metadata-cache-CTCT3w5L.js} +164 -134
  33. package/dist/{protocol-validators-B4F7L8Rf.js → protocol-validators-VeJxxJ0U.js} +80 -5
  34. package/dist/{rate-limits-DZXmOL8-.js → rate-limits-C5_D8Gmb.js} +1 -1
  35. package/dist/{request-BRl5_UfX.js → request-DXXGHko0.js} +2 -2
  36. package/dist/{run-attempt-P8BdxC1I.js → run-attempt-DYc0QCBF.js} +1276 -765
  37. package/dist/{runtime-artifact-BVSPdd6g.js → runtime-artifact-BvyT1uyd.js} +4 -7
  38. package/dist/{sandbox-guard-Cmwc9eIk.js → sandbox-guard-kuWTn9C5.js} +25 -19
  39. package/dist/session-binding-Bcynfd-_.js +874 -0
  40. package/dist/{session-catalog-xwNi_SDM.js → session-catalog-DaLKVtpH.js} +1534 -1288
  41. package/dist/session-catalog-home-id-BNwAJ9D7.js +18 -0
  42. package/dist/{session-cli-7hgXZDV7.js → session-cli-DMc4oS2w.js} +20 -7
  43. package/dist/session-permission-policy-BrNH1bjy.js +160 -0
  44. package/dist/{session-retirement-DoMMJFKm.js → session-retirement-CcNC3YSY.js} +3 -3
  45. package/dist/{session-upstream-marker-CrIFX06J.js → session-upstream-marker-BIkusb95.js} +1 -1
  46. package/dist/{settled-turn-finalizer-BRWBO4MO.js → settled-turn-finalizer-Dc3ApjU4.js} +24 -20
  47. package/dist/{shared-client-kIBbGjk4.js → shared-client-DKz23hHY.js} +1632 -372
  48. package/dist/{side-question-9HAL26l9.js → side-question-DjA_jsNe.js} +105 -54
  49. package/dist/{thread-lifecycle-Bu1BTDXr.js → thread-lifecycle-L7oEkTlq.js} +1147 -114
  50. package/dist/{thread-ownership-6kOQHlyC.js → thread-ownership-DZeuKH1j.js} +2 -2
  51. package/dist/{thread-resume-CPrJNQVM.js → thread-resume-BE9qNEW0.js} +3 -3
  52. package/dist/{transcript-mirror-B9gGgnJS.js → transcript-mirror-DsCMWBca.js} +137 -38
  53. package/dist/{transport-stdio-DIImwDVS.js → transport-stdio-DhoGy33Z.js} +2 -2
  54. package/dist/{upstream-prompt-provenance-ClRBije0.js → upstream-prompt-provenance-CFmsKwr9.js} +12 -14
  55. package/dist/{upstream-session-fork-CE-_LdnP.js → upstream-session-fork-DlaHxSLC.js} +12 -6
  56. package/dist/{usage-CHlV0e-o.js → usage-ROIaW3wo.js} +3 -3
  57. package/dist/{web-search-provider.runtime-DRw2Vl42.js → web-search-provider.runtime-ClaNPV7N.js} +3 -3
  58. package/openclaw.plugin.json +49 -2
  59. package/package.json +9 -8
  60. package/dist/app-server-policy-zcBDc1JU.js +0 -49
@@ -1,8 +1,9 @@
1
- import { B as claimCodexAppServerLiveThread, K as releaseCodexAppServerLiveThread, ct as isJsonObject, q as retainCodexAppServerLiveThread } from "./shared-client-kIBbGjk4.js";
2
- import { A as shouldSynthesizeToolProgressForItem, B as readNullableString$1, C as isSideEffectingNativeToolItem, D as itemTitle, E as itemStatus, F as readItem, L as readNonEmptyString, M as normalizeOptionalString$1, P as readHookOutputEntries, R as readNonEmptyStringArray, S as isNonSuccessItemStatus, T as itemName, k as shouldRecordNativeToolTranscript, w as itemKind, x as isMutatingNativeToolItem, y as auditNativeToolTerminalStatus } from "./attempt-client-cleanup-DMLXUfa8.js";
3
- import { t as attachCodexMirrorIdentity } from "./upstream-prompt-provenance-ClRBije0.js";
1
+ import { $ as releaseCodexAppServerLiveThread, et as retainCodexAppServerLiveThread, q as claimCodexAppServerLiveThread, vt as isJsonObject } from "./shared-client-DKz23hHY.js";
2
+ import { A as shouldSynthesizeToolProgressForItem, B as readNullableString$1, C as isSideEffectingNativeToolItem, D as itemTitle, E as itemStatus, F as readItem, L as readNonEmptyString, M as normalizeOptionalString$1, P as readHookOutputEntries, R as readNonEmptyStringArray, S as isNonSuccessItemStatus, T as itemName, k as shouldRecordNativeToolTranscript, w as itemKind, x as isMutatingNativeToolItem, y as auditNativeToolTerminalStatus } from "./attempt-client-cleanup-bfsmcQ6m.js";
3
+ import { t as attachCodexMirrorIdentity } from "./upstream-prompt-provenance-CFmsKwr9.js";
4
4
  import { n as sanitizeCodexHistoryImagePayloads } from "./image-payload-sanitizer-CnfoUPCE.js";
5
5
  import { t as resolveCodexLocalRuntimeAttribution } from "./local-runtime-attribution-B_2mnqhb.js";
6
+ import { n as codexApprovalTimeoutText } from "./plugin-approval-roundtrip-bUm777tR.js";
6
7
  import { asFiniteNumber, asNonArrayRecord, normalizeOptionalString, readStringField } from "openclaw/plugin-sdk/string-coerce-runtime";
7
8
  import fs from "node:fs/promises";
8
9
  import path from "node:path";
@@ -196,7 +197,7 @@ function sanitizeCodexToolArguments(value) {
196
197
  }
197
198
  /** Sanitizes a Codex dynamic-tool response before diagnostic/event emission. */
198
199
  function sanitizeCodexToolResponse(response) {
199
- return sanitizeCodexAgentEventRecord(response);
200
+ return sanitizeCodexAgentEventRecord({ ...response });
200
201
  }
201
202
  /** Infers compact human-readable tool metadata from Codex dynamic-tool arguments. */
202
203
  function inferCodexDynamicToolMeta(call, detailMode) {
@@ -204,17 +205,6 @@ function inferCodexDynamicToolMeta(call, detailMode) {
204
205
  }
205
206
  //#endregion
206
207
  //#region extensions/codex/src/app-server/event-projector-tool-items.ts
207
- function nativeToolActionFingerprint(item) {
208
- if (item.type === "commandExecution" && typeof item.command === "string") return JSON.stringify({
209
- type: item.type,
210
- command: item.command,
211
- cwd: typeof item.cwd === "string" ? item.cwd : ""
212
- });
213
- if (item.type === "fileChange") return JSON.stringify({
214
- type: item.type,
215
- changes: itemFileChanges(item)
216
- });
217
- }
218
208
  function isNativePostToolUseRelayItem(item) {
219
209
  switch (item.type) {
220
210
  case "commandExecution":
@@ -434,6 +424,7 @@ var CodexToolProgressProjection = class {
434
424
  this.sideEffectingNativeIds = /* @__PURE__ */ new Set();
435
425
  this.sideEffectingDynamicIds = /* @__PURE__ */ new Set();
436
426
  this.transcriptProgressCallIds = /* @__PURE__ */ new Set();
427
+ this.approvalTimeoutKinds = /* @__PURE__ */ new Map();
437
428
  }
438
429
  get outputTextByItem() {
439
430
  return this.output.textByItem;
@@ -450,6 +441,10 @@ var CodexToolProgressProjection = class {
450
441
  get hasPotentialSideEffects() {
451
442
  return this.sideEffectingNativeIds.size > 0 || this.sideEffectingDynamicIds.size > 0;
452
443
  }
444
+ approvalTimeoutExplanation(itemId, status) {
445
+ const kind = isNonSuccessItemStatus(status) && this.approvalTimeoutKinds.get(itemId);
446
+ return kind ? codexApprovalTimeoutText(kind) : void 0;
447
+ }
453
448
  setLastToolError(error) {
454
449
  if (!error) {
455
450
  this.lastNativeToolError = void 0;
@@ -468,9 +463,7 @@ var CodexToolProgressProjection = class {
468
463
  },
469
464
  nativeMutation: {
470
465
  mutatingAction: error.mutatingAction === true,
471
- replaySafe: error.mutatingAction !== true,
472
- ...error.actionFingerprint ? { actionFingerprint: error.actionFingerprint } : {},
473
- ...error.fileTarget ? { fileTarget: error.fileTarget } : {}
466
+ replaySafe: error.mutatingAction !== true
474
467
  }
475
468
  });
476
469
  this.lastNativeToolError = terminalResolution?.lastToolError ?? (this.lastNativeToolError?.mutatingAction && error.mutatingAction !== true ? this.lastNativeToolError : error);
@@ -537,9 +530,14 @@ var CodexToolProgressProjection = class {
537
530
  recordNativeToolError(params) {
538
531
  const executionStarted = params.status !== "blocked";
539
532
  const mutatingAction = executionStarted && isMutatingNativeToolItem(params.item);
540
- const actionFingerprint = mutatingAction ? nativeToolActionFingerprint(params.item) : void 0;
541
533
  const isFailure = isNonSuccessItemStatus(params.status);
542
- const error = isFailure ? itemToolError(params.item, params.status, this.output.textByItem) : void 0;
534
+ const approvalTimeoutExplanation = this.approvalTimeoutExplanation(params.item.id, params.status);
535
+ const error = isFailure ? approvalTimeoutExplanation ?? itemToolError(params.item, params.status, this.output.textByItem) : void 0;
536
+ const failure = error ? {
537
+ ...approvalTimeoutExplanation ? { errorCode: "approval_timeout" } : {},
538
+ error,
539
+ ...approvalTimeoutExplanation ? { timedOut: true } : {}
540
+ } : {};
543
541
  const terminalResolution = this.params.observeToolTerminal?.({
544
542
  toolCallId: params.item.id,
545
543
  toolName: params.name,
@@ -547,11 +545,10 @@ var CodexToolProgressProjection = class {
547
545
  ...params.meta ? { meta: params.meta } : {},
548
546
  executionStarted,
549
547
  outcome: isFailure ? "failure" : "success",
550
- ...isFailure ? { failure: error ? { error } : {} } : {},
548
+ ...isFailure ? { failure } : {},
551
549
  nativeMutation: {
552
550
  mutatingAction,
553
- replaySafe: !mutatingAction,
554
- ...actionFingerprint ? { actionFingerprint } : {}
551
+ replaySafe: !mutatingAction
555
552
  }
556
553
  });
557
554
  if (terminalResolution) {
@@ -561,9 +558,8 @@ var CodexToolProgressProjection = class {
561
558
  if (isFailure) this.lastNativeToolError = {
562
559
  toolName: params.name,
563
560
  ...params.meta ? { meta: params.meta } : {},
564
- ...error ? { error } : {},
565
- ...mutatingAction ? { mutatingAction: true } : {},
566
- ...actionFingerprint ? { actionFingerprint } : {}
561
+ ...failure,
562
+ ...mutatingAction ? { mutatingAction: true } : {}
567
563
  };
568
564
  else if (this.lastNativeToolError?.mutatingAction !== true) this.lastNativeToolError = void 0;
569
565
  }
@@ -819,6 +815,10 @@ const MISSING_TOOL_RESULT_ERROR = "OpenClaw recorded a native Codex tool.call wi
819
815
  const NATIVE_PATCH_REJECTION_RE = /^\s*patch rejected:\s*writing outside of the project;\s*rejected by user approval settings\s*$/iu;
820
816
  const CODE_MODE_NATIVE_PATCH_SOURCE_RE = /^\s*(?:\/\/[^\r\n]*\r?\n\s*)?(?:const|let)\s+([A-Za-z_$][\w$]*)\s*=\s*await\s+tools\.apply_patch\(\s*("(?:\\[\s\S]|[^"\\])*")\s*\)\s*;?\s*text\(\s*\1\s*\)\s*;?\s*$/u;
821
817
  const CODE_MODE_NATIVE_PATCH_RESULT_RE = /^\s*Script (completed|failed)\s*\r?\nWall time\s+\d+(?:\.\d+)?\s+seconds\s*\r?\nOutput:\s*([\s\S]*?)\s*$/iu;
818
+ const MAX_TOOL_APPROVAL_REVIEWS = 16;
819
+ function toolApprovalReviewOutcome(state) {
820
+ return state.denied ? "denied" : state.unresolvedReviewIds === null || state.unresolvedReviewIds.size > 0 ? "reviewing" : "approved";
821
+ }
822
822
  function readCodeModeNativePatchInput(source) {
823
823
  if (typeof source !== "string") return;
824
824
  const match = CODE_MODE_NATIVE_PATCH_SOURCE_RE.exec(source);
@@ -864,12 +864,37 @@ var CodexToolTranscriptProjection = class {
864
864
  this.afterToolCallObservedItemIds = /* @__PURE__ */ new Set();
865
865
  this.nativeMcpAppResultDetails = /* @__PURE__ */ new Map();
866
866
  this.nativeMcpAppResultDetailsAttempted = /* @__PURE__ */ new Set();
867
+ this.approvalReviewsByCallId = /* @__PURE__ */ new Map();
867
868
  this.rawNativeToolOutputByCallId = /* @__PURE__ */ new Map();
868
869
  this.codeModeNativePatchInputsByCallId = /* @__PURE__ */ new Map();
869
870
  }
870
871
  get transcriptMessages() {
871
872
  return this.messages;
872
873
  }
874
+ recordToolApprovalReview(toolCallId, reviewId, status, review) {
875
+ const state = this.approvalReviewsByCallId.get(toolCallId) ?? {
876
+ reviews: [],
877
+ denied: false,
878
+ unresolvedReviewIds: /* @__PURE__ */ new Set()
879
+ };
880
+ state.reviews = [...state.reviews.filter((candidate) => candidate.id !== reviewId), review].slice(-16);
881
+ state.denied ||= [
882
+ "denied",
883
+ "timed_out",
884
+ "aborted"
885
+ ].includes(status);
886
+ const unresolved = state.unresolvedReviewIds;
887
+ if (status === "in_progress") state.unresolvedReviewIds = unresolved && (unresolved.size < MAX_TOOL_APPROVAL_REVIEWS || unresolved.has(reviewId)) ? unresolved.add(reviewId) : null;
888
+ else unresolved?.delete(reviewId);
889
+ this.approvalReviewsByCallId.set(toolCallId, state);
890
+ return toolApprovalReviewOutcome(state);
891
+ }
892
+ finalizeToolApprovalReviews(toolCallId) {
893
+ const state = this.approvalReviewsByCallId.get(toolCallId);
894
+ if (!state) return;
895
+ state.unresolvedReviewIds = /* @__PURE__ */ new Set();
896
+ return toolApprovalReviewOutcome(state);
897
+ }
873
898
  recordDynamicToolCall(params) {
874
899
  this.recordToolCall({
875
900
  id: params.callId,
@@ -897,16 +922,21 @@ var CodexToolTranscriptProjection = class {
897
922
  });
898
923
  }
899
924
  recordNativeToolResult(item, details) {
900
- if (!item || !shouldRecordNativeToolTranscript(item)) return;
925
+ if (!item || !shouldRecordNativeToolTranscript(item) || this.resultIds.has(item.id)) return;
901
926
  const name = itemName(item);
902
- if (name) this.recordToolResult({
903
- id: item.id,
904
- name,
905
- text: this.rawNativeToolOutputByCallId.get(item.id) ?? itemTranscriptResultText(item, this.progress.outputTextByItem),
906
- isError: isNonSuccessItemStatus(itemStatus(item)),
907
- details,
908
- ...item.type === "webSearch" ? { resultContentSource: "network" } : {}
909
- });
927
+ if (name) {
928
+ const status = itemStatus(item);
929
+ const approvalTimeoutExplanation = this.progress.approvalTimeoutExplanation(item.id, status);
930
+ this.recordToolResult({
931
+ id: item.id,
932
+ name,
933
+ text: approvalTimeoutExplanation ?? this.rawNativeToolOutputByCallId.get(item.id) ?? itemTranscriptResultText(item, this.progress.outputTextByItem),
934
+ isError: isNonSuccessItemStatus(status),
935
+ details,
936
+ ...item.type === "webSearch" ? { resultContentSource: "network" } : {}
937
+ });
938
+ this.progress.approvalTimeoutKinds.delete(item.id);
939
+ }
910
940
  }
911
941
  recordRawNativeToolItem(item) {
912
942
  const type = typeof item.type === "string" ? item.type : void 0;
@@ -985,11 +1015,24 @@ var CodexToolTranscriptProjection = class {
985
1015
  id: callId,
986
1016
  name: "apply_patch",
987
1017
  text,
988
- isError: result.isError === true
1018
+ isError: result.isError
989
1019
  }).content;
990
1020
  }
991
1021
  async recordNativeToolResultWithDetails(item) {
992
- this.recordNativeToolResult(item, await this.prepareNativeMcpAppResultDetails(item));
1022
+ const preparedDetails = await this.prepareNativeMcpAppResultDetails(item);
1023
+ const approvalReviewState = item ? this.approvalReviewsByCallId.get(item.id) : void 0;
1024
+ const reviewDetails = approvalReviewState ? {
1025
+ approvalReviews: approvalReviewState.reviews,
1026
+ approvalReviewOutcome: toolApprovalReviewOutcome(approvalReviewState)
1027
+ } : void 0;
1028
+ const details = reviewDetails ? isJsonObject(preparedDetails) ? {
1029
+ ...preparedDetails,
1030
+ ...reviewDetails
1031
+ } : {
1032
+ ...preparedDetails !== void 0 ? { toolDetails: preparedDetails } : {},
1033
+ ...reviewDetails
1034
+ } : preparedDetails;
1035
+ this.recordNativeToolResult(item, details);
993
1036
  }
994
1037
  async prepareNativeMcpAppResultDetails(item) {
995
1038
  if (!item || item.type !== "mcpToolCall" || itemStatus(item) === "running") return;
@@ -1025,7 +1068,7 @@ var CodexToolTranscriptProjection = class {
1025
1068
  }
1026
1069
  this.trajectoryResultIds.add(params.item.id);
1027
1070
  const toolResult = itemToolResult(params.item).result;
1028
- const output = itemOutputText(params.item, this.progress.outputTextByItem);
1071
+ const output = this.progress.approvalTimeoutExplanation(params.item.id, params.status) ?? itemOutputText(params.item, this.progress.outputTextByItem);
1029
1072
  this.options.trajectoryRecorder?.recordEvent("tool.result", {
1030
1073
  threadId: this.threadId,
1031
1074
  turnId: this.turnId,
@@ -1045,7 +1088,7 @@ var CodexToolTranscriptProjection = class {
1045
1088
  if (!name || status === "running") return;
1046
1089
  this.afterToolCallObservedItemIds.add(item.id);
1047
1090
  const result = itemToolResult(item).result;
1048
- const error = itemToolError(item, status, this.progress.outputTextByItem);
1091
+ const error = this.progress.approvalTimeoutExplanation(item.id, status) ?? itemToolError(item, status, this.progress.outputTextByItem);
1049
1092
  const startedAt = resolveStartedAtFromDurationMs(item.durationMs);
1050
1093
  const hookParams = {
1051
1094
  toolName: name,
@@ -1077,7 +1120,8 @@ var CodexToolTranscriptProjection = class {
1077
1120
  id,
1078
1121
  name
1079
1122
  }),
1080
- isError: true
1123
+ isError: true,
1124
+ details: { reason: "missing_tool_result" }
1081
1125
  });
1082
1126
  }
1083
1127
  for (const id of missingTrajectoryIds) {
@@ -1139,7 +1183,6 @@ var CodexToolTranscriptProjection = class {
1139
1183
  if (!name) return;
1140
1184
  const item = this.trajectoryItemsById.get(firstMissingId);
1141
1185
  const meta = item ? itemMeta(item, this.progress.toolProgressDetailMode()) : this.progress.getToolMeta(firstMissingId)?.meta;
1142
- const actionFingerprint = item ? nativeToolActionFingerprint(item) : void 0;
1143
1186
  this.progress.setLastToolError({
1144
1187
  toolName: name,
1145
1188
  ...meta ? { meta } : {},
@@ -1147,8 +1190,7 @@ var CodexToolTranscriptProjection = class {
1147
1190
  id: firstMissingId,
1148
1191
  name
1149
1192
  }),
1150
- ...item && isMutatingNativeToolItem(item) ? { mutatingAction: true } : {},
1151
- ...actionFingerprint ? { actionFingerprint } : {}
1193
+ ...item && isMutatingNativeToolItem(item) ? { mutatingAction: true } : {}
1152
1194
  });
1153
1195
  }
1154
1196
  shouldEmitAfterToolCallObservation(item) {
@@ -1211,6 +1253,41 @@ function resolveStartedAtFromDurationMs(durationMs) {
1211
1253
  }
1212
1254
  //#endregion
1213
1255
  //#region extensions/codex/src/app-server/event-projector-events.ts
1256
+ /** Downstream event consumers must never corrupt the canonical Codex turn projection. */
1257
+ function emitCodexAgentEvent(params, event) {
1258
+ try {
1259
+ emitAgentEvent({
1260
+ runId: params.runId,
1261
+ stream: event.stream,
1262
+ data: event.data,
1263
+ ...params.sessionKey ? { sessionKey: params.sessionKey } : {}
1264
+ });
1265
+ } catch (error) {
1266
+ embeddedAgentLog.debug("codex app-server global agent event emit failed", { error });
1267
+ }
1268
+ try {
1269
+ const maybePromise = params.onAgentEvent?.(event);
1270
+ Promise.resolve(maybePromise).catch((error) => {
1271
+ embeddedAgentLog.debug("codex app-server agent event handler rejected", { error });
1272
+ });
1273
+ } catch (error) {
1274
+ embeddedAgentLog.debug("codex app-server agent event handler threw", { error });
1275
+ }
1276
+ }
1277
+ function guardianActionCommand(action) {
1278
+ if (!action) return;
1279
+ const directLabel = readStringField(action, "command") ?? readStringField(action, "target") ?? readStringField(action, "toolTitle") ?? readStringField(action, "reason");
1280
+ if (directLabel) return directLabel;
1281
+ const server = readStringField(action, "connectorName") ?? readStringField(action, "server");
1282
+ const tool = readStringField(action, "toolName");
1283
+ if (server && tool) return `${server}/${tool}`;
1284
+ const argv = Array.isArray(action.argv) ? action.argv.filter((value) => typeof value === "string") : [];
1285
+ return argv.length > 0 ? argv.join(" ") : readStringField(action, "program");
1286
+ }
1287
+ function normalizeApprovalReviewStatus(status) {
1288
+ return status === "inProgress" ? "in_progress" : status === "timedOut" ? "timed_out" : status;
1289
+ }
1290
+ const GUARDIAN_TIMEOUT_WARNING = "Automatic approval review timed out while evaluating the requested approval.";
1214
1291
  function projectNormalizedToolItem(params) {
1215
1292
  const { item } = params;
1216
1293
  if (!item || !shouldSynthesizeToolProgressForItem(item)) return;
@@ -1257,32 +1334,146 @@ var CodexEventProjection = class {
1257
1334
  get guardianReviewCount() {
1258
1335
  return this.reviewCount;
1259
1336
  }
1337
+ emitCompactionEnd(itemId, completed) {
1338
+ this.emitAgentEvent({
1339
+ stream: "compaction",
1340
+ data: {
1341
+ phase: "end",
1342
+ backend: "codex-app-server",
1343
+ completed,
1344
+ threadId: this.threadId,
1345
+ turnId: this.turnId,
1346
+ itemId
1347
+ }
1348
+ });
1349
+ }
1260
1350
  handleGuardianReview(method, params) {
1261
1351
  this.reviewCount += 1;
1262
1352
  const review = isJsonObject(params.review) ? params.review : void 0;
1263
1353
  const action = isJsonObject(params.action) ? params.action : void 0;
1354
+ const reviewId = readStringField(params, "reviewId");
1355
+ const targetItemId = readNullableString$1(params, "targetItemId");
1356
+ const command = guardianActionCommand(action);
1357
+ const reviewStatus = review ? readStringField(review, "status") : void 0;
1358
+ const status = normalizeApprovalReviewStatus(reviewStatus);
1359
+ const riskLevel = review ? readStringField(review, "riskLevel") : void 0;
1360
+ const userAuthorization = review ? readStringField(review, "userAuthorization") : void 0;
1361
+ const rationale = review ? readNullableString$1(review, "rationale") : void 0;
1362
+ const expectedWarning = status === "timed_out" ? GUARDIAN_TIMEOUT_WARNING : rationale && riskLevel && userAuthorization && (status === "approved" || status === "denied") ? `Automatic approval review ${status} (risk: ${riskLevel}, authorization: ${userAuthorization}): ${rationale}` : void 0;
1363
+ if (Boolean(targetItemId) && Boolean(reviewId) && this.pendingGuardianWarning === expectedWarning) this.pendingGuardianWarning = void 0;
1364
+ else this.flushPendingGuardianWarning();
1365
+ const threadId = readStringField(params, "threadId") ?? this.threadId;
1366
+ const turnId = readStringField(params, "turnId") ?? this.turnId;
1367
+ if (method.endsWith("/started")) this.activeGuardianReview = {
1368
+ reviewId,
1369
+ targetItemId,
1370
+ command,
1371
+ threadId,
1372
+ turnId
1373
+ };
1264
1374
  this.emitAgentEvent({
1265
1375
  stream: "codex_app_server.guardian",
1266
1376
  data: {
1267
1377
  method,
1268
1378
  phase: method.endsWith("/started") ? "started" : "completed",
1269
- reviewId: readStringField(params, "reviewId"),
1270
- targetItemId: readNullableString$1(params, "targetItemId"),
1379
+ threadId,
1380
+ turnId,
1381
+ reviewId,
1382
+ targetItemId,
1271
1383
  decisionSource: readStringField(params, "decisionSource"),
1272
- status: review ? readStringField(review, "status") : void 0,
1273
- riskLevel: review ? readStringField(review, "riskLevel") : void 0,
1274
- userAuthorization: review ? readStringField(review, "userAuthorization") : void 0,
1275
- rationale: review ? readNullableString$1(review, "rationale") : void 0,
1276
- actionType: action ? readStringField(action, "type") : void 0
1384
+ status: reviewStatus,
1385
+ riskLevel,
1386
+ userAuthorization,
1387
+ rationale,
1388
+ actionType: action ? readStringField(action, "type") : void 0,
1389
+ command
1277
1390
  }
1278
1391
  });
1392
+ if (reviewId && targetItemId && status) {
1393
+ const approvalReview = {
1394
+ id: reviewId,
1395
+ label: "Guardian",
1396
+ status,
1397
+ ...riskLevel ? { riskLevel } : {},
1398
+ ...userAuthorization ? { userAuthorization } : {},
1399
+ ...rationale ? { rationale } : {}
1400
+ };
1401
+ const approvalReviewOutcome = this.toolTranscript.recordToolApprovalReview(targetItemId, reviewId, status, approvalReview);
1402
+ this.emitAgentEvent({
1403
+ stream: "tool",
1404
+ data: {
1405
+ phase: "review",
1406
+ toolCallId: targetItemId,
1407
+ hideFromChannelProgress: true,
1408
+ approvalReviewOutcome,
1409
+ review: approvalReview
1410
+ }
1411
+ });
1412
+ }
1413
+ if (method.endsWith("/completed") && this.activeGuardianReview?.reviewId === reviewId) this.activeGuardianReview = void 0;
1279
1414
  }
1280
1415
  handleGuardianWarning(params) {
1416
+ this.flushPendingGuardianWarning();
1417
+ const message = readStringField(params, "message");
1418
+ if (message) {
1419
+ this.pendingGuardianWarning = message;
1420
+ return;
1421
+ }
1281
1422
  this.emitAgentEvent({
1282
1423
  stream: "codex_app_server.guardian",
1283
1424
  data: {
1284
1425
  phase: "warning",
1285
- message: readStringField(params, "message")
1426
+ message
1427
+ }
1428
+ });
1429
+ }
1430
+ handleWarning(params) {
1431
+ const message = [readStringField(params, "summary") ?? readStringField(params, "message"), readStringField(params, "details")].filter(Boolean).join("\n");
1432
+ if (message) this.emitAgentEvent({
1433
+ stream: "notice",
1434
+ data: {
1435
+ phase: "warning",
1436
+ message
1437
+ }
1438
+ });
1439
+ }
1440
+ handleModelRerouted(params) {
1441
+ const fromModel = readStringField(params, "fromModel");
1442
+ const toModel = readStringField(params, "toModel");
1443
+ const reason = readStringField(params, "reason");
1444
+ if (fromModel && toModel && fromModel !== toModel) this.emitAgentEvent({
1445
+ stream: "fallback",
1446
+ data: {
1447
+ fromModel,
1448
+ toModel,
1449
+ ...reason ? { reason } : {}
1450
+ }
1451
+ });
1452
+ }
1453
+ flushPendingGuardianWarning() {
1454
+ const pending = this.pendingGuardianWarning;
1455
+ if (!pending) return;
1456
+ this.pendingGuardianWarning = void 0;
1457
+ this.emitAgentEvent({
1458
+ stream: "codex_app_server.guardian",
1459
+ data: {
1460
+ phase: "warning",
1461
+ message: pending
1462
+ }
1463
+ });
1464
+ }
1465
+ handleStrictReviewRequired(params) {
1466
+ this.emitAgentEvent({
1467
+ stream: "codex_app_server.guardian",
1468
+ data: {
1469
+ method: "autoApprovalReview/strictReviewRequired",
1470
+ phase: "strict_review_required",
1471
+ threadId: readStringField(params, "threadId") ?? this.activeGuardianReview?.threadId ?? this.threadId,
1472
+ turnId: readStringField(params, "turnId") ?? this.activeGuardianReview?.turnId ?? this.turnId,
1473
+ reviewId: this.activeGuardianReview?.reviewId,
1474
+ targetItemId: this.activeGuardianReview?.targetItemId,
1475
+ command: this.activeGuardianReview?.command,
1476
+ startedAtMs: asFiniteNumber(params.startedAtMs)
1286
1477
  }
1287
1478
  });
1288
1479
  }
@@ -1344,6 +1535,8 @@ var CodexEventProjection = class {
1344
1535
  if (!projection || !params.item) return;
1345
1536
  const { item } = params;
1346
1537
  const { name, status, args, meta, event } = projection;
1538
+ const approvalReviewOutcome = params.phase === "result" ? this.toolTranscript.finalizeToolApprovalReviews(item.id) : void 0;
1539
+ if (event && approvalReviewOutcome) event.data.approvalReviewOutcome = approvalReviewOutcome;
1347
1540
  this.toolTranscript.recordTrajectoryEvent({
1348
1541
  phase: params.phase,
1349
1542
  item,
@@ -1408,8 +1601,23 @@ function extractCodexNativeSubagentCompletionsFromText(text) {
1408
1601
  }
1409
1602
  const codexNativeSubagentNotifications = {
1410
1603
  fromNotification: extractCodexNativeSubagentCompletions,
1411
- fromText: extractCodexNativeSubagentCompletionsFromText
1604
+ fromText: extractCodexNativeSubagentCompletionsFromText,
1605
+ deliveredAgentPaths: readDeliveredNativeCompletionPaths
1412
1606
  };
1607
+ /** Reads native delivery receipts, leaving status and result ownership with the child lifecycle. */
1608
+ function readDeliveredNativeCompletionPaths(notification) {
1609
+ if (notification.method !== "rawResponseItem/completed") return [];
1610
+ const params = isJsonObject(notification.params) ? notification.params : void 0;
1611
+ const item = isJsonObject(params?.item) ? params.item : void 0;
1612
+ if (!item || readStringField(item, "type") !== "agent_message") return extractCodexNativeSubagentCompletions(notification).map((completion) => completion.agentPath);
1613
+ const author = readStringField(item, "author");
1614
+ const recipient = readStringField(item, "recipient");
1615
+ const content = item.content;
1616
+ if (!author || !recipient || !Array.isArray(content) || content.length !== 1) return [];
1617
+ const part = content[0];
1618
+ if (!isJsonObject(part) || readStringField(part, "type") !== "input_text") return [];
1619
+ return readStringField(part, "text")?.startsWith(`Message Type: FINAL_ANSWER\nTask name: ${recipient}\nSender: ${author}\nPayload:\n`) ? [author] : [];
1620
+ }
1413
1621
  function parseCodexNativeSubagentNotificationBody(body) {
1414
1622
  let payload;
1415
1623
  try {
@@ -1957,7 +2165,8 @@ function registerMonitor(params) {
1957
2165
  taskRuntimeScope: params.taskRuntimeScope,
1958
2166
  agentId: params.agentId,
1959
2167
  claimDirectChild: params.claimDirectChild,
1960
- rejectPendingDirectChild: params.rejectPendingDirectChild
2168
+ rejectPendingDirectChild: params.rejectPendingDirectChild,
2169
+ onDirectChildAccepted: params.onDirectChildAccepted
1961
2170
  });
1962
2171
  }
1963
2172
  var Monitor = class {
@@ -2007,7 +2216,11 @@ var Monitor = class {
2007
2216
  this.releaseRetainedClient();
2008
2217
  for (const release of this.parentThreadRetentions.values()) release();
2009
2218
  this.parentThreadRetentions.clear();
2010
- for (const state of this.parentStates.values()) state.owners.clear();
2219
+ for (const state of this.parentStates.values()) {
2220
+ state.owners.clear();
2221
+ state.turnIds.clear();
2222
+ this.deliverDetachedCompletions(state);
2223
+ }
2011
2224
  this.pendingDirectSpawnEvidence.clear();
2012
2225
  for (const [parentThreadId] of this.parentStates) if (![...this.childStates.values()].some((childState) => childState.parentThreadId === parentThreadId)) this.parentStates.delete(parentThreadId);
2013
2226
  }
@@ -2020,7 +2233,9 @@ var Monitor = class {
2020
2233
  if (!state) {
2021
2234
  state = {
2022
2235
  parentThreadId,
2023
- owners: /* @__PURE__ */ new Map()
2236
+ owners: /* @__PURE__ */ new Map(),
2237
+ turnIds: /* @__PURE__ */ new Set(),
2238
+ nativeCompletionReceipts: /* @__PURE__ */ new Set()
2024
2239
  };
2025
2240
  this.parentStates.set(parentThreadId, state);
2026
2241
  }
@@ -2030,7 +2245,8 @@ var Monitor = class {
2030
2245
  const owner = Symbol("codex-native-subagent-owner");
2031
2246
  state.owners.set(owner, {
2032
2247
  claimDirectChild: params.claimDirectChild,
2033
- rejectPendingDirectChild: params.rejectPendingDirectChild
2248
+ rejectPendingDirectChild: params.rejectPendingDirectChild,
2249
+ onDirectChildAccepted: params.onDirectChildAccepted
2034
2250
  });
2035
2251
  this.prepareParentTaskRuntime(state);
2036
2252
  for (const childState of this.childStates.values()) if (childState.parentThreadId === parentThreadId && childState.pendingCompletion) this.deliverPendingCompletion(state, childState);
@@ -2049,6 +2265,7 @@ var Monitor = class {
2049
2265
  const current = registeredState.owners.get(owner);
2050
2266
  if (!current || [...registeredState.owners.values()].some((other) => other !== current && other.turnId === turnId)) return;
2051
2267
  current.turnId = turnId;
2268
+ registeredState.turnIds.add(turnId);
2052
2269
  this.drainPendingDirectSpawnEvidence(registeredState, current, turnId);
2053
2270
  this.clearUnconsumablePendingDirectSpawnEvidence();
2054
2271
  },
@@ -2057,8 +2274,15 @@ var Monitor = class {
2057
2274
  registered = false;
2058
2275
  const current = this.parentStates.get(parentThreadId);
2059
2276
  if (current === registeredState) {
2277
+ const turnId = current.owners.get(owner)?.turnId;
2060
2278
  current.owners.delete(owner);
2279
+ if (turnId) current.turnIds.delete(turnId);
2280
+ if (current.owners.size === 0) {
2281
+ current.turnIds.clear();
2282
+ current.nativeCompletionReceipts = /* @__PURE__ */ new Set();
2283
+ }
2061
2284
  this.clearUnconsumablePendingDirectSpawnEvidence();
2285
+ this.deliverDetachedCompletions(current);
2062
2286
  this.pruneParentIfUnused(current);
2063
2287
  }
2064
2288
  }
@@ -2096,6 +2320,11 @@ var Monitor = class {
2096
2320
  const startedThread = isJsonObject(params?.thread) ? params.thread : void 0;
2097
2321
  const threadId = readStringField(params, "threadId")?.trim() ?? readStringField(startedThread, "id")?.trim();
2098
2322
  const threadStatus = isJsonObject(params?.status) ? normalizeIdentifier(readStringField(params.status, "type")) : void 0;
2323
+ const parent = threadId ? this.parentStates.get(threadId) : void 0;
2324
+ if (parent && parent.owners.size > 0 && notification.method === "turn/started") {
2325
+ const turnId = isJsonObject(params?.turn) ? readStringField(params.turn, "id") : void 0;
2326
+ if (turnId) parent.turnIds.add(turnId);
2327
+ }
2099
2328
  const tracksRecoveryRevision = Boolean(threadId && this.threadStatusRevisions.has(threadId));
2100
2329
  if (RECOVERY_REVISION_NOTIFICATION_METHODS.has(notification.method) && threadId && tracksRecoveryRevision) this.threadStatusRevisions.get(threadId).value += 1;
2101
2330
  if (!state && (!threadId || !this.parentStates.has(threadId) && !this.childStates.has(threadId) && !tracksRecoveryRevision)) return;
@@ -2109,8 +2338,13 @@ var Monitor = class {
2109
2338
  }
2110
2339
  if (state) this.handleClosedChild(notification, state);
2111
2340
  const childState = threadId ? this.childStates.get(threadId) : void 0;
2112
- if (notification.method === "turn/started" && childState) this.resumeChild(childState);
2113
- if (childState && !childState.terminal) this.emitChildTaskActivity(notification, childState.childThreadId);
2341
+ if (notification.method === "turn/started" && childState) {
2342
+ childState.nativeCompletionDelivered = false;
2343
+ for (const key of childState.agentPathKeys) state?.nativeCompletionReceipts.delete(key);
2344
+ this.resumeChild(childState);
2345
+ }
2346
+ if (parent && parent.turnIds.has(readStringField(params, "turnId") ?? "")) this.recordNativeCompletionDelivery(parent, notification);
2347
+ if (childState && !childState.terminal) this.emitChildTaskActivity(notification, childState);
2114
2348
  this.captureChildAssistantMessage(notification);
2115
2349
  await this.handleChildTurnCompletion(notification);
2116
2350
  if (notification.method === "thread/status/changed" && threadId && threadStatus) if (threadStatus !== "systemerror") {
@@ -2129,14 +2363,17 @@ var Monitor = class {
2129
2363
  }
2130
2364
  await this.handleCompletionNotification(notification);
2131
2365
  }
2132
- emitChildTaskActivity(notification, childThreadId) {
2366
+ emitChildTaskActivity(notification, childState) {
2133
2367
  const params = isJsonObject(notification.params) ? notification.params : void 0;
2134
2368
  if (!params) return;
2135
- const runId = codexNativeSubagentRunId(childThreadId);
2369
+ const owner = {
2370
+ runId: codexNativeSubagentRunId(childState.childThreadId),
2371
+ ...childState.agentId ? { agentId: childState.agentId } : {}
2372
+ };
2136
2373
  if (notification.method === "item/agentMessage/delta") {
2137
2374
  const delta = readStringField(params, "delta");
2138
2375
  if (delta) emitAgentEvent({
2139
- runId,
2376
+ ...owner,
2140
2377
  stream: "assistant",
2141
2378
  data: { delta }
2142
2379
  });
@@ -2145,7 +2382,7 @@ var Monitor = class {
2145
2382
  if (notification.method === "item/reasoning/summaryTextDelta") {
2146
2383
  const delta = readStringField(params, "delta");
2147
2384
  if (delta) emitAgentEvent({
2148
- runId,
2385
+ ...owner,
2149
2386
  stream: "thinking",
2150
2387
  data: { delta }
2151
2388
  });
@@ -2154,7 +2391,7 @@ var Monitor = class {
2154
2391
  if (notification.method !== "item/started" && notification.method !== "item/completed") return;
2155
2392
  const item = readItem(params.item);
2156
2393
  if (item?.type === "agentMessage" && notification.method === "item/completed" && item.text) emitAgentEvent({
2157
- runId,
2394
+ ...owner,
2158
2395
  stream: "assistant",
2159
2396
  data: { text: item.text }
2160
2397
  });
@@ -2163,7 +2400,7 @@ var Monitor = class {
2163
2400
  item
2164
2401
  });
2165
2402
  if (projection?.event) emitAgentEvent({
2166
- runId,
2403
+ ...owner,
2167
2404
  ...projection.event
2168
2405
  });
2169
2406
  }
@@ -2287,7 +2524,7 @@ var Monitor = class {
2287
2524
  const childThreadId = thread ? readStringField(thread, "id")?.trim() : void 0;
2288
2525
  const agentPath = readStringField(readThreadSpawnSource(thread), "agent_path")?.trim();
2289
2526
  const state = parentThreadId ? this.parentStates.get(parentThreadId) : void 0;
2290
- if (state && childThreadId && parentThreadId) return this.registerChildThread(parentThreadId, childThreadId, agentPath === void 0 ? {} : { agentPath }) ? state : void 0;
2527
+ if (state && childThreadId && parentThreadId) return this.registerChildThread(state, childThreadId, agentPath === void 0 ? {} : { agentPath }) ? state : void 0;
2291
2528
  return state;
2292
2529
  }
2293
2530
  if (notification.method === "thread/status/changed" || notification.method === "turn/started" || notification.method === "turn/completed" || notification.method === "item/agentMessage/delta") {
@@ -2319,7 +2556,7 @@ var Monitor = class {
2319
2556
  for (const childThreadId of childThreadIds) accepted = Boolean(isCompletedSpawnAgentTool ? this.registerDirectSpawnChild(state, turnId, {
2320
2557
  parentThreadId,
2321
2558
  childThreadId
2322
- }, owner) : this.registerChildThread(parentThreadId, childThreadId)) && accepted;
2559
+ }, owner) : this.registerChildThread(state, childThreadId)) && accepted;
2323
2560
  if (!accepted) return;
2324
2561
  }
2325
2562
  return state;
@@ -2418,6 +2655,7 @@ var Monitor = class {
2418
2655
  this.unregisterChild(childState);
2419
2656
  return false;
2420
2657
  }
2658
+ if (recovery.agentPath) this.registerAgentPath(childState, recovery.agentPath);
2421
2659
  if (recovery.threadState === "active") {
2422
2660
  this.observeActiveChild(childState);
2423
2661
  return false;
@@ -2483,6 +2721,7 @@ var Monitor = class {
2483
2721
  }
2484
2722
  return {
2485
2723
  parentThreadId: readThreadParentThreadId(thread),
2724
+ agentPath: normalizeOptionalString(readStringField(readThreadSpawnSource(thread), "agent_path")),
2486
2725
  completion,
2487
2726
  fallbackCompletion,
2488
2727
  resumable,
@@ -2514,6 +2753,10 @@ var Monitor = class {
2514
2753
  this.unregisterChild(childState);
2515
2754
  return;
2516
2755
  }
2756
+ if (childState.nativeCompletionDelivered) {
2757
+ this.finishCompletionDelivery(state, childState);
2758
+ return;
2759
+ }
2517
2760
  childState.pendingCompletion = completion;
2518
2761
  state.taskRuntime?.setDetachedTaskDeliveryStatusByRunId({
2519
2762
  runId: codexNativeSubagentRunId(completion.childThreadId),
@@ -2525,6 +2768,7 @@ var Monitor = class {
2525
2768
  async deliverPendingCompletion(state, childState) {
2526
2769
  const completion = childState.pendingCompletion;
2527
2770
  if (!completion || !state.requesterSessionKey || !state.taskRuntimeScope) return;
2771
+ if (state.owners.size > 0) return;
2528
2772
  if (childState.deliveringCompletion || childState.completionDeliveryTimer) return;
2529
2773
  childState.deliveringCompletion = true;
2530
2774
  try {
@@ -2542,13 +2786,7 @@ var Monitor = class {
2542
2786
  });
2543
2787
  if (this.childStates.get(childState.childThreadId) !== childState || this.parentStates.get(state.parentThreadId) !== state) return;
2544
2788
  if (isDurableAgentHarnessCompletionDelivery(delivery)) {
2545
- childState.pendingCompletion = void 0;
2546
- childState.completionDeliveryAttempt = 0;
2547
- state.taskRuntime?.setDetachedTaskDeliveryStatusByRunId({
2548
- runId: codexNativeSubagentRunId(completion.childThreadId),
2549
- deliveryStatus: "delivered"
2550
- });
2551
- this.unregisterChild(childState);
2789
+ this.finishCompletionDelivery(state, childState);
2552
2790
  return;
2553
2791
  }
2554
2792
  const error = delivery.error ?? "completion delivery did not produce a parent response";
@@ -2576,6 +2814,29 @@ var Monitor = class {
2576
2814
  childState.deliveringCompletion = false;
2577
2815
  }
2578
2816
  }
2817
+ recordNativeCompletionDelivery(state, notification) {
2818
+ for (const agentPath of codexNativeSubagentNotifications.deliveredAgentPaths(notification)) {
2819
+ const key = buildParentAgentPathKey(state.parentThreadId, agentPath);
2820
+ state.nativeCompletionReceipts.add(key);
2821
+ const childThreadId = this.childThreadIdsByAgentPath.get(key);
2822
+ const child = childThreadId ? this.childStates.get(childThreadId) : void 0;
2823
+ if (!child || child.parentThreadId !== state.parentThreadId) continue;
2824
+ child.nativeCompletionDelivered = true;
2825
+ if (child.pendingCompletion && !child.deliveringCompletion) this.finishCompletionDelivery(state, child);
2826
+ }
2827
+ }
2828
+ finishCompletionDelivery(state, child) {
2829
+ child.pendingCompletion = void 0;
2830
+ child.completionDeliveryAttempt = 0;
2831
+ state.taskRuntime?.setDetachedTaskDeliveryStatusByRunId({
2832
+ runId: codexNativeSubagentRunId(child.childThreadId),
2833
+ deliveryStatus: "delivered"
2834
+ });
2835
+ this.unregisterChild(child);
2836
+ }
2837
+ deliverDetachedCompletions(state) {
2838
+ for (const child of this.childStates.values()) if (child.parentThreadId === state.parentThreadId && child.pendingCompletion) this.deliverPendingCompletion(state, child);
2839
+ }
2579
2840
  scheduleCompletionDeliveryRetry(childState, error) {
2580
2841
  if (!childState.pendingCompletion || childState.completionDeliveryTimer || this.childStates.get(childState.childThreadId) !== childState) return;
2581
2842
  if (childState.completionDeliveryAttempt >= this.completionDeliveryMaxRetries) {
@@ -2596,8 +2857,8 @@ var Monitor = class {
2596
2857
  }, delayMs);
2597
2858
  unrefTimer(childState.completionDeliveryTimer);
2598
2859
  }
2599
- registerChildThread(parentThreadIdInput, childThreadIdInput, options = {}) {
2600
- const parentThreadId = parentThreadIdInput.trim();
2860
+ registerChildThread(state, childThreadIdInput, options = {}) {
2861
+ const parentThreadId = state.parentThreadId;
2601
2862
  const childThreadId = childThreadIdInput.trim();
2602
2863
  if (!parentThreadId || !childThreadId || this.disposed) return;
2603
2864
  if (options.claimDirectChild && this.threadStatusRevisions.get(childThreadId)?.terminal) return;
@@ -2620,10 +2881,12 @@ var Monitor = class {
2620
2881
  childState = {
2621
2882
  childThreadId,
2622
2883
  parentThreadId,
2884
+ agentId: state.agentId,
2623
2885
  agentPathKeys: /* @__PURE__ */ new Set(),
2624
2886
  assistantMessagesByTurn: /* @__PURE__ */ new Map(),
2625
2887
  recoveryAttempt: 0,
2626
2888
  terminal: false,
2889
+ nativeCompletionDelivered: false,
2627
2890
  settledWithoutCompletion: false,
2628
2891
  completionDeliveryAttempt: 0,
2629
2892
  deliveringCompletion: false
@@ -2637,7 +2900,7 @@ var Monitor = class {
2637
2900
  }
2638
2901
  if (options.claimDirectChild && !childState.terminal && !childState.settledWithoutCompletion && !childState.releaseDirectChild) childState.releaseDirectChild = options.claimDirectChild(childThreadId);
2639
2902
  this.registerAgentPath(childState, childThreadId);
2640
- this.parentStates.get(parentThreadId)?.mirror?.markAuthoritativeCompletionExpected(childThreadId);
2903
+ state.mirror?.markAuthoritativeCompletionExpected(childThreadId);
2641
2904
  const agentPath = normalizeOptionalString(options.agentPath);
2642
2905
  if (agentPath) this.registerAgentPath(childState, agentPath);
2643
2906
  this.scheduleRecoveryPoll(childState);
@@ -2650,11 +2913,12 @@ var Monitor = class {
2650
2913
  return owners.length === 1 ? owners[0] : void 0;
2651
2914
  }
2652
2915
  registerDirectSpawnChild(state, turnIdInput, evidence, owner) {
2653
- const childState = this.registerChildThread(state.parentThreadId, evidence.childThreadId, {
2916
+ const childState = this.registerChildThread(state, evidence.childThreadId, {
2654
2917
  ...evidence.agentPath === void 0 ? {} : { agentPath: evidence.agentPath },
2655
2918
  ...owner?.claimDirectChild ? { claimDirectChild: owner.claimDirectChild } : {}
2656
2919
  });
2657
2920
  if (!owner) this.bufferPendingDirectSpawnEvidence(turnIdInput, evidence);
2921
+ else if (childState) owner.onDirectChildAccepted?.();
2658
2922
  return childState;
2659
2923
  }
2660
2924
  bufferPendingDirectSpawnEvidence(turnIdInput, evidence) {
@@ -2669,10 +2933,12 @@ var Monitor = class {
2669
2933
  const pending = this.pendingDirectSpawnEvidence.get(turnId);
2670
2934
  this.pendingDirectSpawnEvidence.delete(turnId);
2671
2935
  if (!pending || !owner.claimDirectChild) return;
2672
- for (const evidence of pending) if (evidence.parentThreadId === state.parentThreadId) this.registerChildThread(state.parentThreadId, evidence.childThreadId, {
2673
- ...evidence.agentPath === void 0 ? {} : { agentPath: evidence.agentPath },
2674
- claimDirectChild: owner.claimDirectChild
2675
- });
2936
+ for (const evidence of pending) if (evidence.parentThreadId === state.parentThreadId) {
2937
+ if (this.registerChildThread(state, evidence.childThreadId, {
2938
+ ...evidence.agentPath === void 0 ? {} : { agentPath: evidence.agentPath },
2939
+ claimDirectChild: owner.claimDirectChild
2940
+ })) owner.onDirectChildAccepted?.();
2941
+ }
2676
2942
  }
2677
2943
  hasUnboundParentOwner(parentThreadId) {
2678
2944
  return [...parentThreadId ? [this.parentStates.get(parentThreadId)].filter((state) => Boolean(state)) : this.parentStates.values()].some((state) => [...state.owners.values()].some((owner) => owner.turnId === void 0));
@@ -2707,6 +2973,7 @@ var Monitor = class {
2707
2973
  }
2708
2974
  this.childThreadIdsByAgentPath.set(key, childState.childThreadId);
2709
2975
  childState.agentPathKeys.add(key);
2976
+ if (this.parentStates.get(childState.parentThreadId)?.nativeCompletionReceipts.has(key)) childState.nativeCompletionDelivered = true;
2710
2977
  }
2711
2978
  unregisterChild(childState, options = {}) {
2712
2979
  this.releaseDirectChild(childState);
@@ -2856,6 +3123,7 @@ var Monitor = class {
2856
3123
  const childThreadId = task.runId.slice(13).trim();
2857
3124
  candidates.set(childThreadId, {
2858
3125
  parentState: state,
3126
+ nativeCompletionReceipts: state.nativeCompletionReceipts,
2859
3127
  requesterSessionKey: state.requesterSessionKey,
2860
3128
  childThreadId,
2861
3129
  recoveryAttempt: 0,
@@ -2932,6 +3200,8 @@ var Monitor = class {
2932
3200
  state = {
2933
3201
  parentThreadId,
2934
3202
  owners: /* @__PURE__ */ new Map(),
3203
+ turnIds: /* @__PURE__ */ new Set(),
3204
+ nativeCompletionReceipts: /* @__PURE__ */ new Set(),
2935
3205
  requesterSessionKey: candidate.requesterSessionKey,
2936
3206
  taskRuntimeScope: candidate.taskRuntimeScope,
2937
3207
  agentId: candidate.agentId,
@@ -2940,11 +3210,12 @@ var Monitor = class {
2940
3210
  this.prepareParentTaskRuntime(state);
2941
3211
  this.parentStates.set(parentThreadId, state);
2942
3212
  }
2943
- const childState = this.registerChildThread(parentThreadId, candidate.childThreadId);
3213
+ const childState = this.registerChildThread(state, candidate.childThreadId, recovery.agentPath ? { agentPath: recovery.agentPath } : {});
2944
3214
  if (!childState) {
2945
3215
  this.pruneParentIfUnused(state);
2946
3216
  return;
2947
3217
  }
3218
+ if ([...childState.agentPathKeys].some((key) => candidate.nativeCompletionReceipts.has(key))) childState.nativeCompletionDelivered = true;
2948
3219
  if (recovery.threadState === "active") this.observeActiveChild(childState);
2949
3220
  if (recovery.threadState === "other") this.clearSystemErrorFallback(childState);
2950
3221
  if (recovery.resumable) {
@@ -3108,4 +3379,4 @@ function unrefTimer(timer) {
3108
3379
  if (typeof timer === "object" && timer && "unref" in timer) timer.unref();
3109
3380
  }
3110
3381
  //#endregion
3111
- export { CodexToolProgressProjection as a, isCodexCommandBearingToolCall as c, sanitizeCodexToolResponse as d, readCodexMirroredSessionHistoryMessages as i, resolveCodexToolProgressDetailMode as l, CodexEventProjection as n, shouldEmitTranscriptToolProgress as o, CodexToolTranscriptProjection as r, inferCodexDynamicToolMeta as s, codexNativeSubagentMonitorRuntime as t, sanitizeCodexToolArguments as u };
3382
+ export { readCodexMirroredSessionHistoryMessages as a, inferCodexDynamicToolMeta as c, sanitizeCodexToolArguments as d, sanitizeCodexToolResponse as f, CodexToolTranscriptProjection as i, isCodexCommandBearingToolCall as l, CodexEventProjection as n, CodexToolProgressProjection as o, emitCodexAgentEvent as r, shouldEmitTranscriptToolProgress as s, codexNativeSubagentMonitorRuntime as t, resolveCodexToolProgressDetailMode as u };