@openclaw/codex 2026.9.4 → 2026.9.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/assets/activity.svg +30 -0
  2. package/assets/icon.png +0 -0
  3. package/dist/.setup/account-usage-runtime-C2MOIvfq.mjs +75 -0
  4. package/dist/{apply-CvT8tW5i.js → .setup/apply-CJ0ZfmBG.mjs} +11 -11
  5. package/dist/.setup/async-questions-DdhOCwGi.mjs +27 -0
  6. package/dist/{attempt-client-cleanup-DKHzbwt5.js → .setup/attempt-client-cleanup-BpYKdTA0.mjs} +29 -14
  7. package/dist/{attempt-context-D44yeDII.js → .setup/attempt-context-VXVwTCfS.mjs} +5 -5
  8. package/dist/.setup/attempt-terminal-gZrxQ35N.mjs +5 -0
  9. package/dist/{auth-binding-CWlKVccJ.js → .setup/auth-binding-DhLWa_7K.mjs} +1 -1
  10. package/dist/{auth-cache-key-7orQae_j.js → .setup/auth-cache-key-QirmgiCo.mjs} +3 -3
  11. package/dist/{auth-profile-CwzO4_RG.js → .setup/auth-profile-WqZtZfXN.mjs} +1 -1
  12. package/dist/.setup/binding-connection-Bm38niE8.mjs +50 -0
  13. package/dist/.setup/binding-connection.runtime-CnRMC0ta.mjs +48 -0
  14. package/dist/{bounded-turn-C_Hneydj.js → .setup/bounded-turn-BtlZcivC.mjs} +16 -11
  15. package/dist/{build-state-BCmg9-5p.js → .setup/build-state-Xx9ybZqa.mjs} +1 -1
  16. package/dist/{capabilities-8vx68WLH.js → .setup/capabilities-_vXcZGSx.mjs} +1 -1
  17. package/dist/{client-B57KWPQx.js → .setup/client-vXs2929Q.mjs} +332 -163
  18. package/dist/{command-dispatch-BpduNGVf.js → .setup/command-dispatch-naHIZwwF.mjs} +3 -3
  19. package/dist/{command-formatters-lxlkNZgU.js → .setup/command-formatters-CGEkdawF.mjs} +2 -2
  20. package/dist/{command-handlers-tiL9iWj7.js → .setup/command-handlers-BtAJEW1X.mjs} +59 -42
  21. package/dist/{command-rpc-CR5EOEZX.js → .setup/command-rpc-DHFpn4le.mjs} +22 -13
  22. package/dist/{compact-B_H3AOd7.js → .setup/compact-C3i3qlzj.mjs} +28 -43
  23. package/dist/{config-oIORaQ5T.js → .setup/config-CedDWjM-.mjs} +5 -4
  24. package/dist/{config-options-CXMq1T-C.js → .setup/config-options-BsanJ8QG.mjs} +6 -418
  25. package/dist/{protocol-5bh1G-H7.js → .setup/config-parsing-CcB9iPoq.mjs} +9 -51
  26. package/dist/{config-runtime-D0zGNIHu.js → .setup/config-runtime-CeAhl_h4.mjs} +2 -2
  27. package/dist/.setup/config-security-BRQ2mgW9.mjs +465 -0
  28. package/dist/{conversation-binding-DsB4-O7U.js → .setup/conversation-binding-DhzrpTM6.mjs} +23 -21
  29. package/dist/{conversation-binding-data-BiodpIzq.js → .setup/conversation-binding-data-CrcyZk6O.mjs} +1 -1
  30. package/dist/{conversation-control-CtUu1b3m.js → .setup/conversation-control-DN53ns41.mjs} +17 -13
  31. package/dist/.setup/cyber-failover-DYwbmf1o.mjs +123 -0
  32. package/dist/.setup/cyber-failover-notice-e9G3J9-e.mjs +17 -0
  33. package/dist/{dynamic-tools-CmN5RAip.js → .setup/dynamic-tools-D16lOp67.mjs} +101 -55
  34. package/dist/{effective-mcp-catalog-Bd73bqA8.js → .setup/effective-mcp-catalog-K6kLCN8X.mjs} +3 -3
  35. package/dist/{ephemeral-turn-D78_VmzO.js → .setup/ephemeral-turn-R1gA8Sn6.mjs} +4 -5
  36. package/dist/{event-projector-assistant-message-BmBM4qBV.js → .setup/event-projector-assistant-message-DNUR1s0A.mjs} +6 -3
  37. package/dist/{event-projector-items-5VhsECCO.js → .setup/event-projector-items-DyTQ_XqL.mjs} +1 -1
  38. package/dist/{attempt-notifications-C9XufG6l.js → .setup/event-projector-usage-C7Ntzs-f.mjs} +102 -9
  39. package/dist/{harness-C7rRa7bm.js → .setup/harness-rxaaoN-o.mjs} +74 -20
  40. package/dist/{inference-context-Dr_mzvk4.js → .setup/inference-context-fulhZuz8.mjs} +1 -1
  41. package/dist/{inference-proxy-HGXKUIre.js → .setup/inference-proxy-CC15HuSi.mjs} +4 -4
  42. package/dist/{isolated-completion-DWVb5U2J.js → .setup/isolated-completion-B6srt48J.mjs} +7 -7
  43. package/dist/{launch-args-RXQwn8zV.js → .setup/launch-args-DnMak49W.mjs} +22 -1
  44. package/dist/{managed-binary-D22rNEcR.js → .setup/managed-binary-DP6Rib3P.mjs} +2 -2
  45. package/dist/{managed-thread-store-D1t5jh3G.js → .setup/managed-thread-store-BMqgThVL.mjs} +48 -14
  46. package/dist/{model-catalog-Dq2n8f_p.js → .setup/model-catalog-DkvUuBey.mjs} +35 -10
  47. package/dist/{models-PCKOim-h.js → .setup/models-BDFgm_G-.mjs} +3 -3
  48. package/dist/.setup/native-auth-BLZGqFjw.mjs +57 -0
  49. package/dist/{native-subagent-history-DjtPloaU.js → .setup/native-subagent-history-YXaL6dMd.mjs} +24 -29
  50. package/dist/.setup/native-subagent-monitor-B1hxzIOy.mjs +5031 -0
  51. package/dist/{native-subagent-task-ids-BzTdT0Uw.js → .setup/native-subagent-task-ids-DsuOonKv.mjs} +32 -8
  52. package/dist/{node-cli-sessions-DKaOmVUh.js → .setup/node-cli-sessions-Cl8b2ZF3.mjs} +1 -1
  53. package/dist/{node-exec-server.runtime-Cl2vapEi.js → .setup/node-exec-server.runtime-BaViBKNz.mjs} +3 -3
  54. package/dist/{plan-7uG-Fp36.js → .setup/plan-xD7WKYTM.mjs} +64 -48
  55. package/dist/{plugin-activation-BYQculil.js → .setup/plugin-activation-r8nq5Jzp.mjs} +3 -3
  56. package/dist/{plugin-app-cache-key-d0eKxy7b.js → .setup/plugin-app-cache-key-BOxKP7db.mjs} +29 -25
  57. package/dist/{plugin-approval-roundtrip-Bz3FT8W5.js → .setup/plugin-approval-roundtrip-CjfzafAZ.mjs} +1 -1
  58. package/dist/{plugin-inventory-oL4Na1ZG.js → .setup/plugin-inventory-DUle8DLz.mjs} +7 -6
  59. package/dist/{plugin-metadata-cache-ClPJpRio.js → .setup/plugin-metadata-cache-DsS5buNa.mjs} +29 -14
  60. package/dist/{provider-capabilities-BvCUL69A.js → .setup/provider-capabilities-B8J4Dy-O.mjs} +2 -2
  61. package/dist/{provider-MQ8PVkuE.js → .setup/provider-fFh_-VR3.mjs} +4 -4
  62. package/dist/{rate-limits-CBMmWBr9.js → .setup/rate-limits-DOEGYRNs.mjs} +90 -46
  63. package/dist/{request-B7hEkBGq.js → .setup/request-BioXJLYa.mjs} +113 -33
  64. package/dist/.setup/run-attempt-lifecycle-B7JbY4-F.mjs +71 -0
  65. package/dist/{run-attempt-CvsAAGa0.js → .setup/run-attempt-rlA07pUv.mjs} +580 -498
  66. package/dist/{runtime-artifact-BJ0rXBZ_.js → .setup/runtime-artifact-Dy38Z5iU.mjs} +2 -2
  67. package/dist/{sandbox-guard-BxgyoM8M.js → .setup/sandbox-guard-BBP-RbTf.mjs} +3 -3
  68. package/dist/{session-binding-CI8UuilT.js → .setup/session-binding-_0W_fHRr.mjs} +46 -64
  69. package/dist/{session-binding-record-Bcvslnhf.js → .setup/session-binding-record-TH3xA0zj.mjs} +181 -3
  70. package/dist/.setup/session-binding-sidecars-CKYEcfNn.mjs +543 -0
  71. package/dist/{session-catalog-adoption-tcZi1IfX.js → .setup/session-catalog-adoption-CR_whkEW.mjs} +6 -6
  72. package/dist/{session-catalog-archive-CwKg8Xz2.js → .setup/session-catalog-archive-CwZaPacf.mjs} +6 -6
  73. package/dist/.setup/session-catalog-events-jMcYfQyd.mjs +250 -0
  74. package/dist/.setup/session-catalog-fUdWDx-U.mjs +2464 -0
  75. package/dist/.setup/session-catalog-index-B141u15s.mjs +1070 -0
  76. package/dist/.setup/session-catalog-index-order-Cc5BzlQr.mjs +48 -0
  77. package/dist/.setup/session-catalog-index-state-BAuDztHN.mjs +180 -0
  78. package/dist/{thread-history-page-D0JIp48V.js → .setup/session-catalog-native-projection-ChV3cCtm.mjs} +206 -95
  79. package/dist/{session-catalog-node-adoption-B1tgDW-m.js → .setup/session-catalog-node-adoption-BVRsYOSh.mjs} +3 -3
  80. package/dist/{session-catalog-node-continue-Ci-DXyJP.js → .setup/session-catalog-node-continue-Dowv8osw.mjs} +7 -7
  81. package/dist/.setup/session-catalog-projection-C1Bj9Jl-.mjs +414 -0
  82. package/dist/{session-cli-DNN_jhGc.js → .setup/session-cli-DIj-IE-E.mjs} +4 -4
  83. package/dist/{session-history-Cz-tOOYj.js → .setup/session-history-C--SrLI8.mjs} +10 -5
  84. package/dist/{session-history-import-DwyijFI6.js → .setup/session-history-import-JHXT5Xfi.mjs} +4 -4
  85. package/dist/{session-history-read-cxPUxyVV.js → .setup/session-history-read-B3ZfSUbF.mjs} +2 -2
  86. package/dist/{session-history.worker-BeK1YOyT.js → .setup/session-history.worker-CpNj7H_P.mjs} +5 -6
  87. package/dist/{session-initialization-Ct0_Hzmg.js → .setup/session-initialization-DH1z6fXn.mjs} +2 -2
  88. package/dist/{session-permission-policy-BBmXA8Eg.js → .setup/session-permission-policy-DhurXY0l.mjs} +2 -2
  89. package/dist/{session-retirement-B2YfbAAT.js → .setup/session-retirement-CU87AOg9.mjs} +6 -6
  90. package/dist/{settled-turn-context-Du6gdUDd.js → .setup/settled-turn-context-fmwouT5I.mjs} +2 -2
  91. package/dist/{settled-turn-finalizer-Dn91stmc.js → .setup/settled-turn-finalizer-CiY2bLFK.mjs} +9 -9
  92. package/dist/{shared-client-CscigXXL.js → .setup/shared-client-BpTtuLQ5.mjs} +286 -145
  93. package/dist/{side-question-BGMJQf4U.js → .setup/side-question-DSCZyoBD.mjs} +64 -47
  94. package/dist/{source-CElXU0Oy.js → .setup/source-Bjp4UQij.mjs} +7 -6
  95. package/dist/{thread-archive-guard-DfpBr-Sz.js → .setup/thread-archive-guard-jmecf6OJ.mjs} +1 -1
  96. package/dist/.setup/thread-history-page-BTx-4xsg.mjs +83 -0
  97. package/dist/{thread-lifecycle-DXl1-I6b.js → .setup/thread-lifecycle-Cik28qWn.mjs} +256 -128
  98. package/dist/{thread-ownership-BsDRTsyp.js → .setup/thread-ownership-skomxnIt.mjs} +4 -4
  99. package/dist/{thread-policy-BuEQfE0g.js → .setup/thread-policy-Cjs4B8xf.mjs} +2 -2
  100. package/dist/{thread-resume-DsDOZpFg.js → .setup/thread-resume-BkNpj9Pz.mjs} +8 -5
  101. package/dist/.setup/timeout-DZF05XrR.mjs +63 -0
  102. package/dist/{transcript-history-projection-v17wXgdK.js → .setup/transcript-history-projection-DHNBDhCU.mjs} +8 -3
  103. package/dist/{transcript-mirror-C5CKgNy6.js → .setup/transcript-mirror-D4qp_leP.mjs} +15 -6
  104. package/dist/{transcript-mirror-attestation-DibE0krH.js → .setup/transcript-mirror-attestation-CzM-94NC.mjs} +4 -1
  105. package/dist/{transport-stdio-BGjHoYLr.js → .setup/transport-stdio-Cmx94Oiy.mjs} +149 -44
  106. package/dist/{upstream-session-fork-BZerMte_.js → .setup/upstream-session-fork-D3UKxgVD.mjs} +27 -26
  107. package/dist/{usage-tCk-mg_x.js → .setup/usage-BOgBEKso.mjs} +4 -4
  108. package/dist/.setup/usage-limit-error-C0ow7DOc.mjs +166 -0
  109. package/dist/{version-omm6IPI3.js → .setup/version-CoqzXPgK.mjs} +1 -1
  110. package/dist/{web-search-provider.runtime-B7bGbGWq.js → .setup/web-search-provider.runtime-CTGuJt6i.mjs} +3 -3
  111. package/dist/api.js +6 -6
  112. package/dist/cli-metadata.js +1 -1
  113. package/dist/doctor-contract-api.js +8 -528
  114. package/dist/harness.js +1 -1
  115. package/dist/index.js +123 -83
  116. package/dist/media-understanding-provider.js +3 -3
  117. package/dist/migration-provider-api.js +1 -1
  118. package/dist/native-tool-policy.js +12 -0
  119. package/dist/provider-discovery.js +18 -0
  120. package/dist/session-history-worker-runtime.js +23 -5
  121. package/dist/session-history.worker.js +2 -2
  122. package/dist/web-search-contract-api.js +1 -1
  123. package/openclaw.plugin.json +354 -69
  124. package/package.json +11 -8
  125. package/dist/binding-connection-D3udKbIE.js +0 -60
  126. package/dist/event-projector-usage-BfXmpOec.js +0 -102
  127. package/dist/native-subagent-history-owner-Pcp7JuVF.js +0 -34
  128. package/dist/native-subagent-monitor-fQ7eIXEf.js +0 -2978
  129. package/dist/rpc-error-ttN_QjEm.js +0 -30
  130. package/dist/session-catalog-ct-AH01I.js +0 -1477
  131. package/dist/session-catalog-home-id-CwhLdC03.js +0 -18
  132. package/dist/session-catalog-provenance-D-dIfRAH.js +0 -96
  133. package/dist/timeout-BVw8aaM1.js +0 -33
  134. package/dist/{auth-profile-selection-DFu9e167.js → .setup/auth-profile-selection-DFu9e167.mjs} +0 -0
  135. package/dist/{config-utils-DujwEnhg.js → .setup/config-utils-DujwEnhg.mjs} +0 -0
  136. package/dist/{context-compaction-activity-CMla5FPJ.js → .setup/context-compaction-activity-CMla5FPJ.mjs} +0 -0
  137. package/dist/{elicitation-input-DPoK8F7w.js → .setup/elicitation-input-DPoK8F7w.mjs} +0 -0
  138. package/dist/{history-rejection-B4nOXNXF.js → .setup/history-rejection-B4nOXNXF.mjs} +0 -0
  139. package/dist/{image-payload-sanitizer-tupAr-2o.js → .setup/image-payload-sanitizer-tupAr-2o.mjs} +0 -0
  140. package/dist/{incognito-session-uhrBF6wJ.js → .setup/incognito-session-uhrBF6wJ.mjs} +0 -0
  141. package/dist/{local-runtime-attribution-B_2mnqhb.js → .setup/local-runtime-attribution-B_2mnqhb.mjs} +0 -0
  142. package/dist/{native-execution-policy-umd0tgh4.js → .setup/native-execution-policy-YBMHSzC4.mjs} +1 -1
  143. /package/dist/{plugin-marketplace-discovery-P-Vndfqq.js → .setup/plugin-marketplace-discovery-P-Vndfqq.mjs} +0 -0
  144. /package/dist/{rolldown-runtime-8H4AJuhK.js → .setup/rolldown-runtime-8H4AJuhK.mjs} +0 -0
  145. /package/dist/{session-binding-meta-B7aEMU7g.js → .setup/session-binding-meta-B7aEMU7g.mjs} +0 -0
  146. /package/dist/{session-upstream-marker-D15C9NHp.js → .setup/session-upstream-marker-D15C9NHp.mjs} +0 -0
  147. /package/dist/{upstream-prompt-provenance-LphB8slG.js → .setup/upstream-prompt-provenance-LphB8slG.mjs} +0 -0
  148. /package/dist/{web-search-provider.shared-BrZmlqyR.js → .setup/web-search-provider.shared-BrZmlqyR.mjs} +0 -0
@@ -1,2978 +0,0 @@
1
- import { o as isJsonObject } from "./protocol-5bh1G-H7.js";
2
- import { E as readNullableString$1, a as isNonSuccessItemStatus, b as readHookOutputEntries, c as itemName, d as matchesCodexSnapshotTurn, i as isMutatingNativeToolItem, l as itemStatus, m as shouldSynthesizeToolProgressForItem, n as auditNativeToolTerminalStatus, o as isSideEffectingNativeToolItem, p as shouldRecordNativeToolTranscript, s as itemKind, u as itemTitle, x as readItem } from "./event-projector-items-5VhsECCO.js";
3
- import { t as attachCodexMirrorIdentity } from "./upstream-prompt-provenance-LphB8slG.js";
4
- import { t as readCodexMirroredSessionHistoryMessages } from "./session-history-Cz-tOOYj.js";
5
- import { J as retainCodexAppServerLiveThread, L as claimCodexAppServerLiveThread, q as releaseCodexAppServerLiveThread } from "./shared-client-CscigXXL.js";
6
- import { t as resolveCodexLocalRuntimeAttribution } from "./local-runtime-attribution-B_2mnqhb.js";
7
- import { C as formatToolSummary, E as truncateToolTranscriptText, S as formatToolOutput, T as toolOutputRawEchoSignature, a as isNativePostToolUseRelayItem, b as ToolOutputAccumulator, c as itemToolArgs, d as itemTranscriptResultText, f as shouldSuppressChannelProgressForItem, g as sanitizeCodexToolArguments, h as resolveCodexToolProgressDetailMode, i as isCommandBearingToolItem, l as itemToolError, m as isCodexCommandBearingToolCall, n as CODEX_NATIVE_SUBAGENT_RUN_ID_PREFIX, o as itemMeta, r as CODEX_NATIVE_SUBAGENT_TASK_KIND, s as itemOutputText, t as CODEX_NATIVE_SUBAGENT_RUNTIME, u as itemToolResult, w as normalizeToolTranscriptArguments, x as collectDynamicToolContentText, y as TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS } from "./native-subagent-task-ids-BzTdT0Uw.js";
8
- import { n as codexApprovalTimeoutText } from "./plugin-approval-roundtrip-Bz3FT8W5.js";
9
- import { asFiniteNumber, normalizeOptionalString, readStringField } from "openclaw/plugin-sdk/string-coerce-runtime";
10
- import { asDateTimestampMs } from "openclaw/plugin-sdk/number-runtime";
11
- import path from "node:path";
12
- import { KeyedAsyncQueue } from "openclaw/plugin-sdk/keyed-async-queue";
13
- import { truncateUtf16Safe } from "openclaw/plugin-sdk/text-utility-runtime";
14
- import { TOOL_PROGRESS_OUTPUT_MAX_CHARS, embeddedAgentLog, emitAgentEvent, formatErrorMessage, inferToolMetaFromArgs, runAgentHarnessAfterToolCallHook } from "openclaw/plugin-sdk/agent-harness-runtime";
15
- import { createAgentHarnessTaskRuntime, deliverAgentHarnessTaskCompletion, isDurableAgentHarnessCompletionDelivery } from "openclaw/plugin-sdk/agent-harness-task-runtime";
16
- //#region extensions/codex/src/app-server/event-projector-tool-progress.ts
17
- const TRANSCRIPT_PROGRESS_SUPPRESSED_TOOL_NAMES = /* @__PURE__ */ new Set([
18
- "message",
19
- "messages",
20
- "reply",
21
- "send",
22
- "reaction",
23
- "react",
24
- "typing"
25
- ]);
26
- function shouldEmitTranscriptToolProgress(toolName, _args) {
27
- const normalized = typeof toolName === "string" ? toolName.trim().toLowerCase() : "";
28
- return Boolean(normalized && !TRANSCRIPT_PROGRESS_SUPPRESSED_TOOL_NAMES.has(normalized));
29
- }
30
- var CodexToolProgressProjection = class {
31
- constructor(params) {
32
- this.params = params;
33
- this.echoesByItem = /* @__PURE__ */ new Map();
34
- this.resultSummaryItemIds = /* @__PURE__ */ new Set();
35
- this.resultOutputItemIds = /* @__PURE__ */ new Set();
36
- this.resultOutputStreamedItemIds = /* @__PURE__ */ new Set();
37
- this.transcriptProgressSuppressedIds = /* @__PURE__ */ new Set();
38
- this.transcriptArgumentsById = /* @__PURE__ */ new Map();
39
- this.resultOutputDeltaState = /* @__PURE__ */ new Map();
40
- this.output = new ToolOutputAccumulator();
41
- this.metas = /* @__PURE__ */ new Map();
42
- this.sideEffectingNativeIds = /* @__PURE__ */ new Set();
43
- this.sideEffectingDynamicIds = /* @__PURE__ */ new Set();
44
- this.transcriptProgressCallIds = /* @__PURE__ */ new Set();
45
- this.approvalTimeoutKinds = /* @__PURE__ */ new Map();
46
- }
47
- get outputTextByItem() {
48
- return this.output.textByItem;
49
- }
50
- get toolMetas() {
51
- return [...this.metas.values()];
52
- }
53
- getToolMeta(itemId) {
54
- return this.metas.get(itemId);
55
- }
56
- get lastToolError() {
57
- return this.lastNativeToolError;
58
- }
59
- get hasPotentialSideEffects() {
60
- return this.sideEffectingNativeIds.size > 0 || this.sideEffectingDynamicIds.size > 0;
61
- }
62
- approvalTimeoutExplanation(itemId, status) {
63
- const kind = isNonSuccessItemStatus(status) && this.approvalTimeoutKinds.get(itemId);
64
- return kind ? codexApprovalTimeoutText(kind) : void 0;
65
- }
66
- setLastToolError(error) {
67
- if (!error) {
68
- this.lastNativeToolError = void 0;
69
- return;
70
- }
71
- const terminalResolution = this.params.observeToolTerminal?.({
72
- toolName: error.toolName,
73
- ...error.meta ? { meta: error.meta } : {},
74
- outcome: "failure",
75
- failure: {
76
- ...error.errorCode ? { errorCode: error.errorCode } : {},
77
- ...error.error ? { error: error.error } : {},
78
- ...error.validationErrorSummary ? { validationErrorSummary: error.validationErrorSummary } : {},
79
- ...error.timedOut ? { timedOut: true } : {},
80
- ...error.middlewareError ? { middlewareError: true } : {}
81
- },
82
- nativeMutation: {
83
- mutatingAction: error.mutatingAction === true,
84
- replaySafe: error.mutatingAction !== true
85
- }
86
- });
87
- this.lastNativeToolError = terminalResolution?.lastToolError ?? (this.lastNativeToolError?.mutatingAction && error.mutatingAction !== true ? this.lastNativeToolError : error);
88
- }
89
- recordDynamicToolResult(params) {
90
- const resultText = collectDynamicToolContentText(params.contentItems);
91
- const existing = this.metas.get(params.callId);
92
- this.metas.set(params.callId, {
93
- toolName: existing?.toolName ?? params.tool,
94
- ...existing?.meta ? { meta: existing.meta } : {},
95
- ...params.asyncStarted === true ? { asyncStarted: true } : {},
96
- isError: !params.success
97
- });
98
- if (params.terminalResolution) this.lastNativeToolError = params.terminalResolution.lastToolError;
99
- else if (!params.success) this.lastNativeToolError = {
100
- toolName: params.tool,
101
- error: resultText || (params.terminalType === "blocked" ? "codex dynamic tool blocked" : "codex dynamic tool failed")
102
- };
103
- else if (this.lastNativeToolError?.mutatingAction !== true) this.lastNativeToolError = void 0;
104
- if (params.sideEffectEvidence === true) this.sideEffectingDynamicIds.add(params.callId);
105
- }
106
- handleOutputDelta(params, toolName) {
107
- const itemId = readStringField(params, "itemId");
108
- const delta = readStringField(params, "delta");
109
- if (!itemId || !delta) return;
110
- const storedOutput = this.output.append(itemId, delta);
111
- this.rememberEcho(itemId, {
112
- displayText: storedOutput.text,
113
- rawLength: storedOutput.normalizedLength,
114
- rawPrefix: storedOutput.rawPrefix,
115
- streamedDisplay: true
116
- });
117
- if (!this.shouldEmitToolOutput()) return;
118
- if (this.transcriptProgressSuppressedIds.has(itemId) || !shouldEmitTranscriptToolProgress(toolName, this.transcriptArgumentsById.get(itemId))) return;
119
- const state = this.resultOutputDeltaState.get(itemId) ?? {
120
- chars: 0,
121
- messages: 0,
122
- truncated: false
123
- };
124
- if (state.truncated) return;
125
- const remainingChars = Math.max(0, TOOL_PROGRESS_OUTPUT_MAX_CHARS - state.chars);
126
- const remainingMessages = Math.max(0, 20 - state.messages);
127
- if (remainingChars === 0 || remainingMessages === 0) {
128
- state.truncated = true;
129
- this.resultOutputDeltaState.set(itemId, state);
130
- this.emitToolResultMessage({
131
- itemId,
132
- text: formatToolOutput(toolName, void 0, "(output truncated)")
133
- });
134
- return;
135
- }
136
- const chunk = delta.length > remainingChars ? truncateUtf16Safe(delta, remainingChars) : delta;
137
- state.chars += chunk.length;
138
- state.messages += 1;
139
- const reachedLimit = delta.length > remainingChars || state.chars >= TOOL_PROGRESS_OUTPUT_MAX_CHARS || state.messages >= 20;
140
- if (reachedLimit) state.truncated = true;
141
- this.resultOutputDeltaState.set(itemId, state);
142
- this.resultOutputStreamedItemIds.add(itemId);
143
- this.emitToolResultMessage({
144
- itemId,
145
- text: formatToolOutput(toolName, void 0, reachedLimit ? `${chunk}\n...(truncated)...` : chunk)
146
- });
147
- }
148
- recordNativeToolError(params) {
149
- const executionStarted = params.status !== "blocked";
150
- const mutatingAction = executionStarted && isMutatingNativeToolItem(params.item);
151
- const isFailure = isNonSuccessItemStatus(params.status);
152
- const approvalTimeoutExplanation = this.approvalTimeoutExplanation(params.item.id, params.status);
153
- const error = isFailure ? approvalTimeoutExplanation ?? itemToolError(params.item, params.status, this.output.textByItem) : void 0;
154
- const failure = error ? {
155
- ...approvalTimeoutExplanation ? { errorCode: "approval_timeout" } : {},
156
- error,
157
- ...approvalTimeoutExplanation ? { timedOut: true } : {}
158
- } : {};
159
- const terminalResolution = this.params.observeToolTerminal?.({
160
- toolCallId: params.item.id,
161
- toolName: params.name,
162
- arguments: itemToolArgs(params.item),
163
- ...params.meta ? { meta: params.meta } : {},
164
- executionStarted,
165
- outcome: isFailure ? "failure" : "success",
166
- ...isFailure ? { failure } : {},
167
- nativeMutation: {
168
- mutatingAction,
169
- replaySafe: !mutatingAction
170
- }
171
- });
172
- if (terminalResolution) {
173
- this.lastNativeToolError = terminalResolution.lastToolError;
174
- return;
175
- }
176
- if (isFailure) this.lastNativeToolError = {
177
- toolName: params.name,
178
- ...params.meta ? { meta: params.meta } : {},
179
- ...failure,
180
- ...mutatingAction ? { mutatingAction: true } : {}
181
- };
182
- else if (this.lastNativeToolError?.mutatingAction !== true) this.lastNativeToolError = void 0;
183
- }
184
- emitToolResultSummary(item) {
185
- if (!item || item.type === "dynamicToolCall") return;
186
- if (!this.params.onToolResult || !this.shouldEmitToolResult()) return;
187
- if (this.resultSummaryItemIds.has(item.id)) return;
188
- const toolName = itemName(item);
189
- const args = itemToolArgs(item);
190
- if (!toolName || !shouldEmitTranscriptToolProgress(toolName, args)) return;
191
- this.resultSummaryItemIds.add(item.id);
192
- const meta = this.shouldIncludeFormattedMeta(isCommandBearingToolItem(item, args)) ? itemMeta(item, this.toolProgressDetailMode()) : void 0;
193
- this.emitToolResultMessage({
194
- itemId: item.id,
195
- text: formatToolSummary(toolName, meta)
196
- });
197
- }
198
- emitToolResultOutput(item) {
199
- if (!item || item.type === "dynamicToolCall") return;
200
- if (!this.params.onToolResult || !this.shouldEmitToolOutput()) return;
201
- if (this.resultOutputItemIds.has(item.id) || this.resultOutputStreamedItemIds.has(item.id)) return;
202
- const toolName = itemName(item);
203
- const output = itemOutputText(item, this.output.textByItem);
204
- if (!toolName || !output || !shouldEmitTranscriptToolProgress(toolName, itemToolArgs(item))) return;
205
- const meta = this.shouldIncludeFormattedMeta(isCommandBearingToolItem(item, itemToolArgs(item))) ? itemMeta(item, this.toolProgressDetailMode()) : void 0;
206
- this.emitToolResultMessage({
207
- itemId: item.id,
208
- text: formatToolOutput(toolName, meta, output),
209
- finalOutput: true,
210
- isError: isNonSuccessItemStatus(itemStatus(item))
211
- });
212
- }
213
- recordToolMeta(item) {
214
- if (!item) return;
215
- if (isSideEffectingNativeToolItem(item)) this.sideEffectingNativeIds.add(item.id);
216
- else this.sideEffectingNativeIds.delete(item.id);
217
- const toolName = itemName(item);
218
- if (!toolName) return;
219
- const meta = itemMeta(item, this.toolProgressDetailMode());
220
- const existing = this.metas.get(item.id);
221
- const terminalStatus = auditNativeToolTerminalStatus(item);
222
- const isError = typeof existing?.isError === "boolean" ? existing.isError : terminalStatus === "completed" ? false : terminalStatus === "failed" || terminalStatus === "blocked" ? true : void 0;
223
- this.metas.set(item.id, {
224
- toolName,
225
- ...meta ? { meta } : {},
226
- ...existing?.asyncStarted ? { asyncStarted: true } : {},
227
- ...isError === void 0 ? {} : { isError }
228
- });
229
- }
230
- recordTranscriptCall(params) {
231
- this.transcriptArgumentsById.set(params.id, params.arguments);
232
- if (!shouldEmitTranscriptToolProgress(params.name, params.arguments)) this.transcriptProgressSuppressedIds.add(params.id);
233
- else this.transcriptProgressSuppressedIds.delete(params.id);
234
- this.emitTranscriptToolCallProgress(params);
235
- }
236
- recordTranscriptResult(params) {
237
- this.emitTranscriptToolResultProgress(params);
238
- }
239
- matchesEcho(text) {
240
- for (const state of this.echoesByItem.values()) {
241
- if (state.streamedDisplayText === text || state.displayTexts.includes(text)) return true;
242
- if (state.streamedRawSignature && text.length === state.streamedRawSignature.length && text.startsWith(state.streamedRawSignature.prefix)) return true;
243
- for (const signature of state.rawSignatures) if (text.length === signature.length && text.startsWith(signature.prefix)) return true;
244
- }
245
- return false;
246
- }
247
- rememberCommandAggregateOutputEcho(item) {
248
- if (item?.type !== "commandExecution" || typeof item.aggregatedOutput !== "string") return;
249
- const signature = toolOutputRawEchoSignature(item.aggregatedOutput);
250
- if (signature) this.rememberEcho(item.id, signature);
251
- }
252
- toolProgressDetailMode() {
253
- return resolveCodexToolProgressDetailMode(this.params.toolProgressDetail);
254
- }
255
- emitToolResultMessage(params) {
256
- const rawText = params.text.trim();
257
- const text = truncateToolTranscriptText(rawText);
258
- if (!text) return;
259
- this.rememberEcho(params.itemId, {
260
- displayText: text,
261
- rawText
262
- });
263
- if (params.finalOutput) this.resultOutputItemIds.add(params.itemId);
264
- try {
265
- Promise.resolve(this.params.onToolResult?.({
266
- text,
267
- ...(this.params.messageChannel || this.params.messageProvider) && { channelData: { openclawToolProgressId: params.itemId } },
268
- ...params.isError === true ? { isError: true } : {}
269
- })).catch(() => {});
270
- } catch {}
271
- }
272
- shouldEmitToolResult() {
273
- return typeof this.params.shouldEmitToolResult === "function" ? this.params.shouldEmitToolResult() : this.params.verboseLevel === "on" || this.params.verboseLevel === "full";
274
- }
275
- shouldEmitToolOutput() {
276
- return typeof this.params.shouldEmitToolOutput === "function" ? this.params.shouldEmitToolOutput() : this.params.verboseLevel === "full";
277
- }
278
- shouldIncludeFormattedMeta(commandBearing) {
279
- const channel = this.params.messageChannel ?? this.params.messageProvider;
280
- return !commandBearing || !channel && this.shouldEmitToolOutput();
281
- }
282
- emitTranscriptToolCallProgress(params) {
283
- if (params.name === "progress_card" || !shouldEmitTranscriptToolProgress(params.name, params.arguments)) return;
284
- this.transcriptProgressCallIds.add(params.id);
285
- const args = normalizeToolTranscriptArguments(params.arguments);
286
- const meta = this.shouldIncludeFormattedMeta(isCodexCommandBearingToolCall(params.name, args)) ? inferToolMetaFromArgs(params.name, args, { detailMode: this.toolProgressDetailMode() }) : void 0;
287
- if (!this.params.onToolResult || !this.shouldEmitToolResult() || this.resultSummaryItemIds.has(params.id) || this.resultOutputStreamedItemIds.has(params.id)) return;
288
- this.resultSummaryItemIds.add(params.id);
289
- this.emitToolResultMessage({
290
- itemId: params.id,
291
- text: formatToolSummary(params.name, meta)
292
- });
293
- }
294
- emitTranscriptToolResultProgress(params) {
295
- if (params.name === "progress_card" && !params.isError || this.transcriptProgressSuppressedIds.has(params.id) || !shouldEmitTranscriptToolProgress(params.name, this.transcriptArgumentsById.get(params.id))) return;
296
- if (params.name === "progress_card" && this.shouldEmitToolResult()) this.emitToolResultMessage({
297
- itemId: params.id,
298
- text: formatToolSummary(params.name),
299
- isError: true
300
- });
301
- if (!this.transcriptProgressCallIds.has(params.id)) this.emitTranscriptToolCallProgress({
302
- id: params.id,
303
- name: params.name,
304
- arguments: {}
305
- });
306
- if (!this.params.onToolResult || !this.shouldEmitToolOutput() || this.resultOutputItemIds.has(params.id) || this.resultOutputStreamedItemIds.has(params.id)) return;
307
- const text = params.text?.trim();
308
- if (text) this.emitToolResultMessage({
309
- itemId: params.id,
310
- text: formatToolOutput(params.name, void 0, text),
311
- finalOutput: true,
312
- isError: params.isError
313
- });
314
- }
315
- rememberEcho(itemId, signature) {
316
- if (!itemId) return;
317
- const existing = this.echoesByItem.get(itemId) ?? {
318
- displayTexts: [],
319
- rawSignatures: []
320
- };
321
- const displayText = signature.displayText?.trim();
322
- if (displayText) {
323
- if (signature.streamedDisplay) existing.streamedDisplayText = displayText;
324
- else if (!existing.displayTexts.includes(displayText)) {
325
- if (existing.displayTexts.length >= 24) existing.displayTexts.shift();
326
- existing.displayTexts.push(displayText);
327
- }
328
- }
329
- const rawText = signature.rawText?.trim();
330
- const rawLength = signature.rawLength ?? rawText?.length;
331
- const rawPrefix = signature.rawPrefix?.trim() ?? rawText;
332
- if (rawLength !== void 0 && rawPrefix && rawPrefix.length >= 1024) {
333
- const next = {
334
- length: rawLength,
335
- prefix: rawPrefix.slice(0, TOOL_TRANSCRIPT_OUTPUT_MAX_CHARS)
336
- };
337
- if (signature.streamedDisplay) existing.streamedRawSignature = next;
338
- else {
339
- const matchIndex = existing.rawSignatures.findIndex((entry) => entry.prefix === next.prefix);
340
- if (matchIndex >= 0) existing.rawSignatures[matchIndex] = next;
341
- else {
342
- if (existing.rawSignatures.length >= 24) existing.rawSignatures.shift();
343
- existing.rawSignatures.push(next);
344
- }
345
- }
346
- }
347
- this.echoesByItem.set(itemId, existing);
348
- }
349
- };
350
- //#endregion
351
- //#region extensions/codex/src/app-server/event-projector-tool-transcript.ts
352
- const ZERO_USAGE = {
353
- input: 0,
354
- output: 0,
355
- cacheRead: 0,
356
- cacheWrite: 0,
357
- totalTokens: 0,
358
- cost: {
359
- input: 0,
360
- output: 0,
361
- cacheRead: 0,
362
- cacheWrite: 0,
363
- total: 0
364
- }
365
- };
366
- const MISSING_TOOL_RESULT_ERROR = "OpenClaw recorded a native Codex tool.call without a matching tool.result before the turn completed.";
367
- const NATIVE_PATCH_REJECTION_RE = /^\s*patch rejected:\s*writing outside of the project;\s*rejected by user approval settings\s*$/iu;
368
- 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;
369
- 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;
370
- const MAX_TOOL_APPROVAL_REVIEWS = 16;
371
- function toolApprovalReviewOutcome(state) {
372
- return state.denied ? "denied" : state.unresolvedReviewIds === null || state.unresolvedReviewIds.size > 0 ? "reviewing" : "approved";
373
- }
374
- function readCodeModeNativePatchInput(source) {
375
- if (typeof source !== "string") return;
376
- const match = CODE_MODE_NATIVE_PATCH_SOURCE_RE.exec(source);
377
- if (!match?.[2]) return;
378
- try {
379
- const patch = JSON.parse(match[2]);
380
- return typeof patch === "string" && /^\*\*\* Begin Patch\r?\n[\s\S]*\r?\n\*\*\* End Patch(?:\r?\n)?$/u.test(patch) ? patch : void 0;
381
- } catch {
382
- return;
383
- }
384
- }
385
- function readInterceptedNativePatchInput(command) {
386
- if (typeof command !== "string") return;
387
- const lines = command.replace(/\r\n?/gu, "\n").split("\n");
388
- const patchStart = lines.indexOf("*** Begin Patch");
389
- const invocation = /^[\t ]*(?:cd[\t ]+(?:'([^'\n]+)'|([A-Za-z0-9_./-]+))[\t ]+&&[\t ]+)?apply_patch[\t ]*<<-?[\t ]*'([^'\n]+)'[\t ]*$/u.exec(lines[0] ?? "");
390
- if (!invocation || patchStart !== 1) return;
391
- const patchEnd = lines.indexOf("*** End Patch", patchStart + 1);
392
- const cwd = invocation[1] ?? invocation[2];
393
- const delimiter = invocation[3];
394
- if (patchEnd < 0 || lines[patchEnd + 1] !== delimiter || lines.slice(patchEnd + 2).some((line) => line.trim().length > 0)) return;
395
- return {
396
- input: `${lines.slice(patchStart, patchEnd + 1).join("\n")}\n`,
397
- ...cwd ? { cwd } : {}
398
- };
399
- }
400
- var CodexToolTranscriptProjection = class {
401
- constructor(params, threadId, turnId, progress, nextTranscriptTimestamp, options = {}) {
402
- this.params = params;
403
- this.threadId = threadId;
404
- this.turnId = turnId;
405
- this.progress = progress;
406
- this.nextTranscriptTimestamp = nextTranscriptTimestamp;
407
- this.options = options;
408
- this.messages = [];
409
- this.callIds = /* @__PURE__ */ new Set();
410
- this.resultIds = /* @__PURE__ */ new Set();
411
- this.namesById = /* @__PURE__ */ new Map();
412
- this.trajectoryCallIds = /* @__PURE__ */ new Set();
413
- this.trajectoryResultIds = /* @__PURE__ */ new Set();
414
- this.trajectoryNamesById = /* @__PURE__ */ new Map();
415
- this.trajectoryItemsById = /* @__PURE__ */ new Map();
416
- this.afterToolCallObservedItemIds = /* @__PURE__ */ new Set();
417
- this.nativeMcpAppResultDetails = /* @__PURE__ */ new Map();
418
- this.nativeMcpAppResultDetailsAttempted = /* @__PURE__ */ new Set();
419
- this.approvalReviewsByCallId = /* @__PURE__ */ new Map();
420
- this.rawNativeToolOutputByCallId = /* @__PURE__ */ new Map();
421
- this.pendingRawPatchOutputIds = /* @__PURE__ */ new Set();
422
- this.codeModeNativePatchInputsByCallId = /* @__PURE__ */ new Map();
423
- }
424
- get transcriptMessages() {
425
- return this.messages;
426
- }
427
- recordToolApprovalReview(toolCallId, reviewId, status, review) {
428
- const state = this.approvalReviewsByCallId.get(toolCallId) ?? {
429
- reviews: [],
430
- denied: false,
431
- unresolvedReviewIds: /* @__PURE__ */ new Set()
432
- };
433
- state.reviews = [...state.reviews.filter((candidate) => candidate.id !== reviewId), review].slice(-16);
434
- state.denied ||= [
435
- "denied",
436
- "timed_out",
437
- "aborted"
438
- ].includes(status);
439
- const unresolved = state.unresolvedReviewIds;
440
- if (status === "in_progress") state.unresolvedReviewIds = unresolved && (unresolved.size < MAX_TOOL_APPROVAL_REVIEWS || unresolved.has(reviewId)) ? unresolved.add(reviewId) : null;
441
- else unresolved?.delete(reviewId);
442
- this.approvalReviewsByCallId.set(toolCallId, state);
443
- return toolApprovalReviewOutcome(state);
444
- }
445
- finalizeToolApprovalReviews(toolCallId) {
446
- const state = this.approvalReviewsByCallId.get(toolCallId);
447
- if (!state) return;
448
- state.unresolvedReviewIds = /* @__PURE__ */ new Set();
449
- return toolApprovalReviewOutcome(state);
450
- }
451
- recordDynamicToolCall(params) {
452
- this.recordToolCall({
453
- id: params.callId,
454
- name: params.tool,
455
- arguments: sanitizeCodexToolArguments(params.arguments)
456
- });
457
- }
458
- recordDynamicToolResult(params, resultContentSource) {
459
- this.recordToolResult({
460
- id: params.callId,
461
- name: params.tool,
462
- text: collectDynamicToolContentText(params.contentItems),
463
- isError: !params.success,
464
- details: params.details,
465
- ...resultContentSource ? { resultContentSource } : {}
466
- });
467
- }
468
- recordNativeToolCall(item) {
469
- if (!item || !shouldRecordNativeToolTranscript(item)) return;
470
- const name = itemName(item);
471
- if (name) this.recordToolCall({
472
- id: item.id,
473
- name,
474
- arguments: itemToolArgs(item)
475
- });
476
- }
477
- recordNativeToolResult(item, details) {
478
- if (!item || !shouldRecordNativeToolTranscript(item) || this.resultIds.has(item.id)) return;
479
- const name = itemName(item);
480
- if (name) {
481
- const status = itemStatus(item);
482
- const approvalTimeoutExplanation = this.progress.approvalTimeoutExplanation(item.id, status);
483
- this.recordToolResult({
484
- id: item.id,
485
- name,
486
- text: approvalTimeoutExplanation ?? this.rawNativeToolOutputByCallId.get(item.id) ?? itemTranscriptResultText(item, this.progress.outputTextByItem),
487
- isError: isNonSuccessItemStatus(status),
488
- details,
489
- ...item.type === "webSearch" ? { resultContentSource: "network" } : {}
490
- });
491
- this.progress.approvalTimeoutKinds.delete(item.id);
492
- }
493
- }
494
- recordRawNativeToolItem(item) {
495
- const type = typeof item.type === "string" ? item.type : void 0;
496
- const callId = typeof item.call_id === "string" ? item.call_id : typeof item.callId === "string" ? item.callId : void 0;
497
- if (!callId) return;
498
- if ((type === "custom_tool_call" || type === "function_call") && (item.name === "apply_patch" || item.name === "exec_command" || item.name === "exec")) {
499
- let args;
500
- if (type === "custom_tool_call" && item.name === "apply_patch" && typeof item.input === "string") args = { input: item.input };
501
- else if (type === "custom_tool_call" && item.name === "exec") {
502
- const input = readCodeModeNativePatchInput(item.input);
503
- if (input) this.codeModeNativePatchInputsByCallId.set(callId, input);
504
- return;
505
- } else if (type === "function_call" && typeof item.arguments === "string") try {
506
- const parsed = JSON.parse(item.arguments);
507
- if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
508
- const parsedArguments = parsed;
509
- if (item.name === "apply_patch") args = parsedArguments;
510
- else {
511
- const patch = readInterceptedNativePatchInput(typeof parsedArguments.cmd === "string" ? parsedArguments.cmd : typeof parsedArguments.command === "string" ? parsedArguments.command : void 0);
512
- if (patch) {
513
- const workdir = typeof parsedArguments.workdir === "string" ? parsedArguments.workdir : typeof parsedArguments.cwd === "string" ? parsedArguments.cwd : void 0;
514
- const cwd = patch.cwd ? workdir && !path.isAbsolute(patch.cwd) ? path.join(workdir, patch.cwd) : patch.cwd : workdir;
515
- args = {
516
- input: patch.input,
517
- ...cwd ? { cwd } : {}
518
- };
519
- }
520
- }
521
- }
522
- } catch {
523
- return;
524
- }
525
- if (args) {
526
- this.pendingRawPatchOutputIds.add(callId);
527
- this.recordToolCall({
528
- id: callId,
529
- name: "apply_patch",
530
- arguments: args
531
- });
532
- }
533
- return;
534
- }
535
- if (type !== "custom_tool_call_output" && type !== "function_call_output" || this.namesById.get(callId) !== "apply_patch" && !this.codeModeNativePatchInputsByCallId.has(callId)) return;
536
- this.pendingRawPatchOutputIds.delete(callId);
537
- const text = typeof item.output === "string" ? item.output : Array.isArray(item.output) ? collectDynamicToolContentText(item.output) : "";
538
- if (!text.trim()) return;
539
- const codeModePatchInput = this.codeModeNativePatchInputsByCallId.get(callId);
540
- if (codeModePatchInput) {
541
- this.codeModeNativePatchInputsByCallId.delete(callId);
542
- const execution = CODE_MODE_NATIVE_PATCH_RESULT_RE.exec(text);
543
- if (execution?.[1]?.toLowerCase() === "completed" && execution[2]?.trim() === "{}") return;
544
- if (execution?.[1]?.toLowerCase() === "failed") {
545
- const failure = execution[2]?.replace(/^Script error:\s*/iu, "").trim() || text;
546
- this.recordToolCall({
547
- id: callId,
548
- name: "apply_patch",
549
- arguments: { input: codeModePatchInput }
550
- });
551
- this.recordToolResult({
552
- id: callId,
553
- name: "apply_patch",
554
- text: failure,
555
- isError: true
556
- });
557
- }
558
- return;
559
- }
560
- this.rawNativeToolOutputByCallId.set(callId, text);
561
- const result = this.messages.find((message) => message.role === "toolResult" && message.toolCallId === callId);
562
- if (!result) {
563
- if (NATIVE_PATCH_REJECTION_RE.test(text)) this.recordToolResult({
564
- id: callId,
565
- name: "apply_patch",
566
- text,
567
- isError: true
568
- });
569
- return;
570
- }
571
- result.content = this.createToolResultMessage({
572
- id: callId,
573
- name: "apply_patch",
574
- text,
575
- isError: result.isError
576
- }).content;
577
- }
578
- async prepareNativeToolResultDetails(item) {
579
- const preparedDetails = await this.prepareNativeMcpAppResultDetails(item);
580
- const approvalReviewState = item ? this.approvalReviewsByCallId.get(item.id) : void 0;
581
- const reviewDetails = approvalReviewState ? {
582
- approvalReviews: approvalReviewState.reviews,
583
- approvalReviewOutcome: toolApprovalReviewOutcome(approvalReviewState)
584
- } : void 0;
585
- return reviewDetails ? isJsonObject(preparedDetails) ? {
586
- ...preparedDetails,
587
- ...reviewDetails
588
- } : {
589
- ...preparedDetails !== void 0 ? { toolDetails: preparedDetails } : {},
590
- ...reviewDetails
591
- } : preparedDetails;
592
- }
593
- async prepareNativeMcpAppResultDetails(item) {
594
- if (!item || item.type !== "mcpToolCall" || itemStatus(item) === "running") return;
595
- if (this.nativeMcpAppResultDetails.has(item.id)) return this.nativeMcpAppResultDetails.get(item.id);
596
- if (this.nativeMcpAppResultDetailsAttempted.has(item.id) || !this.options.prepareNativeMcpAppResultDetails) return;
597
- this.nativeMcpAppResultDetailsAttempted.add(item.id);
598
- try {
599
- const details = await this.options.prepareNativeMcpAppResultDetails(item);
600
- if (details !== void 0) this.nativeMcpAppResultDetails.set(item.id, details);
601
- return details;
602
- } catch (error) {
603
- embeddedAgentLog.debug("codex native MCP App preview preparation failed", {
604
- itemId: item.id,
605
- error
606
- });
607
- return;
608
- }
609
- }
610
- recordTrajectoryEvent(params) {
611
- if (params.phase === "start") {
612
- this.trajectoryCallIds.add(params.item.id);
613
- this.trajectoryNamesById.set(params.item.id, params.name);
614
- this.trajectoryItemsById.set(params.item.id, params.item);
615
- this.options.trajectoryRecorder?.recordEvent("tool.call", {
616
- threadId: this.threadId,
617
- turnId: this.turnId,
618
- itemId: params.item.id,
619
- toolCallId: params.item.id,
620
- name: params.name,
621
- arguments: params.args
622
- });
623
- return;
624
- }
625
- this.trajectoryResultIds.add(params.item.id);
626
- const toolResult = itemToolResult(params.item).result;
627
- const output = this.progress.approvalTimeoutExplanation(params.item.id, params.status) ?? itemOutputText(params.item, this.progress.outputTextByItem);
628
- this.options.trajectoryRecorder?.recordEvent("tool.result", {
629
- threadId: this.threadId,
630
- turnId: this.turnId,
631
- itemId: params.item.id,
632
- toolCallId: params.item.id,
633
- name: params.name,
634
- status: params.status,
635
- isError: isNonSuccessItemStatus(params.status),
636
- ...toolResult ? { result: toolResult } : {},
637
- ...output ? { output } : {}
638
- });
639
- }
640
- emitAfterToolCallObservation(item) {
641
- if (!this.shouldEmitAfterToolCallObservation(item)) return;
642
- const name = itemName(item);
643
- const status = itemStatus(item);
644
- if (!name || status === "running") return;
645
- this.afterToolCallObservedItemIds.add(item.id);
646
- const result = itemToolResult(item).result;
647
- const error = this.progress.approvalTimeoutExplanation(item.id, status) ?? itemToolError(item, status, this.progress.outputTextByItem);
648
- const startedAt = resolveStartedAtFromDurationMs(item.durationMs);
649
- const hookParams = {
650
- toolName: name,
651
- toolCallId: item.id,
652
- runId: this.params.runId,
653
- agentId: this.params.agentId,
654
- sessionId: this.params.sessionId,
655
- sessionKey: this.params.sessionKey,
656
- startArgs: itemToolArgs(item) ?? {},
657
- ...result !== void 0 ? { result } : {},
658
- ...error ? { error } : {},
659
- ...startedAt !== void 0 ? { startedAt } : {}
660
- };
661
- setImmediate(() => {
662
- runAgentHarnessAfterToolCallHook(hookParams);
663
- });
664
- }
665
- synthesizeMissingToolResults(params) {
666
- if (!params.synthesize) return;
667
- const missingTranscriptIds = [...this.callIds].filter((id) => !this.resultIds.has(id));
668
- const missingTrajectoryIds = [...this.trajectoryCallIds].filter((id) => !this.trajectoryResultIds.has(id));
669
- if (missingTranscriptIds.length === 0 && missingTrajectoryIds.length === 0) return;
670
- for (const id of missingTranscriptIds) {
671
- const name = this.namesById.get(id) ?? this.trajectoryNamesById.get(id);
672
- if (name) this.recordToolResult({
673
- id,
674
- name,
675
- text: formatMissingToolResultError({
676
- id,
677
- name
678
- }),
679
- isError: true,
680
- details: { reason: "missing_tool_result" }
681
- });
682
- }
683
- for (const id of missingTrajectoryIds) {
684
- const name = this.trajectoryNamesById.get(id) ?? this.namesById.get(id);
685
- if (!name) continue;
686
- this.trajectoryResultIds.add(id);
687
- const text = formatMissingToolResultError({
688
- id,
689
- name
690
- });
691
- this.options.trajectoryRecorder?.recordEvent("tool.result", {
692
- threadId: this.threadId,
693
- turnId: this.turnId,
694
- itemId: id,
695
- toolCallId: id,
696
- name,
697
- status: "failed",
698
- isError: true,
699
- result: {
700
- status: "failed",
701
- reason: "missing_tool_result"
702
- },
703
- output: text
704
- });
705
- }
706
- if (params.terminalDisposition === "tool_error") {
707
- this.recordMissingToolError(missingTranscriptIds, missingTrajectoryIds);
708
- return;
709
- }
710
- if (params.terminalDisposition === "diagnostic_only") return;
711
- const missingCount = (/* @__PURE__ */ new Set([...missingTranscriptIds, ...missingTrajectoryIds])).size;
712
- return missingCount === 1 ? MISSING_TOOL_RESULT_ERROR : `${MISSING_TOOL_RESULT_ERROR} missingToolResultCount=${missingCount}`;
713
- }
714
- async readMirroredSessionMessages(signal) {
715
- return await readCodexMirroredSessionHistoryMessages({
716
- agentId: this.params.agentId,
717
- sessionFile: this.params.sessionFile,
718
- sessionId: this.params.sessionId,
719
- sessionKey: this.params.sessionKey,
720
- sessionTarget: this.params.sessionTarget
721
- }, void 0, "native-evidence", signal) ?? [];
722
- }
723
- recordToolCall(params) {
724
- if (!params.id || !params.name || this.callIds.has(params.id)) return;
725
- this.callIds.add(params.id);
726
- this.namesById.set(params.id, params.name);
727
- this.progress.recordTranscriptCall(params);
728
- const message = attachCodexMirrorIdentity(this.createToolCallMessage(params), `${this.turnId}:tool:${params.id}:call`);
729
- this.messages.push(message);
730
- this.options.checkpointMessage?.({ read: () => message });
731
- }
732
- recordToolResult(params) {
733
- if (!params.id || !params.name || this.resultIds.has(params.id)) return;
734
- this.resultIds.add(params.id);
735
- this.progress.recordTranscriptResult(params);
736
- const message = attachCodexMirrorIdentity(this.createToolResultMessage(params), `${this.turnId}:tool:${params.id}:result`);
737
- this.messages.push(message);
738
- this.options.checkpointMessage?.({
739
- read: () => message,
740
- ready: () => !this.pendingRawPatchOutputIds.has(params.id)
741
- });
742
- }
743
- recordMissingToolError(missingTranscriptIds, missingTrajectoryIds) {
744
- const firstMissingId = missingTranscriptIds.find((id) => Boolean(this.namesById.get(id))) ?? missingTrajectoryIds.find((id) => Boolean(this.trajectoryNamesById.get(id) ?? this.namesById.get(id)));
745
- if (!firstMissingId) return;
746
- const name = this.namesById.get(firstMissingId) ?? this.trajectoryNamesById.get(firstMissingId);
747
- if (!name) return;
748
- const item = this.trajectoryItemsById.get(firstMissingId);
749
- const meta = item ? itemMeta(item, this.progress.toolProgressDetailMode()) : this.progress.getToolMeta(firstMissingId)?.meta;
750
- this.progress.setLastToolError({
751
- toolName: name,
752
- ...meta ? { meta } : {},
753
- error: formatMissingToolResultError({
754
- id: firstMissingId,
755
- name
756
- }),
757
- ...item && isMutatingNativeToolItem(item) ? { mutatingAction: true } : {}
758
- });
759
- }
760
- shouldEmitAfterToolCallObservation(item) {
761
- if (!shouldSynthesizeToolProgressForItem(item) || this.afterToolCallObservedItemIds.has(item.id)) return false;
762
- return !(this.options.nativePostToolUseRelayEnabled && isNativePostToolUseRelayItem(item));
763
- }
764
- createToolCallMessage(params) {
765
- const args = normalizeToolTranscriptArguments(params.arguments);
766
- const attribution = resolveCodexLocalRuntimeAttribution(this.params);
767
- return {
768
- role: "assistant",
769
- content: [{
770
- type: "toolCall",
771
- id: params.id,
772
- name: params.name,
773
- arguments: args,
774
- input: args
775
- }],
776
- api: attribution.api ?? "openai-chatgpt-responses",
777
- provider: attribution.provider,
778
- model: this.params.modelId,
779
- usage: ZERO_USAGE,
780
- stopReason: "toolUse",
781
- timestamp: this.nextTranscriptTimestamp()
782
- };
783
- }
784
- createToolResultMessage(params) {
785
- const text = truncateToolTranscriptText(params.text?.trim() || toolResultStatusText(params));
786
- return {
787
- role: "toolResult",
788
- toolCallId: params.id,
789
- toolName: params.name,
790
- isError: params.isError,
791
- content: [{
792
- type: "toolResult",
793
- id: params.id,
794
- name: params.name,
795
- toolName: params.name,
796
- toolCallId: params.id,
797
- toolUseId: params.id,
798
- tool_use_id: params.id,
799
- content: text,
800
- text
801
- }],
802
- ...params.details !== void 0 ? { details: params.details } : {},
803
- ...params.resultContentSource ? { __openclaw: { resultContentSource: params.resultContentSource } } : {},
804
- timestamp: this.nextTranscriptTimestamp()
805
- };
806
- }
807
- };
808
- function formatMissingToolResultError(params) {
809
- return `${MISSING_TOOL_RESULT_ERROR} toolCallId=${params.id}; toolName=${params.name}`;
810
- }
811
- function toolResultStatusText(params) {
812
- return params.isError ? `${params.name} failed` : `${params.name} completed`;
813
- }
814
- function resolveStartedAtFromDurationMs(durationMs) {
815
- if (typeof durationMs !== "number" || !Number.isFinite(durationMs)) return;
816
- return asDateTimestampMs(Date.now() - Math.max(0, durationMs));
817
- }
818
- //#endregion
819
- //#region extensions/codex/src/app-server/event-projector-events.ts
820
- /** Downstream event consumers must never corrupt the canonical Codex turn projection. */
821
- function emitCodexAgentEvent(params, event) {
822
- try {
823
- emitAgentEvent({
824
- runId: params.runId,
825
- stream: event.stream,
826
- data: event.data,
827
- ...params.sessionKey ? { sessionKey: params.sessionKey } : {}
828
- });
829
- } catch (error) {
830
- embeddedAgentLog.debug("codex app-server global agent event emit failed", { error });
831
- }
832
- try {
833
- const maybePromise = params.onAgentEvent?.(event);
834
- Promise.resolve(maybePromise).catch((error) => {
835
- embeddedAgentLog.debug("codex app-server agent event handler rejected", { error });
836
- });
837
- } catch (error) {
838
- embeddedAgentLog.debug("codex app-server agent event handler threw", { error });
839
- }
840
- }
841
- function guardianActionCommand(action) {
842
- if (!action) return;
843
- const directLabel = readStringField(action, "command") ?? readStringField(action, "target") ?? readStringField(action, "toolTitle") ?? readStringField(action, "reason");
844
- if (directLabel) return directLabel;
845
- const server = readStringField(action, "connectorName") ?? readStringField(action, "server");
846
- const tool = readStringField(action, "toolName");
847
- if (server && tool) return `${server}/${tool}`;
848
- const argv = Array.isArray(action.argv) ? action.argv.filter((value) => typeof value === "string") : [];
849
- return argv.length > 0 ? argv.join(" ") : readStringField(action, "program");
850
- }
851
- function normalizeApprovalReviewStatus(status) {
852
- return status === "inProgress" ? "in_progress" : status === "timedOut" ? "timed_out" : status;
853
- }
854
- const GUARDIAN_TIMEOUT_WARNING = "Automatic approval review timed out while evaluating the requested approval.";
855
- const LOG_ONLY_CODEX_WARNING_PATTERNS = [/^Configured service tier `[^`\r\n]+` is not advertised as supported for model `[^`\r\n]+` and will be omitted from requests\.$/, /^Code Mode is enabled in configuration, but model `[^`\r\n]+` does not advertise Code Mode support\. This may degrade model performance\. Disable `features\.code_mode` and `features\.code_mode_only`, or select a model whose metadata enables Code Mode\.$/];
856
- function projectNormalizedToolItem(params) {
857
- const { item } = params;
858
- if (!item || !shouldSynthesizeToolProgressForItem(item)) return;
859
- const name = itemName(item);
860
- if (!name) return;
861
- const status = params.phase === "result" ? itemStatus(item) : "running";
862
- const args = itemToolArgs(item);
863
- const commandBearing = isCommandBearingToolItem(item, args);
864
- const meta = itemMeta(item, params.detailMode);
865
- return {
866
- name,
867
- status,
868
- args,
869
- meta,
870
- event: shouldEmitTranscriptToolProgress(name, args) ? {
871
- stream: "tool",
872
- data: {
873
- phase: params.phase,
874
- name,
875
- itemId: item.id,
876
- toolCallId: item.id,
877
- ...meta ? { meta } : {},
878
- ...commandBearing ? { commandBearing: true } : {},
879
- ...params.phase === "start" && args ? { args } : {},
880
- ...params.phase === "result" ? {
881
- status,
882
- isError: isNonSuccessItemStatus(status),
883
- ...itemToolResult(item)
884
- } : {}
885
- }
886
- } : void 0
887
- };
888
- }
889
- var CodexEventProjection = class {
890
- constructor(threadId, turnId, emitAgentEvent, toolProgress, toolTranscript, onNativeToolResultRecorded) {
891
- this.threadId = threadId;
892
- this.turnId = turnId;
893
- this.emitAgentEvent = emitAgentEvent;
894
- this.toolProgress = toolProgress;
895
- this.toolTranscript = toolTranscript;
896
- this.onNativeToolResultRecorded = onNativeToolResultRecorded;
897
- this.reviewCount = 0;
898
- }
899
- get guardianReviewCount() {
900
- return this.reviewCount;
901
- }
902
- emitCompactionEnd(itemId, completed) {
903
- this.emitAgentEvent({
904
- stream: "compaction",
905
- data: {
906
- phase: "end",
907
- backend: "codex-app-server",
908
- completed,
909
- threadId: this.threadId,
910
- turnId: this.turnId,
911
- itemId
912
- }
913
- });
914
- }
915
- handleGuardianReview(method, params) {
916
- this.reviewCount += 1;
917
- const review = isJsonObject(params.review) ? params.review : void 0;
918
- const action = isJsonObject(params.action) ? params.action : void 0;
919
- const reviewId = readStringField(params, "reviewId");
920
- const targetItemId = readNullableString$1(params, "targetItemId");
921
- const command = guardianActionCommand(action);
922
- const reviewStatus = review ? readStringField(review, "status") : void 0;
923
- const status = normalizeApprovalReviewStatus(reviewStatus);
924
- const riskLevel = review ? readStringField(review, "riskLevel") : void 0;
925
- const userAuthorization = review ? readStringField(review, "userAuthorization") : void 0;
926
- const rationale = review ? readNullableString$1(review, "rationale") : void 0;
927
- 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;
928
- if (Boolean(targetItemId) && Boolean(reviewId) && this.pendingGuardianWarning === expectedWarning) this.pendingGuardianWarning = void 0;
929
- else this.flushPendingGuardianWarning();
930
- const threadId = readStringField(params, "threadId") ?? this.threadId;
931
- const turnId = readStringField(params, "turnId") ?? this.turnId;
932
- if (method.endsWith("/started")) this.activeGuardianReview = {
933
- reviewId,
934
- targetItemId,
935
- command,
936
- threadId,
937
- turnId
938
- };
939
- this.emitAgentEvent({
940
- stream: "codex_app_server.guardian",
941
- data: {
942
- method,
943
- phase: method.endsWith("/started") ? "started" : "completed",
944
- threadId,
945
- turnId,
946
- reviewId,
947
- targetItemId,
948
- decisionSource: readStringField(params, "decisionSource"),
949
- status: reviewStatus,
950
- riskLevel,
951
- userAuthorization,
952
- rationale,
953
- actionType: action ? readStringField(action, "type") : void 0,
954
- command
955
- }
956
- });
957
- if (reviewId && targetItemId && status) {
958
- const approvalReview = {
959
- id: reviewId,
960
- label: "Guardian",
961
- status,
962
- ...riskLevel ? { riskLevel } : {},
963
- ...userAuthorization ? { userAuthorization } : {},
964
- ...rationale ? { rationale } : {}
965
- };
966
- const approvalReviewOutcome = this.toolTranscript.recordToolApprovalReview(targetItemId, reviewId, status, approvalReview);
967
- this.emitAgentEvent({
968
- stream: "tool",
969
- data: {
970
- phase: "review",
971
- toolCallId: targetItemId,
972
- hideFromChannelProgress: true,
973
- approvalReviewOutcome,
974
- review: approvalReview
975
- }
976
- });
977
- }
978
- if (method.endsWith("/completed") && this.activeGuardianReview?.reviewId === reviewId) this.activeGuardianReview = void 0;
979
- }
980
- handleGuardianWarning(params) {
981
- this.flushPendingGuardianWarning();
982
- const message = readStringField(params, "message");
983
- if (message) {
984
- this.pendingGuardianWarning = message;
985
- return;
986
- }
987
- this.emitAgentEvent({
988
- stream: "codex_app_server.guardian",
989
- data: {
990
- phase: "warning",
991
- message
992
- }
993
- });
994
- }
995
- handleWarning(params) {
996
- const message = [readStringField(params, "summary") ?? readStringField(params, "message"), readStringField(params, "details")].filter(Boolean).join("\n");
997
- if (LOG_ONLY_CODEX_WARNING_PATTERNS.some((pattern) => pattern.test(message))) embeddedAgentLog.warn(message);
998
- else if (message) this.emitAgentEvent({
999
- stream: "notice",
1000
- data: {
1001
- phase: "warning",
1002
- message
1003
- }
1004
- });
1005
- }
1006
- handleModelRerouted(params) {
1007
- const fromModel = readStringField(params, "fromModel");
1008
- const toModel = readStringField(params, "toModel");
1009
- const reason = readStringField(params, "reason");
1010
- if (fromModel && toModel && fromModel !== toModel) this.emitAgentEvent({
1011
- stream: "fallback",
1012
- data: {
1013
- fromModel,
1014
- toModel,
1015
- ...reason ? { reason } : {}
1016
- }
1017
- });
1018
- }
1019
- handleRetry(params) {
1020
- const rateLimited = isJsonObject(params.error) && params.error.codexErrorInfo === "rateLimitExceeded";
1021
- this.emitAgentEvent({
1022
- stream: "run_status",
1023
- data: {
1024
- phase: "retrying",
1025
- message: rateLimited ? "Rate limited. The provider is retrying." : "Connection interrupted. The provider is retrying."
1026
- }
1027
- });
1028
- }
1029
- flushPendingGuardianWarning() {
1030
- const pending = this.pendingGuardianWarning;
1031
- if (!pending) return;
1032
- this.pendingGuardianWarning = void 0;
1033
- this.emitAgentEvent({
1034
- stream: "codex_app_server.guardian",
1035
- data: {
1036
- phase: "warning",
1037
- message: pending
1038
- }
1039
- });
1040
- }
1041
- handleStrictReviewRequired(params) {
1042
- this.emitAgentEvent({
1043
- stream: "codex_app_server.guardian",
1044
- data: {
1045
- method: "autoApprovalReview/strictReviewRequired",
1046
- phase: "strict_review_required",
1047
- threadId: readStringField(params, "threadId") ?? this.activeGuardianReview?.threadId ?? this.threadId,
1048
- turnId: readStringField(params, "turnId") ?? this.activeGuardianReview?.turnId ?? this.turnId,
1049
- reviewId: this.activeGuardianReview?.reviewId,
1050
- targetItemId: this.activeGuardianReview?.targetItemId,
1051
- command: this.activeGuardianReview?.command,
1052
- startedAtMs: asFiniteNumber(params.startedAtMs)
1053
- }
1054
- });
1055
- }
1056
- handleHook(method, params) {
1057
- const run = isJsonObject(params.run) ? params.run : void 0;
1058
- if (!run) return;
1059
- const durationMs = asFiniteNumber(run.durationMs);
1060
- const entries = readHookOutputEntries(run.entries);
1061
- const hookTurnId = readNullableString$1(params, "turnId");
1062
- this.emitAgentEvent({
1063
- stream: "codex_app_server.hook",
1064
- data: {
1065
- phase: method === "hook/started" ? "started" : "completed",
1066
- threadId: this.threadId,
1067
- turnId: hookTurnId === void 0 ? this.turnId : hookTurnId,
1068
- hookRunId: readStringField(run, "id"),
1069
- eventName: readStringField(run, "eventName"),
1070
- handlerType: readStringField(run, "handlerType"),
1071
- executionMode: readStringField(run, "executionMode"),
1072
- scope: readStringField(run, "scope"),
1073
- source: readStringField(run, "source"),
1074
- sourcePath: readStringField(run, "sourcePath"),
1075
- status: readStringField(run, "status"),
1076
- statusMessage: readNullableString$1(run, "statusMessage"),
1077
- ...durationMs !== void 0 ? { durationMs } : {},
1078
- ...entries.length > 0 ? { entries } : {}
1079
- }
1080
- });
1081
- }
1082
- emitStandardItemEvent(params) {
1083
- const { item } = params;
1084
- if (!item) return;
1085
- const activity = item.type === "subAgentActivity";
1086
- if (activity && params.phase === "start") return;
1087
- const subagent = activity || item.type === "collabAgentToolCall";
1088
- const kind = subagent ? "tool" : itemKind(item);
1089
- if (!kind) return;
1090
- const name = subagent ? "subagents" : itemName(item);
1091
- const args = itemToolArgs(item);
1092
- const commandBearing = isCommandBearingToolItem(item, args);
1093
- const subagentStatus = readStringField(item, activity ? "kind" : "status");
1094
- const interaction = activity && subagentStatus === "interacted";
1095
- const status = subagent && subagentStatus === "interrupted" ? "failed" : activity ? subagentStatus === "completed" || interaction ? "completed" : "running" : params.phase === "start" ? "running" : itemStatus(item);
1096
- const meta = subagent ? [interaction ? "message sent" : activity ? subagentStatus : status, readStringField(item, activity ? "agentPath" : "tool")].filter(Boolean).join(": ") : itemMeta(item, this.toolProgress.toolProgressDetailMode());
1097
- const suppressChannelProgress = shouldSuppressChannelProgressForItem(item);
1098
- this.emitAgentEvent({
1099
- stream: "item",
1100
- data: {
1101
- itemId: activity && !interaction ? `subagent:${readStringField(item, "agentThreadId") ?? item.id}` : item.id,
1102
- phase: params.phase,
1103
- kind,
1104
- title: itemTitle(item),
1105
- status,
1106
- ...name ? { name } : {},
1107
- ...meta ? { meta } : {},
1108
- ...commandBearing ? { commandBearing: true } : {},
1109
- ...suppressChannelProgress ? { suppressChannelProgress: true } : {}
1110
- }
1111
- });
1112
- }
1113
- async emitSnapshotOnlyNativeToolProgress(params) {
1114
- const { item, activeItemIds, completedItemIds, isActive } = params;
1115
- if (!shouldSynthesizeToolProgressForItem(item) || !matchesCodexSnapshotTurn(item, this.turnId) || completedItemIds.has(item.id) || itemStatus(item) === "running") return;
1116
- if (!activeItemIds.has(item.id)) {
1117
- this.emitStandardItemEvent({
1118
- phase: "start",
1119
- item
1120
- });
1121
- await this.emitNormalizedToolItemEvent({
1122
- phase: "start",
1123
- item
1124
- });
1125
- }
1126
- if (!isActive()) return;
1127
- activeItemIds.delete(item.id);
1128
- this.emitStandardItemEvent({
1129
- phase: "end",
1130
- item
1131
- });
1132
- await this.emitNormalizedToolItemEvent({
1133
- phase: "result",
1134
- item
1135
- });
1136
- completedItemIds.add(item.id);
1137
- }
1138
- async emitNormalizedToolItemEvent(params) {
1139
- const projection = projectNormalizedToolItem({
1140
- ...params,
1141
- detailMode: this.toolProgress.toolProgressDetailMode()
1142
- });
1143
- if (!projection || !params.item) return;
1144
- const { item } = params;
1145
- const { name, status, args, meta, event } = projection;
1146
- const approvalReviewOutcome = params.phase === "result" ? this.toolTranscript.finalizeToolApprovalReviews(item.id) : void 0;
1147
- if (event && approvalReviewOutcome) event.data.approvalReviewOutcome = approvalReviewOutcome;
1148
- this.toolTranscript.recordTrajectoryEvent({
1149
- phase: params.phase,
1150
- item,
1151
- name,
1152
- args,
1153
- status
1154
- });
1155
- if (params.phase === "result") this.toolProgress.recordNativeToolError({
1156
- item,
1157
- name,
1158
- meta,
1159
- status
1160
- });
1161
- if (!event) {
1162
- if (params.phase === "result") {
1163
- this.toolTranscript.emitAfterToolCallObservation(item);
1164
- await this.onNativeToolResultRecorded?.();
1165
- }
1166
- return;
1167
- }
1168
- this.emitAgentEvent(event);
1169
- if (params.phase === "result") {
1170
- this.toolTranscript.emitAfterToolCallObservation(item);
1171
- await this.onNativeToolResultRecorded?.();
1172
- }
1173
- }
1174
- };
1175
- //#endregion
1176
- //#region extensions/codex/src/app-server/native-subagent-notification.ts
1177
- /**
1178
- * Extracts native Codex subagent completion notifications from trusted
1179
- * inter-agent commentary messages emitted by the app-server.
1180
- */
1181
- const CODEX_SUBAGENT_NOTIFICATION_START = "<subagent_notification>";
1182
- const CODEX_SUBAGENT_NOTIFICATION_END = "</subagent_notification>";
1183
- /** Extracts trusted subagent completion payloads from a Codex server notification. */
1184
- function extractCodexNativeSubagentCompletions(notification) {
1185
- const params = isJsonObject(notification.params) ? notification.params : void 0;
1186
- if (!params) return [];
1187
- const item = isJsonObject(params.item) ? params.item : void 0;
1188
- if (!item) return [];
1189
- const communication = readTrustedInterAgentCommunication(item);
1190
- const text = communication?.content;
1191
- if (typeof text !== "string" || !text) return [];
1192
- return extractCodexNativeSubagentCompletionsFromText(text).filter((completion) => completion.agentPath === communication?.author);
1193
- }
1194
- /** Parses one or more tagged subagent completion payloads from commentary text. */
1195
- function extractCodexNativeSubagentCompletionsFromText(text) {
1196
- const completions = [];
1197
- let cursor = 0;
1198
- while (cursor < text.length) {
1199
- const start = text.indexOf(CODEX_SUBAGENT_NOTIFICATION_START, cursor);
1200
- if (start < 0) break;
1201
- const bodyStart = start + 23;
1202
- const end = text.indexOf(CODEX_SUBAGENT_NOTIFICATION_END, bodyStart);
1203
- if (end < 0) break;
1204
- const parsed = parseCodexNativeSubagentNotificationBody(text.slice(bodyStart, end));
1205
- if (parsed) completions.push(parsed);
1206
- cursor = end + 24;
1207
- }
1208
- return completions;
1209
- }
1210
- const codexNativeSubagentNotifications = {
1211
- fromNotification: extractCodexNativeSubagentCompletions,
1212
- fromText: extractCodexNativeSubagentCompletionsFromText,
1213
- deliveredAgentPaths: readDeliveredNativeCompletionPaths
1214
- };
1215
- /** Reads native delivery receipts, leaving status and result ownership with the child lifecycle. */
1216
- function readDeliveredNativeCompletionPaths(notification) {
1217
- if (notification.method !== "rawResponseItem/completed") return [];
1218
- const params = isJsonObject(notification.params) ? notification.params : void 0;
1219
- const item = isJsonObject(params?.item) ? params.item : void 0;
1220
- if (!item || readStringField(item, "type") !== "agent_message") return extractCodexNativeSubagentCompletions(notification).map((completion) => completion.agentPath);
1221
- const author = readStringField(item, "author");
1222
- const recipient = readStringField(item, "recipient");
1223
- const content = item.content;
1224
- if (!author || !recipient || !Array.isArray(content) || content.length !== 1) return [];
1225
- const part = content[0];
1226
- if (!isJsonObject(part) || readStringField(part, "type") !== "input_text") return [];
1227
- return readStringField(part, "text")?.startsWith(`Message Type: FINAL_ANSWER\nTask name: ${recipient}\nSender: ${author}\nPayload:\n`) ? [author] : [];
1228
- }
1229
- function parseCodexNativeSubagentNotificationBody(body) {
1230
- let payload;
1231
- try {
1232
- payload = JSON.parse(body.trim());
1233
- } catch {
1234
- return;
1235
- }
1236
- if (!isJsonObject(payload)) return;
1237
- const agentPath = readStringField(payload, "agent_path")?.trim();
1238
- const status = isJsonObject(payload.status) ? payload.status : void 0;
1239
- if (!agentPath || !status) return;
1240
- const statusEntry = readCompletionStatus(status);
1241
- if (!statusEntry) return;
1242
- return {
1243
- agentPath,
1244
- status: statusEntry.status,
1245
- statusLabel: statusEntry.label,
1246
- result: statusEntry.result
1247
- };
1248
- }
1249
- function readCompletionStatus(status) {
1250
- for (const [rawKey, value] of Object.entries(status)) {
1251
- const mappedStatus = mapCompletionStatus(normalizeStatusKey(rawKey));
1252
- if (!mappedStatus) continue;
1253
- const result = stringifyResult(value, mappedStatus);
1254
- return {
1255
- status: mappedStatus,
1256
- label: mappedStatus === "succeeded" && result.kind === "no_final_assistant_message" ? "completed_without_final_message" : rawKey,
1257
- result: result.text
1258
- };
1259
- }
1260
- }
1261
- function mapCompletionStatus(value) {
1262
- if (value === "completed" || value === "succeeded" || value === "success") return "succeeded";
1263
- if (value === "cancelled" || value === "canceled" || value === "interrupted" || value === "shutdown") return "cancelled";
1264
- if (value === "failed" || value === "error" || value === "errored" || value === "systemerror" || value === "notfound") return "failed";
1265
- }
1266
- function stringifyResult(value, status) {
1267
- if (typeof value === "string") {
1268
- const text = value.trim();
1269
- if (text) return { text };
1270
- return status === "succeeded" ? completedWithoutFinalAssistantMessage() : { text: "(no output)" };
1271
- }
1272
- if (value === null || value === void 0) return status === "succeeded" ? completedWithoutFinalAssistantMessage() : { text: "(no output)" };
1273
- try {
1274
- return { text: JSON.stringify(value) };
1275
- } catch {
1276
- return { text: "(unserializable output)" };
1277
- }
1278
- }
1279
- function completedWithoutFinalAssistantMessage() {
1280
- return {
1281
- text: "Subagent completed without a final assistant message.",
1282
- kind: "no_final_assistant_message"
1283
- };
1284
- }
1285
- function readTrustedInterAgentCommunication(item) {
1286
- if (readStringField(item, "type") !== "message" || readStringField(item, "role") !== "assistant" || readStringField(item, "phase") !== "commentary") return;
1287
- const text = extractSingleTextPart(item);
1288
- if (!text) return;
1289
- let parsed;
1290
- try {
1291
- parsed = JSON.parse(text);
1292
- } catch {
1293
- return;
1294
- }
1295
- if (!isJsonObject(parsed)) return;
1296
- if (typeof parsed.author !== "string" || typeof parsed.recipient !== "string" || typeof parsed.content !== "string" || parsed.trigger_turn !== false) return;
1297
- return parsed;
1298
- }
1299
- function extractSingleTextPart(item) {
1300
- const content = item.content;
1301
- if (!Array.isArray(content) || content.length !== 1) return;
1302
- const [entry] = content;
1303
- if (!isJsonObject(entry)) return;
1304
- const type = readStringField(entry, "type");
1305
- if (type !== "output_text" && type !== "text") return;
1306
- return readStringField(entry, "text")?.trim();
1307
- }
1308
- function normalizeStatusKey(value) {
1309
- return value.replace(/[^a-z0-9]/giu, "").toLowerCase();
1310
- }
1311
- //#endregion
1312
- //#region extensions/codex/src/app-server/native-subagent-task-mirror.ts
1313
- /** Projects Codex thread and collab-agent notifications into task lifecycle updates. */
1314
- var CodexNativeSubagentTaskMirror = class {
1315
- constructor(params, runtime) {
1316
- this.params = params;
1317
- this.runtime = runtime;
1318
- this.mirrorStateByThreadId = /* @__PURE__ */ new Map();
1319
- this.terminalRunIds = /* @__PURE__ */ new Set();
1320
- this.authoritativeRunIds = /* @__PURE__ */ new Set();
1321
- this.expectedAuthoritativeRunIds = /* @__PURE__ */ new Set();
1322
- this.now = params.now ?? Date.now;
1323
- }
1324
- markAuthoritativeCompletion(childThreadId) {
1325
- const runId = codexNativeSubagentRunId(childThreadId);
1326
- this.authoritativeRunIds.add(runId);
1327
- this.terminalRunIds.add(runId);
1328
- }
1329
- markAuthoritativeCompletionExpected(childThreadId) {
1330
- this.expectedAuthoritativeRunIds.add(codexNativeSubagentRunId(childThreadId));
1331
- }
1332
- handleNotification(notification) {
1333
- const params = isJsonObject(notification.params) ? notification.params : void 0;
1334
- if (!params) return;
1335
- if (notification.method === "thread/started") {
1336
- this.handleThreadStarted(params);
1337
- return;
1338
- }
1339
- if (notification.method === "thread/status/changed") {
1340
- this.handleThreadStatusChanged(params);
1341
- return;
1342
- }
1343
- if (notification.method === "item/started" || notification.method === "item/completed") {
1344
- const item = isJsonObject(params.item) ? params.item : void 0;
1345
- if (notification.method === "item/completed" && item && readStringField(item, "type") === "subAgentActivity") {
1346
- this.handleSubagentActivityItem(params);
1347
- return;
1348
- }
1349
- this.handleCollabAgentItem(params);
1350
- }
1351
- }
1352
- handleThreadStarted(params) {
1353
- const notification = readThreadStartedNotification(params);
1354
- if (!notification) return;
1355
- const thread = notification.thread;
1356
- const spawn = readSubagentThreadSpawnSource(thread.source, this.params.parentThreadId);
1357
- if (!spawn) return;
1358
- const threadId = thread.id.trim();
1359
- const label = normalizeOptionalString(spawn.agent_nickname) ?? normalizeOptionalString(thread.agentNickname) ?? normalizeOptionalString(spawn.agent_role) ?? normalizeOptionalString(thread.agentRole) ?? "Subagent";
1360
- const task = normalizeOptionalString(thread.preview) ?? `Subagent${label === "Subagent" ? "" : ` ${label}`}`;
1361
- const createdAt = secondsToMillis(thread.createdAt) ?? this.now();
1362
- if (!this.createRunningTask({
1363
- threadId,
1364
- label,
1365
- task,
1366
- startedAt: createdAt,
1367
- progressSummary: "Subagent started."
1368
- })) return;
1369
- this.applyStatus(threadId, thread.status);
1370
- }
1371
- handleThreadStatusChanged(params) {
1372
- const notification = readThreadStatusChangedNotification(params);
1373
- if (!notification) return;
1374
- this.applyStatus(notification.threadId, notification.status);
1375
- }
1376
- applyStatus(threadId, status) {
1377
- if (this.mirrorStateByThreadId.get(threadId) === "failed") return;
1378
- const statusType = status?.type;
1379
- if (!statusType) return;
1380
- const runId = codexNativeSubagentRunId(threadId);
1381
- if (this.authoritativeRunIds.has(runId)) return;
1382
- if (this.terminalRunIds.has(runId) && statusType !== "systemError") return;
1383
- const eventAt = this.now();
1384
- if (statusType === "active") {
1385
- this.runtime.recordTaskRunProgressByRunId({
1386
- runId,
1387
- lastEventAt: eventAt,
1388
- progressSummary: "Subagent is active."
1389
- });
1390
- return;
1391
- }
1392
- if (statusType === "idle") {
1393
- this.runtime.recordTaskRunProgressByRunId({
1394
- runId,
1395
- lastEventAt: eventAt,
1396
- progressSummary: "Subagent is idle."
1397
- });
1398
- return;
1399
- }
1400
- if (statusType === "systemError") {
1401
- if (this.expectedAuthoritativeRunIds.has(runId)) {
1402
- this.terminalRunIds.delete(runId);
1403
- this.runtime.recordTaskRunProgressByRunId({
1404
- runId,
1405
- lastEventAt: eventAt,
1406
- progressSummary: "Subagent hit a system error; awaiting recovery."
1407
- });
1408
- return;
1409
- }
1410
- this.terminalRunIds.add(runId);
1411
- this.runtime.finalizeTaskRunByRunId({
1412
- runId,
1413
- status: "failed",
1414
- endedAt: eventAt,
1415
- lastEventAt: eventAt,
1416
- error: "Subagent encountered a system error.",
1417
- progressSummary: "Subagent hit a system error.",
1418
- terminalSummary: "Subagent failed."
1419
- });
1420
- return;
1421
- }
1422
- if (statusType === "notLoaded") this.runtime.recordTaskRunProgressByRunId({
1423
- runId,
1424
- lastEventAt: eventAt,
1425
- progressSummary: "Subagent is not loaded."
1426
- });
1427
- }
1428
- handleCollabAgentItem(params) {
1429
- const item = isJsonObject(params.item) ? params.item : void 0;
1430
- if (!item || readStringField(item, "type") !== "collabAgentToolCall") return;
1431
- if ((readStringField(item, "senderThreadId") ?? readStringField(params, "threadId")) !== this.params.parentThreadId) return;
1432
- const isSpawnAgentTool = normalizeToolName(readStringField(item, "tool")) === "spawnagent";
1433
- const receiverThreadIds = readStringArray$1(item.receiverThreadIds);
1434
- const agentsStates = readAgentsStates(item.agentsStates);
1435
- const spawnChildThreadIds = /* @__PURE__ */ new Set([...receiverThreadIds, ...agentsStates.keys()]);
1436
- if (isSpawnAgentTool) for (const childThreadId of spawnChildThreadIds) this.createTaskFromCollabSpawnItem(childThreadId, item);
1437
- const toolCallStatus = normalizeCollabToolCallStatus(readStringField(item, "status"));
1438
- const terminalToolCallThreadIds = /* @__PURE__ */ new Set();
1439
- if (isSpawnAgentTool && isBlockedOrFailedCollabToolCallStatus(toolCallStatus)) {
1440
- for (const threadId of spawnChildThreadIds) terminalToolCallThreadIds.add(threadId);
1441
- for (const threadId of agentsStates.keys()) terminalToolCallThreadIds.add(threadId);
1442
- }
1443
- const terminalAgentStateThreadIds = /* @__PURE__ */ new Set();
1444
- for (const [threadId, state] of agentsStates) {
1445
- const normalizedStatus = normalizeAgentStateStatus(state.status);
1446
- if (terminalToolCallThreadIds.has(threadId) && isNonTerminalAgentStateStatus(normalizedStatus)) continue;
1447
- this.applyCollabAgentStatus(threadId, normalizedStatus, state.message);
1448
- if (isTerminalAgentStateStatus(normalizedStatus)) terminalAgentStateThreadIds.add(threadId);
1449
- }
1450
- if (isBlockedOrFailedCollabToolCallStatus(toolCallStatus)) for (const threadId of terminalToolCallThreadIds) {
1451
- if (terminalAgentStateThreadIds.has(threadId)) continue;
1452
- const state = agentsStates.get(threadId);
1453
- this.applyCollabAgentStatus(threadId, toolCallStatus, state?.message);
1454
- }
1455
- }
1456
- handleSubagentActivityItem(params) {
1457
- const item = isJsonObject(params.item) ? params.item : void 0;
1458
- if (!item || readStringField(item, "type") !== "subAgentActivity" || readStringField(params, "threadId") !== this.params.parentThreadId) return;
1459
- const threadId = normalizeOptionalString(readStringField(item, "agentThreadId"));
1460
- const kind = normalizeSubagentActivityKind(readStringField(item, "kind"));
1461
- if (!threadId || !kind) return;
1462
- if (kind === "started") {
1463
- this.createTaskFromSubagentActivity(threadId, normalizeOptionalString(readStringField(item, "agentPath")));
1464
- return;
1465
- }
1466
- if (this.mirrorStateByThreadId.get(threadId) !== "mirrored") return;
1467
- const message = kind === "interacted" ? "Subagent received more input." : "Subagent was interrupted.";
1468
- this.applyCollabAgentStatus(threadId, kind === "interacted" ? "running" : "interrupted", message);
1469
- }
1470
- createTaskFromSubagentActivity(threadId, agentPath) {
1471
- const eventAt = this.now();
1472
- this.createRunningTask({
1473
- threadId,
1474
- label: "Subagent",
1475
- task: agentPath ? `Subagent ${agentPath}` : "Subagent",
1476
- startedAt: eventAt,
1477
- progressSummary: "Subagent started."
1478
- });
1479
- }
1480
- createTaskFromCollabSpawnItem(threadId, item) {
1481
- const prompt = normalizeOptionalString(readStringField(item, "prompt"));
1482
- const createdAt = this.now();
1483
- this.createRunningTask({
1484
- threadId,
1485
- label: "Subagent",
1486
- task: prompt ?? "Subagent",
1487
- startedAt: createdAt,
1488
- progressSummary: "Subagent spawned."
1489
- });
1490
- }
1491
- createRunningTask(params) {
1492
- const threadId = params.threadId.trim();
1493
- if (!threadId || this.mirrorStateByThreadId.get(threadId) === "mirrored") return false;
1494
- this.mirrorStateByThreadId.set(threadId, "mirrored");
1495
- const runId = codexNativeSubagentRunId(threadId);
1496
- const historyOwner = this.params.historyOwner;
1497
- const stampHistoryOwner = historyOwner && !this.runtime.listTaskRecords().some((task) => task.runId === runId);
1498
- if (!this.runtime.tryCreateRunningTaskRun({
1499
- sourceId: runId,
1500
- agentId: this.params.agentId,
1501
- runId,
1502
- label: params.label,
1503
- task: params.task,
1504
- notifyPolicy: "silent",
1505
- deliveryStatus: "not_applicable",
1506
- preferMetadata: true,
1507
- startedAt: params.startedAt,
1508
- lastEventAt: this.now(),
1509
- progressSummary: params.progressSummary,
1510
- ...stampHistoryOwner ? { detail: { nativeHistory: { ...historyOwner } } } : {}
1511
- })) {
1512
- this.mirrorStateByThreadId.set(threadId, "failed");
1513
- return false;
1514
- }
1515
- this.terminalRunIds.delete(runId);
1516
- this.authoritativeRunIds.delete(runId);
1517
- return true;
1518
- }
1519
- applyCollabAgentStatus(threadId, status, message) {
1520
- if (this.mirrorStateByThreadId.get(threadId) === "failed") return;
1521
- const normalizedStatus = normalizeAgentStateStatus(status);
1522
- if (!normalizedStatus) return;
1523
- const runId = codexNativeSubagentRunId(threadId);
1524
- if (this.authoritativeRunIds.has(runId)) return;
1525
- if (this.terminalRunIds.has(runId) && isNonTerminalAgentStateStatus(normalizedStatus)) return;
1526
- const eventAt = this.now();
1527
- if (isNonTerminalAgentStateStatus(normalizedStatus)) {
1528
- this.runtime.recordTaskRunProgressByRunId({
1529
- runId,
1530
- lastEventAt: eventAt,
1531
- progressSummary: normalizeOptionalString(message) ?? (normalizedStatus === "pendingInit" ? "Subagent is initializing." : normalizedStatus === "interrupted" ? "Subagent was interrupted." : "Subagent is running.")
1532
- });
1533
- return;
1534
- }
1535
- if (normalizedStatus === "completed") {
1536
- this.terminalRunIds.add(runId);
1537
- const summary = normalizeOptionalString(message) ?? "Subagent completed.";
1538
- if (this.expectedAuthoritativeRunIds.has(runId)) this.runtime.recordTaskRunProgressByRunId({
1539
- runId,
1540
- lastEventAt: eventAt,
1541
- progressSummary: summary
1542
- });
1543
- else this.runtime.finalizeTaskRunByRunId({
1544
- runId,
1545
- status: "succeeded",
1546
- endedAt: eventAt,
1547
- lastEventAt: eventAt,
1548
- progressSummary: summary,
1549
- terminalSummary: summary
1550
- });
1551
- return;
1552
- }
1553
- if (normalizedStatus === "blocked") {
1554
- this.terminalRunIds.add(runId);
1555
- this.runtime.finalizeTaskRunByRunId({
1556
- runId,
1557
- status: "succeeded",
1558
- endedAt: eventAt,
1559
- lastEventAt: eventAt,
1560
- progressSummary: normalizeOptionalString(message) ?? "Subagent blocked.",
1561
- terminalSummary: normalizeOptionalString(message) ?? "Subagent blocked.",
1562
- terminalOutcome: "blocked"
1563
- });
1564
- return;
1565
- }
1566
- this.terminalRunIds.add(runId);
1567
- this.runtime.finalizeTaskRunByRunId({
1568
- runId,
1569
- status: normalizedStatus === "shutdown" ? "cancelled" : "failed",
1570
- endedAt: eventAt,
1571
- lastEventAt: eventAt,
1572
- error: normalizeOptionalString(message) ?? `Subagent status: ${normalizedStatus}`,
1573
- progressSummary: normalizeOptionalString(message) ?? `Subagent ${normalizedStatus}.`,
1574
- terminalSummary: normalizeOptionalString(message) ?? "Subagent did not complete."
1575
- });
1576
- }
1577
- };
1578
- /** Converts a Codex child thread id into the OpenClaw task-runtime run id. */
1579
- function codexNativeSubagentRunId(threadId) {
1580
- return `${CODEX_NATIVE_SUBAGENT_RUN_ID_PREFIX}${threadId.trim()}`;
1581
- }
1582
- /** Reads a subagent thread-spawn source only when it belongs to the expected parent thread. */
1583
- function readSubagentThreadSpawnSource(source, parentThreadId) {
1584
- if (!source || typeof source !== "object" || !("subAgent" in source)) return;
1585
- const subAgent = source.subAgent;
1586
- if (!subAgent || typeof subAgent !== "object" || !("thread_spawn" in subAgent)) return;
1587
- const spawn = subAgent.thread_spawn;
1588
- if (!spawn || typeof spawn !== "object") return;
1589
- return spawn.parent_thread_id === parentThreadId ? spawn : void 0;
1590
- }
1591
- function readThreadStartedNotification(params) {
1592
- const thread = params.thread;
1593
- if (!isJsonObject(thread) || typeof thread.id !== "string") return;
1594
- return { thread };
1595
- }
1596
- function readThreadStatusChangedNotification(params) {
1597
- if (typeof params.threadId !== "string") return;
1598
- const status = params.status;
1599
- if (!isJsonObject(status) || !isCodexThreadStatusType(status.type)) return;
1600
- return {
1601
- threadId: params.threadId,
1602
- status
1603
- };
1604
- }
1605
- function isCodexThreadStatusType(value) {
1606
- return value === "notLoaded" || value === "idle" || value === "systemError" || value === "active";
1607
- }
1608
- function readAgentsStates(value) {
1609
- const states = /* @__PURE__ */ new Map();
1610
- if (!isJsonObject(value)) return states;
1611
- for (const [threadId, rawState] of Object.entries(value)) {
1612
- if (!isJsonObject(rawState)) continue;
1613
- const status = readStringField(rawState, "status");
1614
- const message = readNullableString(rawState, "message");
1615
- states.set(threadId, {
1616
- status,
1617
- message
1618
- });
1619
- }
1620
- return states;
1621
- }
1622
- function readStringArray$1(value) {
1623
- if (!Array.isArray(value)) return [];
1624
- return value.filter((entry) => typeof entry === "string" && entry.trim() !== "");
1625
- }
1626
- function readNullableString(value, key) {
1627
- const entry = value[key];
1628
- return typeof entry === "string" || entry === null ? entry : void 0;
1629
- }
1630
- function normalizeToolName(value) {
1631
- return value?.replace(/[^a-z0-9]/giu, "").toLowerCase();
1632
- }
1633
- function normalizeSubagentActivityKind(value) {
1634
- const key = value?.replace(/[^a-z]/giu, "").toLowerCase();
1635
- return key === "started" || key === "interacted" || key === "interrupted" ? key : void 0;
1636
- }
1637
- function normalizeCollabToolCallStatus(value) {
1638
- const key = value?.replace(/[^a-z0-9]/giu, "").toLowerCase();
1639
- if (key === "completed" || key === "succeeded" || key === "success") return "completed";
1640
- if (key === "failed" || key === "error" || key === "errored") return "failed";
1641
- if (key === "blocked" || key === "declined") return "blocked";
1642
- if (key === "inprogress" || key === "running") return "running";
1643
- return value?.trim();
1644
- }
1645
- function isBlockedOrFailedCollabToolCallStatus(value) {
1646
- return value === "failed" || value === "blocked";
1647
- }
1648
- function isNonTerminalAgentStateStatus(value) {
1649
- return value === "pendingInit" || value === "running" || value === "interrupted";
1650
- }
1651
- function isTerminalAgentStateStatus(value) {
1652
- return value !== void 0 && !isNonTerminalAgentStateStatus(value);
1653
- }
1654
- function normalizeAgentStateStatus(value) {
1655
- const key = value?.replace(/[^a-z0-9]/giu, "").toLowerCase();
1656
- if (!key) return;
1657
- if (key === "pendinginit") return "pendingInit";
1658
- if (key === "inprogress" || key === "running") return "running";
1659
- if (key === "completed" || key === "succeeded" || key === "success") return "completed";
1660
- if (key === "interrupted" || key === "cancelled" || key === "canceled" || key === "shutdown") return key === "shutdown" ? "shutdown" : "interrupted";
1661
- if (key === "failed" || key === "error" || key === "systemerror") return "failed";
1662
- if (key === "blocked" || key === "declined") return "blocked";
1663
- return value?.trim();
1664
- }
1665
- function secondsToMillis(value) {
1666
- if (typeof value !== "number" || !Number.isFinite(value)) return;
1667
- return value * 1e3;
1668
- }
1669
- //#endregion
1670
- //#region extensions/codex/src/app-server/native-subagent-monitor.ts
1671
- /**
1672
- * Mirrors Codex native subagent lifecycle and completion into OpenClaw task
1673
- * runtime records, with app-server history as the recovery source.
1674
- */
1675
- const DEFAULT_RECOVERY_POLL_DELAYS_MS = [
1676
- 2e3,
1677
- 5e3,
1678
- 1e4,
1679
- 15e3,
1680
- 3e4,
1681
- 6e4,
1682
- 12e4,
1683
- 3e5
1684
- ];
1685
- const DEFAULT_COMPLETION_DELIVERY_RETRY_DELAYS_MS = [
1686
- 5e3,
1687
- 15e3,
1688
- 3e4,
1689
- 6e4,
1690
- 12e4,
1691
- 3e5
1692
- ];
1693
- const RECENT_TERMINAL_TASK_RECONCILE_GRACE_MS = 6e4;
1694
- const THREAD_READ_TIMEOUT_MS = 3e4;
1695
- const NATIVE_SUBAGENT_NOTIFICATION_METHODS = /* @__PURE__ */ new Set([
1696
- "thread/started",
1697
- "thread/status/changed",
1698
- "turn/started",
1699
- "turn/completed",
1700
- "item/agentMessage/delta",
1701
- "item/reasoning/summaryTextDelta",
1702
- "item/started",
1703
- "item/completed",
1704
- "rawResponseItem/completed"
1705
- ]);
1706
- const RECOVERY_REVISION_NOTIFICATION_METHODS = /* @__PURE__ */ new Set([
1707
- "thread/started",
1708
- "thread/status/changed",
1709
- "turn/started",
1710
- "turn/completed"
1711
- ]);
1712
- const MAX_PENDING_DIRECT_SPAWN_EVIDENCE = 32;
1713
- const defaultRuntime = {
1714
- createAgentHarnessTaskRuntime,
1715
- deliverAgentHarnessTaskCompletion
1716
- };
1717
- const monitors = /* @__PURE__ */ new WeakMap();
1718
- const completionDeliveryOwners = /* @__PURE__ */ new Map();
1719
- function registerMonitor(params) {
1720
- let monitor = monitors.get(params.client);
1721
- if (!monitor) {
1722
- const childThreadOwnership = /* @__PURE__ */ new Map();
1723
- const childThreadTransitions = new KeyedAsyncQueue();
1724
- monitor = new Monitor(params.client, params.runtime ?? defaultRuntime, {
1725
- retainClient: params.retainClient,
1726
- retainParentThread: params.retainParentThread,
1727
- claimChildThread: (threadId) => childThreadTransitions.enqueue(threadId, async () => {
1728
- const ownership = await claimCodexAppServerLiveThread(params.client, threadId);
1729
- if (ownership) childThreadOwnership.set(threadId, ownership);
1730
- return ownership;
1731
- }),
1732
- retainChildThread: (threadId) => childThreadTransitions.enqueue(threadId, async () => {
1733
- const ownership = childThreadOwnership.get(threadId);
1734
- let retained = false;
1735
- try {
1736
- retained = await retainCodexAppServerLiveThread(params.client, threadId, ownership?.release);
1737
- return retained;
1738
- } finally {
1739
- if (!retained && ownership) await ownership.release(threadId);
1740
- if (childThreadOwnership.get(threadId) === ownership) childThreadOwnership.delete(threadId);
1741
- }
1742
- }),
1743
- releaseChildThread: (threadId) => childThreadTransitions.enqueue(threadId, async () => {
1744
- const ownership = childThreadOwnership.get(threadId);
1745
- if (ownership) {
1746
- await ownership.release(threadId);
1747
- if (childThreadOwnership.get(threadId) === ownership) childThreadOwnership.delete(threadId);
1748
- } else await releaseCodexAppServerLiveThread(params.client, threadId);
1749
- })
1750
- });
1751
- monitors.set(params.client, monitor);
1752
- }
1753
- return monitor.registerParent({
1754
- parentThreadId: params.parentThreadId,
1755
- requesterSessionKey: params.requesterSessionKey,
1756
- taskRuntimeScope: params.taskRuntimeScope,
1757
- historyOwner: params.historyOwner,
1758
- agentId: params.agentId,
1759
- claimDirectChild: params.claimDirectChild,
1760
- rejectPendingDirectChild: params.rejectPendingDirectChild,
1761
- onDirectChildAccepted: params.onDirectChildAccepted
1762
- });
1763
- }
1764
- var Monitor = class {
1765
- constructor(client, runtime = defaultRuntime, options = {}) {
1766
- this.client = client;
1767
- this.runtime = runtime;
1768
- this.parentStates = /* @__PURE__ */ new Map();
1769
- this.pendingDirectSpawnEvidence = /* @__PURE__ */ new Map();
1770
- this.retiredParentStates = /* @__PURE__ */ new WeakSet();
1771
- this.childStates = /* @__PURE__ */ new Map();
1772
- this.childThreadIdsByAgentPath = /* @__PURE__ */ new Map();
1773
- this.taskReconciliations = /* @__PURE__ */ new Map();
1774
- this.taskReconciliationTimers = /* @__PURE__ */ new Map();
1775
- this.threadStatusRevisions = /* @__PURE__ */ new Map();
1776
- this.parentThreadRetentions = /* @__PURE__ */ new Map();
1777
- this.disposed = false;
1778
- this.recoveryPollDelaysMs = options.recoveryPollDelaysMs ?? DEFAULT_RECOVERY_POLL_DELAYS_MS;
1779
- this.completionDeliveryRetryDelaysMs = options.completionDeliveryRetryDelaysMs ?? DEFAULT_COMPLETION_DELIVERY_RETRY_DELAYS_MS;
1780
- this.completionDeliveryMaxRetries = options.completionDeliveryMaxRetries ?? this.completionDeliveryRetryDelaysMs.length;
1781
- this.now = options.now ?? Date.now;
1782
- this.retainClient = options.retainClient;
1783
- this.retainParentThread = options.retainParentThread;
1784
- this.claimChildThread = options.claimChildThread;
1785
- this.retainChildThread = options.retainChildThread;
1786
- this.releaseChildThread = options.releaseChildThread;
1787
- this.removeNotificationHandler = client.addNotificationHandler(async (notification) => {
1788
- if (!NATIVE_SUBAGENT_NOTIFICATION_METHODS.has(notification.method)) return;
1789
- await this.handleNotification(notification);
1790
- });
1791
- this.removeCloseHandler = client.addCloseHandler(() => this.dispose());
1792
- }
1793
- dispose() {
1794
- if (this.disposed) return;
1795
- this.disposed = true;
1796
- this.removeNotificationHandler();
1797
- this.removeCloseHandler();
1798
- for (const timer of this.taskReconciliationTimers.values()) clearTimeout(timer);
1799
- this.taskReconciliationTimers.clear();
1800
- for (const childState of this.childStates.values()) {
1801
- this.releaseDirectChild(childState);
1802
- if (childState.terminal && childState.pendingCompletion) {
1803
- this.clearRecoveryTimers(childState);
1804
- continue;
1805
- }
1806
- this.unregisterChild(childState);
1807
- }
1808
- this.releaseRetainedClient();
1809
- for (const release of this.parentThreadRetentions.values()) release();
1810
- this.parentThreadRetentions.clear();
1811
- for (const state of this.parentStates.values()) {
1812
- state.owners.clear();
1813
- state.turnIds.clear();
1814
- this.deliverDetachedCompletions(state);
1815
- }
1816
- this.pendingDirectSpawnEvidence.clear();
1817
- for (const [parentThreadId] of this.parentStates) if (![...this.childStates.values()].some((childState) => childState.parentThreadId === parentThreadId)) this.parentStates.delete(parentThreadId);
1818
- }
1819
- registerParent(params) {
1820
- const parentThreadId = params.parentThreadId.trim();
1821
- if (!parentThreadId) throw new Error("Codex native subagent monitor requires a parent thread id");
1822
- if (this.disposed) throw new Error("Codex native subagent monitor is closed");
1823
- let state = this.parentStates.get(parentThreadId);
1824
- if (state?.requesterSessionKey && params.requesterSessionKey && state.requesterSessionKey !== params.requesterSessionKey) throw new Error(`Codex thread ${parentThreadId} is already bound to another session`);
1825
- if (!state) {
1826
- state = {
1827
- parentThreadId,
1828
- owners: /* @__PURE__ */ new Map(),
1829
- turnIds: /* @__PURE__ */ new Set(),
1830
- nativeCompletionReceipts: /* @__PURE__ */ new Set()
1831
- };
1832
- this.parentStates.set(parentThreadId, state);
1833
- }
1834
- state.requesterSessionKey ??= params.requesterSessionKey;
1835
- state.taskRuntimeScope ??= params.taskRuntimeScope;
1836
- state.historyOwner ??= params.historyOwner;
1837
- state.agentId ??= params.agentId;
1838
- const owner = Symbol("codex-native-subagent-owner");
1839
- state.owners.set(owner, {
1840
- claimDirectChild: params.claimDirectChild,
1841
- rejectPendingDirectChild: params.rejectPendingDirectChild,
1842
- onDirectChildAccepted: params.onDirectChildAccepted
1843
- });
1844
- this.prepareParentTaskRuntime(state);
1845
- for (const childState of this.childStates.values()) if (childState.parentThreadId === parentThreadId && childState.pendingCompletion) this.deliverPendingCompletion(state, childState);
1846
- let registered = true;
1847
- const registeredState = state;
1848
- this.reconcileTaskRowsForParent(registeredState).catch((error) => {
1849
- embeddedAgentLog.warn("Failed to reconcile Codex native subagent task rows", {
1850
- parentThreadId,
1851
- error: formatErrorMessage(error)
1852
- });
1853
- });
1854
- return {
1855
- bindTurn: (turnIdInput) => {
1856
- const turnId = turnIdInput.trim();
1857
- if (!turnId || this.parentStates.get(parentThreadId) !== registeredState) return;
1858
- const current = registeredState.owners.get(owner);
1859
- if (!current || [...registeredState.owners.values()].some((other) => other !== current && other.turnId === turnId)) return;
1860
- current.turnId = turnId;
1861
- registeredState.turnIds.add(turnId);
1862
- this.drainPendingDirectSpawnEvidence(registeredState, current, turnId);
1863
- this.clearUnconsumablePendingDirectSpawnEvidence();
1864
- },
1865
- unregister: () => {
1866
- if (!registered) return;
1867
- registered = false;
1868
- const current = this.parentStates.get(parentThreadId);
1869
- if (current === registeredState) {
1870
- const turnId = current.owners.get(owner)?.turnId;
1871
- current.owners.delete(owner);
1872
- if (turnId) current.turnIds.delete(turnId);
1873
- if (current.owners.size === 0) {
1874
- current.turnIds.clear();
1875
- current.nativeCompletionReceipts = /* @__PURE__ */ new Set();
1876
- }
1877
- this.clearUnconsumablePendingDirectSpawnEvidence();
1878
- this.deliverDetachedCompletions(current);
1879
- this.pruneParentIfUnused(current);
1880
- }
1881
- }
1882
- };
1883
- }
1884
- retireParent(parentThreadIdInput) {
1885
- const parentThreadId = parentThreadIdInput.trim();
1886
- const state = this.parentStates.get(parentThreadId);
1887
- if (!state) return;
1888
- this.retiredParentStates.add(state);
1889
- state.owners.clear();
1890
- this.clearPendingDirectSpawnEvidenceForParent(parentThreadId);
1891
- for (const childState of Array.from(this.childStates.values())) if (childState.parentThreadId === parentThreadId) this.retireChild(state, childState, "Subagent parent session ended.");
1892
- if (this.parentStates.get(parentThreadId) === state) this.parentStates.delete(parentThreadId);
1893
- }
1894
- prepareParentTaskRuntime(state) {
1895
- if (!state.requesterSessionKey || !state.taskRuntimeScope) return;
1896
- state.taskRuntime ??= this.runtime.createAgentHarnessTaskRuntime({
1897
- runtime: CODEX_NATIVE_SUBAGENT_RUNTIME,
1898
- taskKind: CODEX_NATIVE_SUBAGENT_TASK_KIND,
1899
- scope: state.taskRuntimeScope,
1900
- runIdPrefix: CODEX_NATIVE_SUBAGENT_RUN_ID_PREFIX
1901
- });
1902
- state.mirror ??= new CodexNativeSubagentTaskMirror({
1903
- parentThreadId: state.parentThreadId,
1904
- requesterSessionKey: state.requesterSessionKey,
1905
- historyOwner: state.historyOwner,
1906
- agentId: state.agentId
1907
- }, state.taskRuntime);
1908
- }
1909
- /** Handles one notification from the client-wide router observer. */
1910
- async handleNotification(notification) {
1911
- if (this.disposed) return;
1912
- const state = this.resolveMirrorState(notification);
1913
- const params = isJsonObject(notification.params) ? notification.params : void 0;
1914
- const startedThread = isJsonObject(params?.thread) ? params.thread : void 0;
1915
- const threadId = readStringField(params, "threadId")?.trim() ?? readStringField(startedThread, "id")?.trim();
1916
- const threadStatus = isJsonObject(params?.status) ? normalizeIdentifier(readStringField(params.status, "type")) : void 0;
1917
- const parent = threadId ? this.parentStates.get(threadId) : void 0;
1918
- if (parent && parent.owners.size > 0 && notification.method === "turn/started") {
1919
- const turnId = isJsonObject(params?.turn) ? readStringField(params.turn, "id") : void 0;
1920
- if (turnId) parent.turnIds.add(turnId);
1921
- }
1922
- const tracksRecoveryRevision = Boolean(threadId && this.threadStatusRevisions.has(threadId));
1923
- if (RECOVERY_REVISION_NOTIFICATION_METHODS.has(notification.method) && threadId && tracksRecoveryRevision) this.threadStatusRevisions.get(threadId).value += 1;
1924
- if (!state && (!threadId || !this.parentStates.has(threadId) && !this.childStates.has(threadId) && !tracksRecoveryRevision)) return;
1925
- if (state?.mirror) try {
1926
- state.mirror.handleNotification(notification);
1927
- } catch (error) {
1928
- embeddedAgentLog.warn("Failed to mirror Codex native subagent lifecycle event", {
1929
- method: notification.method,
1930
- error: formatErrorMessage(error)
1931
- });
1932
- }
1933
- if (state) this.handleClosedChild(notification, state);
1934
- const childState = threadId ? this.childStates.get(threadId) : void 0;
1935
- if (notification.method === "turn/started" && childState) {
1936
- childState.nativeCompletionDelivered = false;
1937
- for (const key of childState.agentPathKeys) state?.nativeCompletionReceipts.delete(key);
1938
- this.resumeChild(childState);
1939
- }
1940
- if (parent && parent.turnIds.has(readStringField(params, "turnId") ?? "")) this.recordNativeCompletionDelivery(parent, notification);
1941
- if (childState && !childState.terminal) this.emitChildTaskActivity(notification, childState);
1942
- this.captureChildAssistantMessage(notification);
1943
- await this.handleChildTurnCompletion(notification);
1944
- if (notification.method === "thread/status/changed" && threadId && threadStatus) {
1945
- if (threadStatus !== "systemerror") {
1946
- if (childState) this.clearSystemErrorFallback(childState);
1947
- } else {
1948
- if (childState) {
1949
- this.resumeChild(childState, { scheduleRecovery: false });
1950
- this.setRecoveryFallback(childState, systemErrorFallbackCompletion(childState.childThreadId), this.now());
1951
- }
1952
- this.reconcileChildThread(threadId).catch((error) => {
1953
- this.logRecoveryFailure(threadId, error);
1954
- return false;
1955
- }).then((reconciled) => {
1956
- if (!reconciled && childState && this.childStates.get(threadId) === childState) this.scheduleRecoveryPoll(childState);
1957
- });
1958
- }
1959
- }
1960
- await this.handleCompletionNotification(notification);
1961
- }
1962
- emitChildTaskActivity(notification, childState) {
1963
- const params = isJsonObject(notification.params) ? notification.params : void 0;
1964
- if (!params) return;
1965
- const owner = {
1966
- runId: codexNativeSubagentRunId(childState.childThreadId),
1967
- ...childState.agentId ? { agentId: childState.agentId } : {}
1968
- };
1969
- if (notification.method === "item/agentMessage/delta") {
1970
- const delta = readStringField(params, "delta");
1971
- if (delta) emitAgentEvent({
1972
- ...owner,
1973
- stream: "assistant",
1974
- data: { delta }
1975
- });
1976
- return;
1977
- }
1978
- if (notification.method === "item/reasoning/summaryTextDelta") {
1979
- const delta = readStringField(params, "delta");
1980
- if (delta) emitAgentEvent({
1981
- ...owner,
1982
- stream: "thinking",
1983
- data: { delta }
1984
- });
1985
- return;
1986
- }
1987
- if (notification.method !== "item/started" && notification.method !== "item/completed") return;
1988
- const item = readItem(params.item);
1989
- if (item?.type === "agentMessage" && notification.method === "item/completed" && item.text) emitAgentEvent({
1990
- ...owner,
1991
- stream: "assistant",
1992
- data: { text: item.text }
1993
- });
1994
- const projection = projectNormalizedToolItem({
1995
- phase: notification.method === "item/started" ? "start" : "result",
1996
- item
1997
- });
1998
- if (projection?.event) emitAgentEvent({
1999
- ...owner,
2000
- ...projection.event
2001
- });
2002
- }
2003
- resumeChild(childState, options = {}) {
2004
- if (childState.terminal) return;
2005
- this.observeActiveChild(childState);
2006
- this.clearRecoveryTimers(childState);
2007
- childState.recoveryAttempt = 0;
2008
- if (options.scheduleRecovery !== false) this.scheduleRecoveryPoll(childState);
2009
- }
2010
- observeActiveChild(childState) {
2011
- childState.settledWithoutCompletion = false;
2012
- childState.fallbackCompletion = void 0;
2013
- this.releaseClientRetention ??= this.retainClient?.();
2014
- }
2015
- settleResumableChild(childState) {
2016
- if (childState.terminal) return;
2017
- childState.settledWithoutCompletion = true;
2018
- childState.fallbackCompletion = void 0;
2019
- this.releaseDirectChild(childState);
2020
- this.clearRecoveryTimers(childState);
2021
- this.releaseClientRetentionIfIdle();
2022
- }
2023
- captureChildAssistantMessage(notification) {
2024
- const params = isJsonObject(notification.params) ? notification.params : void 0;
2025
- const childThreadId = readStringField(params, "threadId")?.trim();
2026
- const childState = childThreadId ? this.childStates.get(childThreadId) : void 0;
2027
- if (!childState || childState.terminal) return;
2028
- if (notification.method === "item/agentMessage/delta") {
2029
- const turnId = readStringField(params, "turnId");
2030
- const itemId = readStringField(params, "itemId");
2031
- const delta = readStringField(params, "delta");
2032
- if (turnId && itemId && delta) this.recordChildAssistantMessage(childState, turnId, itemId, delta);
2033
- return;
2034
- }
2035
- if (notification.method !== "item/started" && notification.method !== "item/completed") return;
2036
- this.captureChildAssistantMessageItem(childState, readStringField(params, "turnId"), isJsonObject(params?.item) ? params.item : void 0);
2037
- }
2038
- captureChildAssistantMessageItem(childState, turnId, item) {
2039
- if (readStringField(item, "type") !== "agentMessage" || !turnId) return;
2040
- const itemId = readStringField(item, "id");
2041
- if (!itemId) return;
2042
- const messages = this.getChildAssistantMessages(childState, turnId);
2043
- if (readStringField(item, "phase") === "commentary") messages.commentaryIds.add(itemId);
2044
- else messages.finalMessageIds.add(itemId);
2045
- const text = readStringField(item, "text");
2046
- if (text) this.recordChildAssistantMessage(childState, turnId, itemId, text, { replace: true });
2047
- }
2048
- captureChildTurnAssistantMessages(childState, turn) {
2049
- const turnId = readStringField(turn, "id");
2050
- if (!turnId || !Array.isArray(turn.items)) return;
2051
- for (const item of turn.items) this.captureChildAssistantMessageItem(childState, turnId, isJsonObject(item) ? item : void 0);
2052
- }
2053
- recordChildAssistantMessage(childState, turnId, itemId, text, options = {}) {
2054
- const messages = this.getChildAssistantMessages(childState, turnId);
2055
- if (!messages.texts.has(itemId)) messages.order.push(itemId);
2056
- const existing = messages.texts.get(itemId) ?? "";
2057
- messages.texts.set(itemId, options.replace ? text : `${existing}${text}`);
2058
- }
2059
- getChildAssistantMessages(childState, turnId) {
2060
- let messages = childState.assistantMessagesByTurn.get(turnId);
2061
- if (!messages) {
2062
- messages = {
2063
- texts: /* @__PURE__ */ new Map(),
2064
- order: [],
2065
- commentaryIds: /* @__PURE__ */ new Set(),
2066
- finalMessageIds: /* @__PURE__ */ new Set()
2067
- };
2068
- childState.assistantMessagesByTurn.set(turnId, messages);
2069
- }
2070
- return messages;
2071
- }
2072
- async handleChildTurnCompletion(notification) {
2073
- if (notification.method !== "turn/completed") return;
2074
- const params = isJsonObject(notification.params) ? notification.params : void 0;
2075
- const childThreadId = readStringField(params, "threadId")?.trim();
2076
- const childState = childThreadId ? this.childStates.get(childThreadId) : void 0;
2077
- const state = childState ? this.parentStates.get(childState.parentThreadId) : void 0;
2078
- const turn = isJsonObject(params?.turn) ? params.turn : void 0;
2079
- if (!state || !childState || !turn || childState.terminal) return;
2080
- const turnId = readStringField(turn, "id");
2081
- const status = normalizeIdentifier(readStringField(turn, "status"));
2082
- if (status === "interrupted") {
2083
- this.removePendingDirectSpawnEvidenceForChild(childState.childThreadId);
2084
- this.rejectPendingDirectChild(state, childState.childThreadId, "Codex child turn interrupted");
2085
- if (turnId) childState.assistantMessagesByTurn.delete(turnId);
2086
- this.settleResumableChild(childState);
2087
- return;
2088
- }
2089
- if (status === "completed" || status === "failed") {
2090
- const revision = this.threadStatusRevisions.get(childState.childThreadId);
2091
- if (revision) revision.terminal = true;
2092
- this.rejectPendingDirectChild(state, childState.childThreadId, "Codex child turn completed");
2093
- this.releaseDirectChild(childState);
2094
- this.removePendingDirectSpawnEvidenceForChild(childState.childThreadId);
2095
- }
2096
- this.captureChildTurnAssistantMessages(childState, turn);
2097
- const completion = toChildTurnCompletion(childState, turn);
2098
- if (!completion) return;
2099
- await this.processObservedCompletion(state, childState, completion);
2100
- }
2101
- /** Reads one child through app-server history and delivers a terminal result when present. */
2102
- async reconcileChildThread(childThreadIdInput) {
2103
- const childState = this.childStates.get(childThreadIdInput.trim());
2104
- if (!childState || childState.terminal || this.disposed) return false;
2105
- if (childState.recoveryInFlight) return await childState.recoveryInFlight;
2106
- const recovery = this.reconcileChildState(childState);
2107
- childState.recoveryInFlight = recovery;
2108
- try {
2109
- return await recovery;
2110
- } finally {
2111
- if (childState.recoveryInFlight === recovery) childState.recoveryInFlight = void 0;
2112
- }
2113
- }
2114
- resolveMirrorState(notification) {
2115
- const params = isJsonObject(notification.params) ? notification.params : void 0;
2116
- if (!params) return;
2117
- if (notification.method === "thread/started") {
2118
- const thread = isJsonObject(params.thread) ? params.thread : void 0;
2119
- const parentThreadId = readThreadParentThreadId(thread);
2120
- const childThreadId = thread ? readStringField(thread, "id")?.trim() : void 0;
2121
- const agentPath = readStringField(readThreadSpawnSource(thread), "agent_path")?.trim();
2122
- const state = parentThreadId ? this.parentStates.get(parentThreadId) : void 0;
2123
- if (state && childThreadId && parentThreadId) return this.registerChildThread(state, childThreadId, agentPath === void 0 ? {} : { agentPath }) ? state : void 0;
2124
- return state;
2125
- }
2126
- if (notification.method === "thread/status/changed" || notification.method === "turn/started" || notification.method === "turn/completed" || notification.method === "item/agentMessage/delta") {
2127
- const childThreadId = readStringField(params, "threadId")?.trim();
2128
- const parentThreadId = childThreadId ? this.childStates.get(childThreadId)?.parentThreadId : void 0;
2129
- return parentThreadId ? this.parentStates.get(parentThreadId) : void 0;
2130
- }
2131
- if (notification.method === "item/started" || notification.method === "item/completed") {
2132
- const item = isJsonObject(params.item) ? params.item : void 0;
2133
- const parentThreadId = item ? (readStringField(item, "senderThreadId") ?? readStringField(params, "threadId"))?.trim() : void 0;
2134
- const state = parentThreadId ? this.parentStates.get(parentThreadId) : void 0;
2135
- if (state && parentThreadId) {
2136
- const turnId = readStringField(params, "turnId");
2137
- const owner = this.resolveParentOwner(state, turnId);
2138
- if (notification.method === "item/completed" && readStringField(item, "type") === "subAgentActivity" && normalizeIdentifier(readStringField(item, "kind")) === "started") {
2139
- const childThreadId = readStringField(item, "agentThreadId")?.trim();
2140
- const agentPath = readStringField(item, "agentPath");
2141
- if (childThreadId) this.registerDirectSpawnChild(state, turnId, {
2142
- parentThreadId,
2143
- childThreadId,
2144
- ...agentPath === void 0 ? {} : { agentPath }
2145
- }, owner);
2146
- return state;
2147
- }
2148
- const isCompletedSpawnAgentTool = notification.method === "item/completed" && readStringField(item, "type") === "collabAgentToolCall" && normalizeIdentifier(readStringField(item, "tool")) === "spawnagent" && normalizeIdentifier(readStringField(item, "status")) === "completed";
2149
- if (normalizeIdentifier(readStringField(item, "tool")) === "closeagent") return state;
2150
- const childThreadIds = new Set(readStringArray(item?.receiverThreadIds));
2151
- let accepted = true;
2152
- for (const childThreadId of childThreadIds) accepted = Boolean(isCompletedSpawnAgentTool ? this.registerDirectSpawnChild(state, turnId, {
2153
- parentThreadId,
2154
- childThreadId
2155
- }, owner) : this.registerChildThread(state, childThreadId)) && accepted;
2156
- if (!accepted) return;
2157
- }
2158
- return state;
2159
- }
2160
- }
2161
- handleClosedChild(notification, state) {
2162
- if (notification.method !== "item/completed") return;
2163
- const params = isJsonObject(notification.params) ? notification.params : void 0;
2164
- const item = isJsonObject(params?.item) ? params.item : void 0;
2165
- if (readStringField(item, "type") !== "collabAgentToolCall" || normalizeIdentifier(readStringField(item, "tool")) !== "closeagent" || normalizeIdentifier(readStringField(item, "status")) !== "completed") return;
2166
- const childThreadIds = /* @__PURE__ */ new Set([...readStringArray(item?.receiverThreadIds), ...readObjectStringKeys(item?.agentsStates)]);
2167
- for (const childThreadId of childThreadIds) {
2168
- const childState = this.childStates.get(childThreadId);
2169
- if (childState && childState.parentThreadId !== state.parentThreadId) continue;
2170
- if (childState) this.retireChild(state, childState, "Subagent was closed.");
2171
- else this.updateChildThreadOwnership("release", childThreadId, this.releaseChildThread);
2172
- }
2173
- }
2174
- retireChild(state, childState, summary) {
2175
- if (!childState.terminal) {
2176
- childState.terminal = true;
2177
- const revision = this.threadStatusRevisions.get(childState.childThreadId);
2178
- if (revision) revision.terminal = true;
2179
- const eventAt = this.now();
2180
- state.mirror?.markAuthoritativeCompletion(childState.childThreadId);
2181
- state.taskRuntime?.finalizeTaskRunByRunId({
2182
- runId: codexNativeSubagentRunId(childState.childThreadId),
2183
- status: "cancelled",
2184
- endedAt: eventAt,
2185
- lastEventAt: eventAt,
2186
- error: summary,
2187
- progressSummary: summary,
2188
- terminalSummary: summary
2189
- });
2190
- }
2191
- if (childState.pendingCompletion) {
2192
- childState.pendingCompletion = void 0;
2193
- state.taskRuntime?.setDetachedTaskDeliveryStatusByRunId({
2194
- runId: codexNativeSubagentRunId(childState.childThreadId),
2195
- deliveryStatus: "failed",
2196
- error: summary
2197
- });
2198
- }
2199
- this.unregisterChild(childState, { retainSubscription: false });
2200
- this.updateChildThreadOwnership("release", childState.childThreadId, this.releaseChildThread);
2201
- }
2202
- async handleCompletionNotification(notification) {
2203
- const params = isJsonObject(notification.params) ? notification.params : void 0;
2204
- const parentThreadId = params ? readStringField(params, "threadId")?.trim() : void 0;
2205
- const state = parentThreadId ? this.parentStates.get(parentThreadId) : void 0;
2206
- if (!state) return;
2207
- for (const nativeCompletion of codexNativeSubagentNotifications.fromNotification(notification)) {
2208
- const childThreadId = this.childThreadIdsByAgentPath.get(buildParentAgentPathKey(state.parentThreadId, nativeCompletion.agentPath));
2209
- const childState = childThreadId ? this.childStates.get(childThreadId) : void 0;
2210
- if (!childState || childState.parentThreadId !== state.parentThreadId || childState.terminal) {
2211
- embeddedAgentLog.warn("Ignoring Codex native subagent completion for unknown child thread", {
2212
- parentThreadId: state.parentThreadId,
2213
- agentPath: nativeCompletion.agentPath
2214
- });
2215
- continue;
2216
- }
2217
- const completion = {
2218
- childThreadId: childState.childThreadId,
2219
- status: nativeCompletion.status,
2220
- statusLabel: nativeCompletion.statusLabel,
2221
- result: nativeCompletion.result
2222
- };
2223
- await this.processObservedCompletion(state, childState, completion);
2224
- }
2225
- }
2226
- async processObservedCompletion(state, childState, completion) {
2227
- if (!isNoFinalCompletion(completion)) {
2228
- await this.processCompletion(state, childState, completion);
2229
- return;
2230
- }
2231
- this.resumeChild(childState, { scheduleRecovery: false });
2232
- this.setRecoveryFallback(childState, completion, this.now());
2233
- await this.reconcileChildThread(childState.childThreadId).catch((error) => {
2234
- this.logRecoveryFailure(childState.childThreadId, error);
2235
- return false;
2236
- });
2237
- }
2238
- async reconcileChildState(childState) {
2239
- const state = this.parentStates.get(childState.parentThreadId);
2240
- if (!state) return false;
2241
- const statusRead = this.retainThreadStatusRevision(childState.childThreadId);
2242
- try {
2243
- const recovery = await this.readThreadRecovery(childState.childThreadId);
2244
- if (!statusRead.isCurrent() || this.childStates.get(childState.childThreadId) !== childState) return false;
2245
- if (recovery.parentThreadId && recovery.parentThreadId !== childState.parentThreadId) {
2246
- embeddedAgentLog.warn("Codex native subagent parent did not match monitor state", {
2247
- childThreadId: childState.childThreadId,
2248
- expectedParentThreadId: childState.parentThreadId,
2249
- actualParentThreadId: recovery.parentThreadId
2250
- });
2251
- this.unregisterChild(childState);
2252
- return false;
2253
- }
2254
- if (recovery.agentPath) this.registerAgentPath(childState, recovery.agentPath);
2255
- if (recovery.threadState === "active") {
2256
- this.observeActiveChild(childState);
2257
- return false;
2258
- }
2259
- if (recovery.threadState === "other") this.clearSystemErrorFallback(childState);
2260
- if (recovery.resumable) {
2261
- this.settleResumableChild(childState);
2262
- return false;
2263
- }
2264
- const completion = recovery.completion;
2265
- if (!completion) {
2266
- if (recovery.fallbackCompletion) this.setRecoveryFallback(childState, recovery.fallbackCompletion, recovery.fallbackCompletion.completedAt ?? this.now());
2267
- return false;
2268
- }
2269
- if (isNoFinalCompletion(completion)) {
2270
- this.setRecoveryFallback(childState, completion, completion.completedAt ?? this.now());
2271
- return false;
2272
- }
2273
- await this.processCompletion(state, childState, completion, completion.completedAt);
2274
- return true;
2275
- } finally {
2276
- statusRead.release();
2277
- }
2278
- }
2279
- requestThreadRead(childThreadId, includeTurns) {
2280
- return this.client.request("thread/read", {
2281
- threadId: childThreadId,
2282
- includeTurns
2283
- }, { timeoutMs: THREAD_READ_TIMEOUT_MS });
2284
- }
2285
- requestLatestThreadTurn(childThreadId) {
2286
- return this.client.request("thread/turns/list", {
2287
- threadId: childThreadId,
2288
- limit: 1,
2289
- sortDirection: "desc",
2290
- itemsView: "full"
2291
- }, { timeoutMs: THREAD_READ_TIMEOUT_MS });
2292
- }
2293
- async readThreadRecovery(childThreadId) {
2294
- const response = await this.requestThreadRead(childThreadId, true).catch(() => this.requestThreadRead(childThreadId, false));
2295
- const thread = isJsonObject(response.thread) ? response.thread : void 0;
2296
- if (!thread || readStringField(thread, "id")?.trim() !== childThreadId) return {
2297
- resumable: false,
2298
- threadState: "unavailable"
2299
- };
2300
- const threadStatus = isJsonObject(thread.status) ? normalizeIdentifier(readStringField(thread.status, "type")) : void 0;
2301
- let completion;
2302
- let fallbackCompletion;
2303
- let resumable = false;
2304
- let threadState = threadStatus === "active" ? "active" : threadStatus === "systemerror" ? "system_error" : threadStatus ? "other" : "unavailable";
2305
- if (threadStatus === "systemerror") {
2306
- const turnsResponse = await this.requestLatestThreadTurn(childThreadId).catch(() => void 0);
2307
- const data = isJsonObject(turnsResponse) && Array.isArray(turnsResponse.data) ? turnsResponse.data : [];
2308
- const latestTurn = isJsonObject(data[0]) ? data[0] : void 0;
2309
- const latestTurnStatus = normalizeIdentifier(readStringField(latestTurn, "status"));
2310
- completion = latestTurn && latestTurnStatus === "failed" ? readTurnCompletion(latestTurn, childThreadId) : void 0;
2311
- if (latestTurnStatus === "inprogress") threadState = "active";
2312
- else if (!completion) fallbackCompletion = systemErrorFallbackCompletion(childThreadId);
2313
- } else if (threadStatus !== "active") {
2314
- const turnRecovery = readThreadTurnRecovery(thread, childThreadId);
2315
- completion = turnRecovery.completion;
2316
- resumable = turnRecovery.resumable;
2317
- }
2318
- return {
2319
- parentThreadId: readThreadParentThreadId(thread),
2320
- agentPath: normalizeOptionalString(readStringField(readThreadSpawnSource(thread), "agent_path")),
2321
- completion,
2322
- fallbackCompletion,
2323
- resumable,
2324
- threadState
2325
- };
2326
- }
2327
- async processCompletion(state, childState, completion, eventAt = this.now()) {
2328
- if (childState.terminal) return;
2329
- if (!this.claimCompletionDelivery(state, childState)) {
2330
- this.unregisterChild(childState);
2331
- return;
2332
- }
2333
- childState.terminal = true;
2334
- const revision = this.threadStatusRevisions.get(childState.childThreadId);
2335
- if (revision) revision.terminal = true;
2336
- this.releaseDirectChild(childState);
2337
- this.clearRecoveryTimers(childState);
2338
- state.mirror?.markAuthoritativeCompletion(completion.childThreadId);
2339
- state.taskRuntime?.finalizeTaskRunByRunId({
2340
- runId: codexNativeSubagentRunId(completion.childThreadId),
2341
- status: completion.status,
2342
- endedAt: eventAt,
2343
- lastEventAt: eventAt,
2344
- ...completion.status === "succeeded" ? {} : { error: completion.result },
2345
- progressSummary: completion.result,
2346
- terminalSummary: completion.result
2347
- });
2348
- if (!state.requesterSessionKey || !state.taskRuntimeScope) {
2349
- this.unregisterChild(childState);
2350
- return;
2351
- }
2352
- if (childState.nativeCompletionDelivered) {
2353
- this.finishCompletionDelivery(state, childState);
2354
- return;
2355
- }
2356
- childState.pendingCompletion = completion;
2357
- state.taskRuntime?.setDetachedTaskDeliveryStatusByRunId({
2358
- runId: codexNativeSubagentRunId(completion.childThreadId),
2359
- deliveryStatus: "pending"
2360
- });
2361
- this.releaseClientRetentionIfIdle();
2362
- await this.deliverPendingCompletion(state, childState);
2363
- }
2364
- async deliverPendingCompletion(state, childState) {
2365
- const completion = childState.pendingCompletion;
2366
- if (!completion || !state.requesterSessionKey || !state.taskRuntimeScope) return;
2367
- if (state.owners.size > 0) return;
2368
- if (childState.deliveringCompletion || childState.completionDeliveryTimer) return;
2369
- childState.deliveringCompletion = true;
2370
- try {
2371
- const delivery = await this.runtime.deliverAgentHarnessTaskCompletion({
2372
- scope: state.taskRuntimeScope,
2373
- childSessionKey: codexNativeSubagentRunId(completion.childThreadId),
2374
- childSessionId: completion.childThreadId,
2375
- announceId: `codex-native:${state.parentThreadId}:${completion.childThreadId}:${completion.status}`,
2376
- announceType: "Subagent",
2377
- taskLabel: "Subagent",
2378
- status: completion.status,
2379
- statusLabel: completion.statusLabel,
2380
- result: completion.result,
2381
- replyInstruction: "Use the Codex native subagent result to continue or wrap up the parent task. If this is a Discord/channel session, send the visible response with the message tool instead of only writing a transcript final answer. Reply in your normal assistant voice and do not expose internal notification markup."
2382
- });
2383
- if (this.childStates.get(childState.childThreadId) !== childState || this.parentStates.get(state.parentThreadId) !== state) return;
2384
- if (isDurableAgentHarnessCompletionDelivery(delivery)) {
2385
- this.finishCompletionDelivery(state, childState);
2386
- return;
2387
- }
2388
- const error = delivery.error ?? "completion delivery did not produce a parent response";
2389
- state.taskRuntime?.setDetachedTaskDeliveryStatusByRunId({
2390
- runId: codexNativeSubagentRunId(completion.childThreadId),
2391
- deliveryStatus: "pending",
2392
- error
2393
- });
2394
- this.scheduleCompletionDeliveryRetry(childState, error);
2395
- } catch (error) {
2396
- if (this.childStates.get(childState.childThreadId) !== childState || this.parentStates.get(state.parentThreadId) !== state) return;
2397
- const message = formatErrorMessage(error);
2398
- state.taskRuntime?.setDetachedTaskDeliveryStatusByRunId({
2399
- runId: codexNativeSubagentRunId(completion.childThreadId),
2400
- deliveryStatus: "pending",
2401
- error: message
2402
- });
2403
- this.scheduleCompletionDeliveryRetry(childState, message);
2404
- embeddedAgentLog.warn("Failed to deliver Codex native subagent completion", {
2405
- parentThreadId: state.parentThreadId,
2406
- childThreadId: completion.childThreadId,
2407
- error: message
2408
- });
2409
- } finally {
2410
- childState.deliveringCompletion = false;
2411
- }
2412
- }
2413
- recordNativeCompletionDelivery(state, notification) {
2414
- for (const agentPath of codexNativeSubagentNotifications.deliveredAgentPaths(notification)) {
2415
- const key = buildParentAgentPathKey(state.parentThreadId, agentPath);
2416
- state.nativeCompletionReceipts.add(key);
2417
- const childThreadId = this.childThreadIdsByAgentPath.get(key);
2418
- const child = childThreadId ? this.childStates.get(childThreadId) : void 0;
2419
- if (!child || child.parentThreadId !== state.parentThreadId) continue;
2420
- child.nativeCompletionDelivered = true;
2421
- if (child.pendingCompletion && !child.deliveringCompletion) this.finishCompletionDelivery(state, child);
2422
- }
2423
- }
2424
- finishCompletionDelivery(state, child) {
2425
- child.pendingCompletion = void 0;
2426
- child.completionDeliveryAttempt = 0;
2427
- state.taskRuntime?.setDetachedTaskDeliveryStatusByRunId({
2428
- runId: codexNativeSubagentRunId(child.childThreadId),
2429
- deliveryStatus: "delivered"
2430
- });
2431
- this.unregisterChild(child);
2432
- }
2433
- deliverDetachedCompletions(state) {
2434
- for (const child of this.childStates.values()) if (child.parentThreadId === state.parentThreadId && child.pendingCompletion) this.deliverPendingCompletion(state, child);
2435
- }
2436
- scheduleCompletionDeliveryRetry(childState, error) {
2437
- if (!childState.pendingCompletion || childState.completionDeliveryTimer || this.childStates.get(childState.childThreadId) !== childState) return;
2438
- if (childState.completionDeliveryAttempt >= this.completionDeliveryMaxRetries) {
2439
- this.parentStates.get(childState.parentThreadId)?.taskRuntime?.setDetachedTaskDeliveryStatusByRunId({
2440
- runId: codexNativeSubagentRunId(childState.childThreadId),
2441
- deliveryStatus: "failed",
2442
- error
2443
- });
2444
- this.unregisterChild(childState);
2445
- return;
2446
- }
2447
- const delayMs = delayForAttempt(this.completionDeliveryRetryDelaysMs, childState.completionDeliveryAttempt++);
2448
- childState.completionDeliveryTimer = setTimeout(() => {
2449
- childState.completionDeliveryTimer = void 0;
2450
- if (this.childStates.get(childState.childThreadId) !== childState) return;
2451
- const state = this.parentStates.get(childState.parentThreadId);
2452
- if (state) this.deliverPendingCompletion(state, childState);
2453
- }, delayMs);
2454
- unrefTimer(childState.completionDeliveryTimer);
2455
- }
2456
- registerChildThread(state, childThreadIdInput, options = {}) {
2457
- const parentThreadId = state.parentThreadId;
2458
- const childThreadId = childThreadIdInput.trim();
2459
- if (!parentThreadId || !childThreadId || this.disposed) return;
2460
- if (options.claimDirectChild && this.threadStatusRevisions.get(childThreadId)?.terminal) return;
2461
- let childState = this.childStates.get(childThreadId);
2462
- if (childState && childState.parentThreadId !== parentThreadId) {
2463
- embeddedAgentLog.warn("Ignoring Codex native subagent child reparenting", {
2464
- childThreadId,
2465
- existingParentThreadId: childState.parentThreadId,
2466
- attemptedParentThreadId: parentThreadId
2467
- });
2468
- return;
2469
- }
2470
- if (!childState) {
2471
- this.updateChildThreadOwnership("claim", childThreadId, this.claimChildThread);
2472
- this.releaseClientRetention ??= this.retainClient?.();
2473
- if (!this.parentThreadRetentions.has(parentThreadId)) {
2474
- const releaseParentThread = this.retainParentThread?.(parentThreadId);
2475
- if (releaseParentThread) this.parentThreadRetentions.set(parentThreadId, releaseParentThread);
2476
- }
2477
- childState = {
2478
- childThreadId,
2479
- parentThreadId,
2480
- agentId: state.agentId,
2481
- agentPathKeys: /* @__PURE__ */ new Set(),
2482
- assistantMessagesByTurn: /* @__PURE__ */ new Map(),
2483
- recoveryAttempt: 0,
2484
- terminal: false,
2485
- nativeCompletionDelivered: false,
2486
- settledWithoutCompletion: false,
2487
- completionDeliveryAttempt: 0,
2488
- deliveringCompletion: false
2489
- };
2490
- this.childStates.set(childThreadId, childState);
2491
- this.threadStatusRevisions.set(childThreadId, this.threadStatusRevisions.get(childThreadId) ?? {
2492
- value: 0,
2493
- readers: 0,
2494
- parentThreadId
2495
- });
2496
- }
2497
- if (options.claimDirectChild && !childState.terminal && !childState.settledWithoutCompletion && !childState.releaseDirectChild) childState.releaseDirectChild = options.claimDirectChild(childThreadId);
2498
- this.registerAgentPath(childState, childThreadId);
2499
- state.mirror?.markAuthoritativeCompletionExpected(childThreadId);
2500
- const agentPath = normalizeOptionalString(options.agentPath);
2501
- if (agentPath) this.registerAgentPath(childState, agentPath);
2502
- this.scheduleRecoveryPoll(childState);
2503
- return childState;
2504
- }
2505
- resolveParentOwner(state, turnIdInput) {
2506
- const turnId = turnIdInput?.trim();
2507
- if (!turnId) return;
2508
- const owners = [...state.owners.values()].filter((owner) => owner.turnId === turnId);
2509
- return owners.length === 1 ? owners[0] : void 0;
2510
- }
2511
- registerDirectSpawnChild(state, turnIdInput, evidence, owner) {
2512
- const childState = this.registerChildThread(state, evidence.childThreadId, {
2513
- ...evidence.agentPath === void 0 ? {} : { agentPath: evidence.agentPath },
2514
- ...owner?.claimDirectChild ? { claimDirectChild: owner.claimDirectChild } : {}
2515
- });
2516
- if (!owner) this.bufferPendingDirectSpawnEvidence(turnIdInput, evidence);
2517
- else if (childState) owner.onDirectChildAccepted?.();
2518
- return childState;
2519
- }
2520
- bufferPendingDirectSpawnEvidence(turnIdInput, evidence) {
2521
- const turnId = turnIdInput?.trim();
2522
- if (!turnId || !this.hasUnboundParentOwner(evidence.parentThreadId)) return;
2523
- const pending = this.pendingDirectSpawnEvidence.get(turnId) ?? [];
2524
- if (pending.some((candidate) => candidate.parentThreadId === evidence.parentThreadId && candidate.childThreadId === evidence.childThreadId && candidate.agentPath === evidence.agentPath) || [...this.pendingDirectSpawnEvidence.values()].reduce((count, entries) => count + entries.length, 0) >= MAX_PENDING_DIRECT_SPAWN_EVIDENCE) return;
2525
- pending.push(evidence);
2526
- this.pendingDirectSpawnEvidence.set(turnId, pending);
2527
- }
2528
- drainPendingDirectSpawnEvidence(state, owner, turnId) {
2529
- const pending = this.pendingDirectSpawnEvidence.get(turnId);
2530
- this.pendingDirectSpawnEvidence.delete(turnId);
2531
- if (!pending || !owner.claimDirectChild) return;
2532
- for (const evidence of pending) if (evidence.parentThreadId === state.parentThreadId) {
2533
- if (this.registerChildThread(state, evidence.childThreadId, {
2534
- ...evidence.agentPath === void 0 ? {} : { agentPath: evidence.agentPath },
2535
- claimDirectChild: owner.claimDirectChild
2536
- })) owner.onDirectChildAccepted?.();
2537
- }
2538
- }
2539
- hasUnboundParentOwner(parentThreadId) {
2540
- return [...parentThreadId ? [this.parentStates.get(parentThreadId)].filter((state) => Boolean(state)) : this.parentStates.values()].some((state) => [...state.owners.values()].some((owner) => owner.turnId === void 0));
2541
- }
2542
- clearUnconsumablePendingDirectSpawnEvidence() {
2543
- if (!this.hasUnboundParentOwner()) this.pendingDirectSpawnEvidence.clear();
2544
- }
2545
- clearPendingDirectSpawnEvidenceForParent(parentThreadId) {
2546
- this.filterPendingDirectSpawnEvidence((evidence) => evidence.parentThreadId !== parentThreadId);
2547
- }
2548
- removePendingDirectSpawnEvidenceForChild(childThreadId) {
2549
- this.filterPendingDirectSpawnEvidence((evidence) => evidence.childThreadId !== childThreadId);
2550
- }
2551
- filterPendingDirectSpawnEvidence(keep) {
2552
- for (const [turnId, pending] of this.pendingDirectSpawnEvidence) {
2553
- const remaining = pending.filter(keep);
2554
- if (remaining.length) this.pendingDirectSpawnEvidence.set(turnId, remaining);
2555
- else this.pendingDirectSpawnEvidence.delete(turnId);
2556
- }
2557
- }
2558
- registerAgentPath(childState, agentPath) {
2559
- const key = buildParentAgentPathKey(childState.parentThreadId, agentPath);
2560
- const existingChild = this.childThreadIdsByAgentPath.get(key);
2561
- if (existingChild && existingChild !== childState.childThreadId) {
2562
- embeddedAgentLog.warn("Ignoring conflicting Codex native subagent agent path", {
2563
- parentThreadId: childState.parentThreadId,
2564
- agentPath,
2565
- existingChildThreadId: existingChild,
2566
- attemptedChildThreadId: childState.childThreadId
2567
- });
2568
- return;
2569
- }
2570
- this.childThreadIdsByAgentPath.set(key, childState.childThreadId);
2571
- childState.agentPathKeys.add(key);
2572
- if (this.parentStates.get(childState.parentThreadId)?.nativeCompletionReceipts.has(key)) childState.nativeCompletionDelivered = true;
2573
- }
2574
- unregisterChild(childState, options = {}) {
2575
- this.releaseDirectChild(childState);
2576
- if (childState.terminal && options.retainSubscription !== false && !this.disposed) this.updateChildThreadOwnership("retain", childState.childThreadId, this.retainChildThread);
2577
- this.clearRecoveryTimers(childState);
2578
- if (childState.completionDeliveryTimer) clearTimeout(childState.completionDeliveryTimer);
2579
- const deliveryOwnerKey = childState.deliveryOwnerKey;
2580
- if (deliveryOwnerKey && completionDeliveryOwners.get(deliveryOwnerKey) === childState) completionDeliveryOwners.delete(deliveryOwnerKey);
2581
- childState.deliveryOwnerKey = void 0;
2582
- for (const key of childState.agentPathKeys) if (this.childThreadIdsByAgentPath.get(key) === childState.childThreadId) this.childThreadIdsByAgentPath.delete(key);
2583
- if (this.childStates.get(childState.childThreadId) === childState) this.childStates.delete(childState.childThreadId);
2584
- if (![...this.childStates.values()].some((remainingChild) => remainingChild.parentThreadId === childState.parentThreadId)) {
2585
- const releaseParentThread = this.parentThreadRetentions.get(childState.parentThreadId);
2586
- this.parentThreadRetentions.delete(childState.parentThreadId);
2587
- releaseParentThread?.();
2588
- }
2589
- this.collectThreadStatusRevision(childState.childThreadId);
2590
- this.releaseClientRetentionIfIdle();
2591
- const state = this.parentStates.get(childState.parentThreadId);
2592
- if (state) this.pruneParentIfUnused(state);
2593
- }
2594
- releaseDirectChild(childState) {
2595
- const release = childState.releaseDirectChild;
2596
- childState.releaseDirectChild = void 0;
2597
- release?.();
2598
- }
2599
- rejectPendingDirectChild(state, childThreadId, reason) {
2600
- for (const owner of state.owners.values()) owner.rejectPendingDirectChild?.(childThreadId, reason);
2601
- }
2602
- updateChildThreadOwnership(operation, childThreadId, update) {
2603
- if (!update) return;
2604
- update(childThreadId).catch((error) => {
2605
- embeddedAgentLog.warn("Failed to update Codex native subagent thread ownership", {
2606
- operation,
2607
- childThreadId,
2608
- error: formatErrorMessage(error)
2609
- });
2610
- });
2611
- }
2612
- releaseClientRetentionIfIdle() {
2613
- if ([...this.childStates.values()].some((childState) => !childState.terminal && !childState.settledWithoutCompletion)) return;
2614
- this.releaseRetainedClient();
2615
- }
2616
- releaseRetainedClient() {
2617
- const release = this.releaseClientRetention;
2618
- this.releaseClientRetention = void 0;
2619
- release?.();
2620
- }
2621
- claimCompletionDelivery(state, childState) {
2622
- const requesterSessionKey = state.requesterSessionKey?.trim();
2623
- if (!requesterSessionKey) return true;
2624
- const key = `${requesterSessionKey}\0${childState.childThreadId}`;
2625
- const owner = completionDeliveryOwners.get(key);
2626
- if (owner) return owner === childState;
2627
- const runId = codexNativeSubagentRunId(childState.childThreadId);
2628
- if (state.taskRuntime?.listTaskRecords().some((task) => task.runId === runId && task.deliveryStatus === "delivered")) return false;
2629
- completionDeliveryOwners.set(key, childState);
2630
- childState.deliveryOwnerKey = key;
2631
- return true;
2632
- }
2633
- pruneParentIfUnused(state) {
2634
- if (state.owners.size > 0) return;
2635
- for (const childState of this.childStates.values()) if (childState.parentThreadId === state.parentThreadId) return;
2636
- if (this.parentStates.get(state.parentThreadId) === state) {
2637
- this.clearTerminalRevisionsForParent(state.parentThreadId);
2638
- this.parentStates.delete(state.parentThreadId);
2639
- }
2640
- }
2641
- clearTerminalRevisionsForParent(parentThreadId) {
2642
- for (const [threadId, revision] of this.threadStatusRevisions) if (revision.parentThreadId === parentThreadId) this.collectThreadStatusRevision(threadId, revision);
2643
- }
2644
- collectThreadStatusRevision(threadId, revision = this.threadStatusRevisions.get(threadId)) {
2645
- if (!revision || revision.readers > 0 || this.childStates.has(threadId)) return;
2646
- if ((revision.parentThreadId ? this.parentStates.get(revision.parentThreadId) : void 0)?.owners.size) return;
2647
- if (this.threadStatusRevisions.get(threadId) === revision) this.threadStatusRevisions.delete(threadId);
2648
- }
2649
- scheduleRecoveryPoll(childState) {
2650
- if (childState.terminal || childState.settledWithoutCompletion || childState.recoveryTimer || this.disposed || this.recoveryPollDelaysMs.length === 0) return;
2651
- const delayMs = delayForAttempt(this.recoveryPollDelaysMs, childState.recoveryAttempt++);
2652
- childState.recoveryTimer = setTimeout(() => {
2653
- childState.recoveryTimer = void 0;
2654
- this.reconcileChildThread(childState.childThreadId).catch((error) => {
2655
- this.logRecoveryFailure(childState.childThreadId, error);
2656
- return false;
2657
- }).then(async (reconciled) => {
2658
- if (reconciled || this.childStates.get(childState.childThreadId) !== childState) return;
2659
- const fallback = childState.fallbackCompletion;
2660
- const state = this.parentStates.get(childState.parentThreadId);
2661
- if (fallback && state && childState.recoveryAttempt >= 2) {
2662
- await this.processCompletion(state, childState, fallback, fallback.completedAt ?? this.now());
2663
- return;
2664
- }
2665
- this.scheduleRecoveryPoll(childState);
2666
- });
2667
- }, delayMs);
2668
- unrefTimer(childState.recoveryTimer);
2669
- }
2670
- setRecoveryFallback(childState, completion, eventAt) {
2671
- if (childState.terminal) return;
2672
- const current = childState.fallbackCompletion;
2673
- if (current?.status === completion.status && current.statusLabel === completion.statusLabel && current.result === completion.result) return;
2674
- if (childState.recoveryTimer) {
2675
- clearTimeout(childState.recoveryTimer);
2676
- childState.recoveryTimer = void 0;
2677
- }
2678
- childState.recoveryAttempt = 0;
2679
- childState.fallbackCompletion = {
2680
- ...completion,
2681
- completedAt: eventAt
2682
- };
2683
- this.scheduleRecoveryPoll(childState);
2684
- }
2685
- clearSystemErrorFallback(childState) {
2686
- if (childState.fallbackCompletion?.statusLabel !== "system_error") return;
2687
- childState.fallbackCompletion = void 0;
2688
- }
2689
- retainThreadStatusRevision(threadId) {
2690
- const revision = this.threadStatusRevisions.get(threadId) ?? {
2691
- value: 0,
2692
- readers: 0
2693
- };
2694
- this.threadStatusRevisions.set(threadId, revision);
2695
- revision.readers += 1;
2696
- const capturedValue = revision.value;
2697
- let retained = true;
2698
- return {
2699
- isCurrent: () => this.threadStatusRevisions.get(threadId) === revision && revision.value === capturedValue,
2700
- release: () => {
2701
- if (!retained) return;
2702
- retained = false;
2703
- revision.readers -= 1;
2704
- this.collectThreadStatusRevision(threadId, revision);
2705
- }
2706
- };
2707
- }
2708
- clearRecoveryTimers(childState) {
2709
- if (childState.recoveryTimer) {
2710
- clearTimeout(childState.recoveryTimer);
2711
- childState.recoveryTimer = void 0;
2712
- }
2713
- }
2714
- async reconcileTaskRowsForParent(state) {
2715
- if (this.disposed || this.parentStates.get(state.parentThreadId) !== state || !state.taskRuntime || !state.requesterSessionKey || !state.taskRuntimeScope) return;
2716
- const candidates = /* @__PURE__ */ new Map();
2717
- for (const task of state.taskRuntime.listTaskRecords()) {
2718
- if (task.requesterSessionKey !== state.requesterSessionKey || !this.shouldReconcileCodexNativeTask(task)) continue;
2719
- const childThreadId = task.runId.slice(CODEX_NATIVE_SUBAGENT_RUN_ID_PREFIX.length).trim();
2720
- candidates.set(childThreadId, {
2721
- parentState: state,
2722
- nativeCompletionReceipts: state.nativeCompletionReceipts,
2723
- requesterSessionKey: state.requesterSessionKey,
2724
- childThreadId,
2725
- recoveryAttempt: 0,
2726
- taskRuntimeScope: state.taskRuntimeScope,
2727
- agentId: state.agentId,
2728
- taskRuntime: state.taskRuntime
2729
- });
2730
- }
2731
- for (const candidate of candidates.values()) await this.reconcileTaskCandidate(candidate);
2732
- }
2733
- async reconcileTaskCandidate(candidate) {
2734
- const key = `${candidate.requesterSessionKey}\0${candidate.childThreadId}`;
2735
- const scheduled = this.taskReconciliationTimers.get(key);
2736
- if (scheduled) {
2737
- clearTimeout(scheduled);
2738
- this.taskReconciliationTimers.delete(key);
2739
- }
2740
- const existing = this.taskReconciliations.get(key);
2741
- if (existing) {
2742
- await existing;
2743
- return;
2744
- }
2745
- const reconciliation = this.reconcileTaskCandidateOnce(candidate);
2746
- this.taskReconciliations.set(key, reconciliation);
2747
- try {
2748
- await reconciliation;
2749
- } finally {
2750
- if (this.taskReconciliations.get(key) === reconciliation) this.taskReconciliations.delete(key);
2751
- }
2752
- }
2753
- scheduleTaskCandidateReconciliation(candidate) {
2754
- const key = `${candidate.requesterSessionKey}\0${candidate.childThreadId}`;
2755
- if (this.disposed || this.retiredParentStates.has(candidate.parentState) || this.recoveryPollDelaysMs.length === 0 || this.taskReconciliationTimers.has(key)) return;
2756
- const delayMs = delayForAttempt(this.recoveryPollDelaysMs, candidate.recoveryAttempt++);
2757
- const timer = setTimeout(() => {
2758
- this.taskReconciliationTimers.delete(key);
2759
- this.reconcileTaskCandidate(candidate).catch((error) => {
2760
- this.logRecoveryFailure(candidate.childThreadId, error);
2761
- this.scheduleTaskCandidateReconciliation(candidate);
2762
- });
2763
- }, delayMs);
2764
- this.taskReconciliationTimers.set(key, timer);
2765
- unrefTimer(timer);
2766
- }
2767
- async reconcileTaskCandidateOnce(candidate) {
2768
- if (this.retiredParentStates.has(candidate.parentState)) return;
2769
- const runId = codexNativeSubagentRunId(candidate.childThreadId);
2770
- const task = candidate.taskRuntime.listTaskRecords().find((record) => record.runId === runId);
2771
- if (!task || task.requesterSessionKey !== candidate.requesterSessionKey || !this.shouldReconcileCodexNativeTask(task)) return;
2772
- const childBeforeRead = this.childStates.get(candidate.childThreadId);
2773
- const statusRead = this.retainThreadStatusRevision(candidate.childThreadId);
2774
- try {
2775
- let recovery;
2776
- try {
2777
- recovery = await this.readThreadRecovery(candidate.childThreadId);
2778
- } catch (error) {
2779
- this.logRecoveryFailure(candidate.childThreadId, error);
2780
- this.scheduleTaskCandidateReconciliation(candidate);
2781
- return;
2782
- }
2783
- if (this.retiredParentStates.has(candidate.parentState)) return;
2784
- if (!statusRead.isCurrent() || this.childStates.get(candidate.childThreadId) !== childBeforeRead) {
2785
- this.scheduleTaskCandidateReconciliation(candidate);
2786
- return;
2787
- }
2788
- const parentThreadId = recovery.parentThreadId;
2789
- if (!parentThreadId) {
2790
- this.scheduleTaskCandidateReconciliation(candidate);
2791
- return;
2792
- }
2793
- let state = this.parentStates.get(parentThreadId);
2794
- if (state && state.requesterSessionKey !== candidate.requesterSessionKey) return;
2795
- if (!state) {
2796
- state = {
2797
- parentThreadId,
2798
- owners: /* @__PURE__ */ new Map(),
2799
- turnIds: /* @__PURE__ */ new Set(),
2800
- nativeCompletionReceipts: /* @__PURE__ */ new Set(),
2801
- requesterSessionKey: candidate.requesterSessionKey,
2802
- taskRuntimeScope: candidate.taskRuntimeScope,
2803
- agentId: candidate.agentId,
2804
- taskRuntime: candidate.taskRuntime
2805
- };
2806
- this.prepareParentTaskRuntime(state);
2807
- this.parentStates.set(parentThreadId, state);
2808
- }
2809
- const childState = this.registerChildThread(state, candidate.childThreadId, recovery.agentPath ? { agentPath: recovery.agentPath } : {});
2810
- if (!childState) {
2811
- this.pruneParentIfUnused(state);
2812
- return;
2813
- }
2814
- if ([...childState.agentPathKeys].some((key) => candidate.nativeCompletionReceipts.has(key))) childState.nativeCompletionDelivered = true;
2815
- if (recovery.threadState === "active") this.observeActiveChild(childState);
2816
- if (recovery.threadState === "other") this.clearSystemErrorFallback(childState);
2817
- if (recovery.resumable) {
2818
- this.settleResumableChild(childState);
2819
- return;
2820
- }
2821
- const completion = recovery.completion;
2822
- if (!completion) {
2823
- if (recovery.fallbackCompletion) {
2824
- this.setRecoveryFallback(childState, recovery.fallbackCompletion, recovery.fallbackCompletion.completedAt ?? this.now());
2825
- return;
2826
- }
2827
- this.scheduleRecoveryPoll(childState);
2828
- return;
2829
- }
2830
- if (isNoFinalCompletion(completion)) {
2831
- this.setRecoveryFallback(childState, completion, completion.completedAt ?? this.now());
2832
- return;
2833
- }
2834
- await this.processCompletion(state, childState, completion, completion.completedAt);
2835
- } finally {
2836
- statusRead.release();
2837
- }
2838
- }
2839
- shouldReconcileCodexNativeTask(task) {
2840
- if (task.status === "queued" || task.status === "running" || task.deliveryStatus === "pending") return true;
2841
- if (task.deliveryStatus !== "not_applicable" || task.endedAt === void 0) return false;
2842
- return task.endedAt >= this.now() - RECENT_TERMINAL_TASK_RECONCILE_GRACE_MS;
2843
- }
2844
- logRecoveryFailure(childThreadId, error) {
2845
- embeddedAgentLog.debug("Codex native subagent history is not ready", {
2846
- childThreadId,
2847
- error: formatErrorMessage(error)
2848
- });
2849
- }
2850
- };
2851
- const codexNativeSubagentMonitorRuntime = {
2852
- Monitor,
2853
- register: registerMonitor,
2854
- retireParent: (client, parentThreadId) => {
2855
- monitors.get(client)?.retireParent(parentThreadId);
2856
- }
2857
- };
2858
- function readThreadTurnRecovery(thread, childThreadId) {
2859
- const turns = Array.isArray(thread.turns) ? thread.turns : [];
2860
- for (let index = turns.length - 1; index >= 0; index -= 1) {
2861
- const turn = turns[index];
2862
- if (!isJsonObject(turn)) continue;
2863
- const status = normalizeIdentifier(readStringField(turn, "status"));
2864
- return {
2865
- completion: readTurnCompletion(turn, childThreadId),
2866
- resumable: status === "interrupted"
2867
- };
2868
- }
2869
- return { resumable: false };
2870
- }
2871
- function toChildTurnCompletion(childState, turn) {
2872
- const status = normalizeIdentifier(readStringField(turn, "status"));
2873
- if (status === "completed") {
2874
- const turnId = readStringField(turn, "id");
2875
- const result = turnId ? lastChildAssistantMessage(childState, turnId) : void 0;
2876
- return {
2877
- childThreadId: childState.childThreadId,
2878
- status: "succeeded",
2879
- statusLabel: result ? "turn_completed" : "completed_without_final_message",
2880
- result: result ?? "Subagent completed without a final assistant message."
2881
- };
2882
- }
2883
- if (status === "failed") return {
2884
- childThreadId: childState.childThreadId,
2885
- status: "failed",
2886
- statusLabel: "turn_failed",
2887
- result: readTurnErrorMessage(turn) ?? "Subagent failed."
2888
- };
2889
- }
2890
- function lastChildAssistantMessage(childState, turnId) {
2891
- const messages = childState.assistantMessagesByTurn.get(turnId);
2892
- if (!messages) return;
2893
- for (const itemId of messages.order.toReversed()) if (messages.finalMessageIds.has(itemId) && !messages.commentaryIds.has(itemId)) {
2894
- const text = normalizeOptionalString(messages.texts.get(itemId));
2895
- if (text) return text;
2896
- }
2897
- }
2898
- function readTurnErrorMessage(turn) {
2899
- const error = isJsonObject(turn.error) ? turn.error : void 0;
2900
- return normalizeOptionalString(readStringField(error, "message")) ?? normalizeOptionalString(isJsonObject(error?.codexErrorInfo) ? readStringField(error.codexErrorInfo, "message") : void 0);
2901
- }
2902
- function systemErrorFallbackCompletion(childThreadId) {
2903
- return {
2904
- childThreadId,
2905
- status: "failed",
2906
- statusLabel: "system_error",
2907
- result: "Subagent runtime reported a system error."
2908
- };
2909
- }
2910
- function readTurnCompletion(turn, childThreadId) {
2911
- const status = normalizeIdentifier(readStringField(turn, "status"));
2912
- if (status === "inprogress" || !status) return;
2913
- const result = readLastAgentMessage(turn);
2914
- const completedAtSeconds = asFiniteNumber(turn.completedAt);
2915
- const completedAt = completedAtSeconds === void 0 ? void 0 : Math.round(completedAtSeconds * 1e3);
2916
- if (status === "completed") return {
2917
- childThreadId,
2918
- status: "succeeded",
2919
- statusLabel: result ? "task_complete" : "completed_without_final_message",
2920
- result: result ?? "Subagent completed without a final assistant message.",
2921
- completedAt
2922
- };
2923
- if (status === "interrupted") return;
2924
- if (status === "failed") return {
2925
- childThreadId,
2926
- status: "failed",
2927
- statusLabel: "task_failed",
2928
- result: readTurnErrorMessage(turn) ?? result ?? "Subagent failed.",
2929
- completedAt
2930
- };
2931
- }
2932
- function readLastAgentMessage(turn) {
2933
- const items = Array.isArray(turn.items) ? turn.items : [];
2934
- let legacyResult;
2935
- for (let index = items.length - 1; index >= 0; index -= 1) {
2936
- const item = items[index];
2937
- if (!isJsonObject(item)) continue;
2938
- if (normalizeIdentifier(readStringField(item, "type")) !== "agentmessage") continue;
2939
- const text = readStringField(item, "text")?.trim();
2940
- if (!text) continue;
2941
- const phase = normalizeIdentifier(readStringField(item, "phase"));
2942
- if (phase === "finalanswer") return text;
2943
- if (!phase) legacyResult ??= text;
2944
- }
2945
- return legacyResult;
2946
- }
2947
- function buildParentAgentPathKey(parentThreadId, agentPath) {
2948
- return `${parentThreadId}\0${agentPath}`;
2949
- }
2950
- function isNoFinalCompletion(completion) {
2951
- return completion.status === "succeeded" && completion.statusLabel === "completed_without_final_message";
2952
- }
2953
- function delayForAttempt(delays, attempt) {
2954
- return Math.max(1, delays[Math.min(attempt, delays.length - 1)] ?? 1);
2955
- }
2956
- function readThreadParentThreadId(thread) {
2957
- return readStringField(thread, "parentThreadId")?.trim() ?? readStringField(readThreadSpawnSource(thread), "parent_thread_id")?.trim();
2958
- }
2959
- function readThreadSpawnSource(thread) {
2960
- const source = isJsonObject(thread?.source) ? thread.source : void 0;
2961
- const subAgent = isJsonObject(source?.subAgent) ? source.subAgent : void 0;
2962
- return isJsonObject(subAgent?.thread_spawn) ? subAgent.thread_spawn : void 0;
2963
- }
2964
- function readStringArray(value) {
2965
- if (!Array.isArray(value)) return [];
2966
- return value.filter((entry) => typeof entry === "string" && entry.trim() !== "");
2967
- }
2968
- function readObjectStringKeys(value) {
2969
- return isJsonObject(value) ? Object.keys(value).filter((entry) => entry.trim() !== "") : [];
2970
- }
2971
- function normalizeIdentifier(value) {
2972
- return value?.replace(/[^a-z0-9]/giu, "").toLowerCase();
2973
- }
2974
- function unrefTimer(timer) {
2975
- if (typeof timer === "object" && timer && "unref" in timer) timer.unref();
2976
- }
2977
- //#endregion
2978
- export { CodexToolProgressProjection as a, CodexToolTranscriptProjection as i, CodexEventProjection as n, shouldEmitTranscriptToolProgress as o, emitCodexAgentEvent as r, codexNativeSubagentMonitorRuntime as t };