chainlesschain 0.166.26 → 0.166.29

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 (177) hide show
  1. package/package.json +1 -1
  2. package/src/assets/web-panel/assets/{AIOps-Z8_dnLd8.js → AIOps-D4Dhiipq.js} +1 -1
  3. package/src/assets/web-panel/assets/{ActionButton-C4bKCISV.js → ActionButton-P6fPjlUB.js} +1 -1
  4. package/src/assets/web-panel/assets/{Analytics-GztAv2jy.js → Analytics-CzeKpXdh.js} +3 -3
  5. package/src/assets/web-panel/assets/{AppLayout-DEqNcuVx.js → AppLayout-Cj8CqntA.js} +4 -4
  6. package/src/assets/web-panel/assets/{Artifacts-D-R4Ehap.js → Artifacts-BOe7lviy.js} +1 -1
  7. package/src/assets/web-panel/assets/{Audit-mzzdTIlM.js → Audit-D6kxPJyo.js} +1 -1
  8. package/src/assets/web-panel/assets/{BackgroundAgents-DS2QupIC.js → BackgroundAgents-OVuYY65D.js} +1 -1
  9. package/src/assets/web-panel/assets/{Backup-CQSirC39.js → Backup-UAlkEXOa.js} +1 -1
  10. package/src/assets/web-panel/assets/{BaseInput-Bhuc-eOV.js → BaseInput-DikQWFIL.js} +1 -1
  11. package/src/assets/web-panel/assets/{Chat-B-RLVGnt.js → Chat-CEpqrZcV.js} +6 -6
  12. package/src/assets/web-panel/assets/ChatBubbleRenderer-BLE9L1yw.js +1 -0
  13. package/src/assets/web-panel/assets/{Checkbox-DxwgBryW.js → Checkbox-D2mdaw7o.js} +1 -1
  14. package/src/assets/web-panel/assets/{Codegen-Cwrm-7nh.js → Codegen-CJ2LEcdr.js} +1 -1
  15. package/src/assets/web-panel/assets/{Col-DrSCT-nF.js → Col-ej56LWvr.js} +1 -1
  16. package/src/assets/web-panel/assets/{Community-DY2D9WNs.js → Community-D9neNmTp.js} +1 -1
  17. package/src/assets/web-panel/assets/{Compact-o-tV0URw.js → Compact-BzWfgovR.js} +1 -1
  18. package/src/assets/web-panel/assets/{Compliance-Bndh6S8f.js → Compliance-dStoa8Mw.js} +1 -1
  19. package/src/assets/web-panel/assets/{Cowork-CSNQODak.js → Cowork-BxYPXbQl.js} +3 -3
  20. package/src/assets/web-panel/assets/{Cron-CTgxRHdy.js → Cron-DxOQIcrL.js} +2 -2
  21. package/src/assets/web-panel/assets/{Crosschain-BJoGQzDI.js → Crosschain-BYyOjqVA.js} +1 -1
  22. package/src/assets/web-panel/assets/{DID-V0Ztm8ne.js → DID-c81gsUZq.js} +2 -2
  23. package/src/assets/web-panel/assets/{Dashboard-B-38THOj.js → Dashboard-CHIjYxb2.js} +2 -2
  24. package/src/assets/web-panel/assets/{Dropdown-B3FdOwMO.js → Dropdown-C7hRZzkL.js} +1 -1
  25. package/src/assets/web-panel/assets/{EmailListRenderer-YQDz4mUF.js → EmailListRenderer--h_ShKAT.js} +1 -1
  26. package/src/assets/web-panel/assets/{FamilyGuardDashboard-DYE45IF9.js → FamilyGuardDashboard-Bq68asD0.js} +1 -1
  27. package/src/assets/web-panel/assets/{Federation-DjBFjdRZ.js → Federation-DGKsWpUO.js} +1 -1
  28. package/src/assets/web-panel/assets/{FormItemContext-CVTXEa0R.js → FormItemContext-1HbCXJAf.js} +1 -1
  29. package/src/assets/web-panel/assets/{GenericCardRenderer-B6Tkke8X.js → GenericCardRenderer-BlKJ93Fy.js} +1 -1
  30. package/src/assets/web-panel/assets/{Git-CD0hyAzT.js → Git-DJA-kxuw.js} +2 -2
  31. package/src/assets/web-panel/assets/{Governance-CWOQQJr8.js → Governance-BWZPtzHj.js} +1 -1
  32. package/src/assets/web-panel/assets/{Inference-lHYwUk-C.js → Inference-D3QXUTYP.js} +1 -1
  33. package/src/assets/web-panel/assets/{KnowledgeGraph-Cledxv7t.js → KnowledgeGraph-BM37hWOP.js} +1 -1
  34. package/src/assets/web-panel/assets/{Logs-D45mt-rM.js → Logs-Bpu4Of_0.js} +2 -2
  35. package/src/assets/web-panel/assets/MarkdownRenderer-DAZcw_ZS.js +1 -0
  36. package/src/assets/web-panel/assets/{Marketplace-Yy30UZPw.js → Marketplace-BZe0jmAU.js} +1 -1
  37. package/src/assets/web-panel/assets/{McpTools-Cil5l-bh.js → McpTools-_q_nfUnU.js} +3 -3
  38. package/src/assets/web-panel/assets/{Memory-DdJcnyqy.js → Memory-CIzcovHt.js} +2 -2
  39. package/src/assets/web-panel/assets/{MobileBridge-IrzFYHEv.js → MobileBridge-DZzo5UjF.js} +1 -1
  40. package/src/assets/web-panel/assets/{MobileProjects-D8q64LMd.js → MobileProjects-DVZr9bVO.js} +1 -1
  41. package/src/assets/web-panel/assets/{Mtc-CpdTJzW7.js → Mtc-pULSsEOx.js} +4 -4
  42. package/src/assets/web-panel/assets/{MtcAudit-C7Tvw2m6.js → MtcAudit-BLz9fiz0.js} +2 -2
  43. package/src/assets/web-panel/assets/{Multisig-Dmj9F5Kr.js → Multisig-B1qxfPkT.js} +3 -3
  44. package/src/assets/web-panel/assets/{NLProgramming-C9Xchob5.js → NLProgramming-Bkb9YB7P.js} +1 -1
  45. package/src/assets/web-panel/assets/{Notes-Bzq6Yry5.js → Notes-N0G87PD1.js} +4 -4
  46. package/src/assets/web-panel/assets/{NotificationSettings-DxG9eKb4.js → NotificationSettings-D0jB-hRv.js} +1 -1
  47. package/src/assets/web-panel/assets/{OrderTableRenderer-BS_IYoCe.js → OrderTableRenderer-soFvgov0.js} +1 -1
  48. package/src/assets/web-panel/assets/{Organization-kazsRvcq.js → Organization-BNBL1-7S.js} +4 -4
  49. package/src/assets/web-panel/assets/{Overflow-i4wP-hwn.js → Overflow-yqaJxwEo.js} +1 -1
  50. package/src/assets/web-panel/assets/{P2P-CfGeU3h-.js → P2P-1JHDOnl3.js} +2 -2
  51. package/src/assets/web-panel/assets/{PdhVaultBrowser-CS-VhVUx.js → PdhVaultBrowser-D1FgaOLV.js} +5 -5
  52. package/src/assets/web-panel/assets/{Permissions-DnEHXs0I.js → Permissions-DOQh1Wzv.js} +4 -4
  53. package/src/assets/web-panel/assets/{PersonalDataHub-DeD82qke.js → PersonalDataHub-SVa21bUw.js} +5 -5
  54. package/src/assets/web-panel/assets/{Pipeline-CMGGLgBY.js → Pipeline-Du3gCATi.js} +1 -1
  55. package/src/assets/web-panel/assets/{Privacy-CvHoFv32.js → Privacy-CPW8EDaC.js} +1 -1
  56. package/src/assets/web-panel/assets/{ProjectInit-DnJapCc1.js → ProjectInit-CAu5N0A_.js} +2 -2
  57. package/src/assets/web-panel/assets/{ProjectSettings-CqVdv3-g.js → ProjectSettings-DVTow6ty.js} +2 -2
  58. package/src/assets/web-panel/assets/{Projects-B_o8vcs_.js → Projects-CBUF9hPa.js} +1 -1
  59. package/src/assets/web-panel/assets/{Providers-CPKseoDW.js → Providers-B7pNEoaY.js} +1 -1
  60. package/src/assets/web-panel/assets/{QrScannerModal-_iBfKbPQ.js → QrScannerModal-BHs1Kx7e.js} +1 -1
  61. package/src/assets/web-panel/assets/{QuickAsk-CMrlZ69a.js → QuickAsk-IBrdC5B5.js} +1 -1
  62. package/src/assets/web-panel/assets/{Recommend-BwDtSZ0l.js → Recommend-BtkLuO-e.js} +1 -1
  63. package/src/assets/web-panel/assets/{RemoteSession-DomUAtn4.js → RemoteSession-Du4_izg3.js} +2 -2
  64. package/src/assets/web-panel/assets/{Reputation-Cuu2GCHr.js → Reputation-IEbMZN6v.js} +1 -1
  65. package/src/assets/web-panel/assets/{Row-C7GVts31.js → Row-D5UM_ivw.js} +1 -1
  66. package/src/assets/web-panel/assets/{RssFeed-DRKvgEog.js → RssFeed-DTTNnkdJ.js} +3 -3
  67. package/src/assets/web-panel/assets/{Search-BGI9wOeA.js → Search-B5f7ggJE.js} +1 -1
  68. package/src/assets/web-panel/assets/{Security-BlLaHy_L.js → Security-CsZp2uGu.js} +3 -3
  69. package/src/assets/web-panel/assets/{Services-DFqZbjmX.js → Services-BJhguqIh.js} +2 -2
  70. package/src/assets/web-panel/assets/{Skeleton-BCGxdooP.js → Skeleton-CAwO2JUK.js} +1 -1
  71. package/src/assets/web-panel/assets/{Skills-CwFKgcmm.js → Skills-hKJcP390.js} +1 -1
  72. package/src/assets/web-panel/assets/{Sla-CiXXh9eS.js → Sla-BCFiB8oS.js} +1 -1
  73. package/src/assets/web-panel/assets/{SpeechSettings-WSx2CLqO.js → SpeechSettings-Bi1Y-Tgf.js} +1 -1
  74. package/src/assets/web-panel/assets/{SyncSettings-BBIqQOtW.js → SyncSettings-ZHYDv46g.js} +2 -2
  75. package/src/assets/web-panel/assets/{Tasks-D1BGLjO1.js → Tasks-BMCSrUy-.js} +1 -1
  76. package/src/assets/web-panel/assets/{Templates-CUIl9axA.js → Templates-DF_FOEH8.js} +1 -1
  77. package/src/assets/web-panel/assets/{Tenant-BFZJ0hNz.js → Tenant-C7Q2LriV.js} +1 -1
  78. package/src/assets/web-panel/assets/{Terminal-Cw-3eYVn.js → Terminal-C59ckWXW.js} +2 -2
  79. package/src/assets/web-panel/assets/{TimelineRenderer-bOVPB56L.js → TimelineRenderer-Biu1m6Uf.js} +1 -1
  80. package/src/assets/web-panel/assets/{Tokens-Czfyq2VY.js → Tokens-CoHYWg3-.js} +1 -1
  81. package/src/assets/web-panel/assets/{Trigger-C-o4uJY0.js → Trigger-DglXXzEp.js} +1 -1
  82. package/src/assets/web-panel/assets/{Trust-BKq_S6iF.js → Trust-CBBLh73r.js} +1 -1
  83. package/src/assets/web-panel/assets/{UkeySign-fKlWUvMx.js → UkeySign-DuNdKeiD.js} +1 -1
  84. package/src/assets/web-panel/assets/{VideoEditing-DB5MLuS7.js → VideoEditing-BizHWVrh.js} +1 -1
  85. package/src/assets/web-panel/assets/{Wallet-WGXBn7IS.js → Wallet-ClUQGSKi.js} +4 -4
  86. package/src/assets/web-panel/assets/{WebAuthn-B8TC4EMF.js → WebAuthn-zyD7K5f5.js} +4 -4
  87. package/src/assets/web-panel/assets/{WorkflowEditor-DLY--KmM.js → WorkflowEditor-qbTI37Fi.js} +1 -1
  88. package/src/assets/web-panel/assets/{chat-Crw3XQaA.js → chat-CHv66tBY.js} +1 -1
  89. package/src/assets/web-panel/assets/{colors-CxhWauPV.js → colors-vBsvcJjY.js} +1 -1
  90. package/src/assets/web-panel/assets/{compact-item-Cp3ojtk5.js → compact-item-CdBQZWFX.js} +1 -1
  91. package/src/assets/web-panel/assets/{createContext-CRuRXjSo.js → createContext-CLE2XsPX.js} +1 -1
  92. package/src/assets/web-panel/assets/devWarning-DRQGMdYB.js +1 -0
  93. package/src/assets/web-panel/assets/{hasIn-XGW474dj.js → hasIn-Du5rnUSg.js} +1 -1
  94. package/src/assets/web-panel/assets/{index-C73pqyDb.js → index-9nDAQkO-.js} +1 -1
  95. package/src/assets/web-panel/assets/{index-DHNixOg_.js → index-B-3GrN7D.js} +1 -1
  96. package/src/assets/web-panel/assets/{index-DUSVsOGS.js → index-BDaW0C3l.js} +1 -1
  97. package/src/assets/web-panel/assets/{index-BXnNbbwa.js → index-BY0Jg8JC.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-Yq3bFbYX.js → index-Bdfg7CY3.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-BW028Pwn.js → index-BnZkmomS.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-DBcBsJYg.js → index-BojUN0eY.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-DoUC5_ry.js → index-BrFwv-2v.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CPFam-me.js → index-Bu3v3PRU.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-J_08R33H.js → index-BuSZyAD0.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-WvNZXbIO.js → index-Bwqa-FcB.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-rsACoVT9.js → index-ByEfQiLz.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-DhomnuaB.js → index-CKoOU-ne.js} +1 -1
  107. package/src/assets/web-panel/assets/index-CPJgV0Ho.js +1 -0
  108. package/src/assets/web-panel/assets/{index-DfPLIA-f.js → index-CRiOcWZ1.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-BuVA26SD.js → index-Ca0WeKz1.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-E-RSfImO.js → index-Cc53mZoS.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-C8UOVaUH.js → index-CigkcWWh.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-qzmihx1d.js → index-Cuvyt0vv.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-BUWZ57T4.js → index-CvHjeRw2.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-BetOkRLs.js → index-CxmlGwpv.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-B5fJS-kn.js → index-Cz48QuqC.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-nJR64pA_.js → index-D-KoBLmE.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-Dp2nC5On.js → index-D-jjL85C.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-BYkjs7eP.js → index-DADajBnD.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-BElgeKJ0.js → index-DHdrZp_q.js} +3 -3
  120. package/src/assets/web-panel/assets/{index-QqAuH7-S.js → index-DHhNie07.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-jrIcbPUa.js → index-DnB7oqAR.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-Ctu98x57.js → index-DsyYG63S.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-CTE32qol.js → index-Dv9b_iFq.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-CdlfrcC-.js → index-DzYEc47A.js} +1 -1
  125. package/src/assets/web-panel/assets/index-OtXVaszG.js +1 -0
  126. package/src/assets/web-panel/assets/{index-CDIpH_8Q.js → index-aYAtijnz.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-38TRdZb6.js → index-dEhWAtoe.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-DxOtBFVy.js → index-q3sGyZnD.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-B45Vkh3T.js → index-sLcRd9pi.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-BVmSfIkJ.js → index-sz6sGerd.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-De2FN0xN.js → index-uHX8ZrJ9.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-W8_0yAi_.js → index-x_0JRAO3.js} +1 -1
  133. package/src/assets/web-panel/assets/{initDefaultProps-DAu-hgme.js → initDefaultProps-CThtsKhS.js} +1 -1
  134. package/src/assets/web-panel/assets/{motion-Db8yk0Hu.js → motion-BoqT16ZT.js} +1 -1
  135. package/src/assets/web-panel/assets/{move-Cii2jOin.js → move-1Jf6ZXg5.js} +1 -1
  136. package/src/assets/web-panel/assets/{mtc-parser-CnZBDkyZ.js → mtc-parser-DjfCYvnq.js} +1 -1
  137. package/src/assets/web-panel/assets/{omit-Buzt1FTL.js → omit-BaJPeP5Y.js} +1 -1
  138. package/src/assets/web-panel/assets/{pickAttrs-CpZ_NmE6.js → pickAttrs-B7nqrfVR.js} +1 -1
  139. package/src/assets/web-panel/assets/{placementArrow-mBrx3dYm.js → placementArrow-Dmb7i435.js} +1 -1
  140. package/src/assets/web-panel/assets/{responsiveObserve-DC_QzljB.js → responsiveObserve-B0TqfHJR.js} +1 -1
  141. package/src/assets/web-panel/assets/{slide-DT_UVED-.js → slide-C9PINvAM.js} +1 -1
  142. package/src/assets/web-panel/assets/{statusUtils-78t6eNLV.js → statusUtils-DAug5z5S.js} +1 -1
  143. package/src/assets/web-panel/assets/{styleChecker-CV_T1ULL.js → styleChecker-o6QvGnrq.js} +1 -1
  144. package/src/assets/web-panel/assets/{useFlexGapSupport-s8edGuXD.js → useFlexGapSupport-CtZwQFCt.js} +1 -1
  145. package/src/assets/web-panel/assets/{useFs-Pk9dH2HC.js → useFs-B0HVNsmA.js} +1 -1
  146. package/src/assets/web-panel/assets/{usePersonalDataHub-B_GqAm8c.js → usePersonalDataHub-CbLIg5eO.js} +1 -1
  147. package/src/assets/web-panel/assets/{vnode-Cxyss24q.js → vnode-uOK2NMHj.js} +1 -1
  148. package/src/assets/web-panel/assets/{zoom-0UY3cOuc.js → zoom-BhyA2sIv.js} +1 -1
  149. package/src/assets/web-panel/index.html +1 -1
  150. package/src/commands/ask.js +84 -5
  151. package/src/commands/chat.js +67 -1
  152. package/src/commands/compact.js +81 -2
  153. package/src/commands/complete.js +64 -5
  154. package/src/commands/cowork.js +133 -0
  155. package/src/commands/orchestrate.js +18 -7
  156. package/src/data/changelog.json +26 -0
  157. package/src/gateways/ws/action-protocol.js +2 -0
  158. package/src/lib/agent-router.js +116 -36
  159. package/src/lib/cowork-task-runner.js +107 -4
  160. package/src/lib/evolution/agent-evolution-ingress.js +231 -40
  161. package/src/lib/evolution/agent-evolution-runtime-composition.js +85 -5
  162. package/src/lib/evolution/evolution-deployment-loader.js +17 -1
  163. package/src/lib/evolution/evolution-evidence-projector.js +25 -6
  164. package/src/lib/model-failure-policy.js +10 -0
  165. package/src/lib/orchestrator.js +97 -27
  166. package/src/lib/read-file-loop-guard.js +33 -10
  167. package/src/lib/sub-agent-context.js +37 -2
  168. package/src/lib/task-progress-tracker.js +223 -0
  169. package/src/repl/chat-repl.js +60 -10
  170. package/src/runtime/agent-core.js +186 -16
  171. package/src/runtime/agent-runtime.js +20 -1
  172. package/src/runtime/runtime-factory.js +1 -1
  173. package/src/assets/web-panel/assets/ChatBubbleRenderer-CBbMoVuE.js +0 -1
  174. package/src/assets/web-panel/assets/MarkdownRenderer-DJjPaOnM.js +0 -1
  175. package/src/assets/web-panel/assets/devWarning-CKAQY2zn.js +0 -1
  176. package/src/assets/web-panel/assets/index-Cetfwq8j.js +0 -1
  177. package/src/assets/web-panel/assets/index-DOpcRO2-.js +0 -1
@@ -26,7 +26,9 @@ import crypto from "crypto";
26
26
  import { AgentRouter } from "./agent-router.js";
27
27
  import { NotificationManager } from "./notifiers/index.js";
28
28
  import { createChatFn } from "./cowork-adapter.js";
29
+ import { captureAgentEvolutionRuntimeComposition } from "./evolution/agent-evolution-runtime-composition-brand.js";
29
30
  import { firstBalancedJson } from "./json-schema-output.js";
31
+ import { isTerminalModelFailure } from "./model-failure-policy.js";
30
32
  import {
31
33
  assertCLILegacyMutationAllowed,
32
34
  cliLegacyRuntimeReadOnly,
@@ -58,6 +60,7 @@ export const TASK_STATUS = {
58
60
  CI_PASSED: "ci-passed",
59
61
  CI_FAILED: "ci-failed",
60
62
  RETRYING: "retrying",
63
+ FINALIZING: "finalizing",
61
64
  COMPLETED: "completed",
62
65
  FAILED: "failed",
63
66
  };
@@ -98,6 +101,15 @@ export class Orchestrator extends EventEmitter {
98
101
  this.maxRetries = options.maxRetries || 3;
99
102
  this.ciCommand = options.ciCommand || "npm test";
100
103
  this.verbose = options.verbose || false;
104
+ this._evolutionCompositionFactory =
105
+ options.evolutionCompositionFactory ?? null;
106
+ if (
107
+ this._evolutionCompositionFactory !== null &&
108
+ typeof this._evolutionCompositionFactory !== "function"
109
+ ) {
110
+ throw new TypeError("evolutionCompositionFactory must be a function");
111
+ }
112
+ this._llmOptions = options.llm || {};
101
113
 
102
114
  // Cap retained task history. Every addTask stores a record in _tasks and
103
115
  // nothing ever removes it, so a long-running orchestrator (cron-watch /
@@ -141,7 +153,7 @@ export class Orchestrator extends EventEmitter {
141
153
  this.notifier =
142
154
  options.notifier || NotificationManager.fromEnv(options.notify || {});
143
155
 
144
- this._chat = createChatFn(options.llm || {});
156
+ this._chat = createChatFn(this._llmOptions);
145
157
  this._cronTimer = null;
146
158
 
147
159
  // Forward router events
@@ -210,7 +222,51 @@ export class Orchestrator extends EventEmitter {
210
222
  .catch(() => {});
211
223
  }
212
224
 
213
- await this._orchestrate(task);
225
+ let evolutionComposition = null;
226
+ try {
227
+ if (this._evolutionCompositionFactory !== null) {
228
+ evolutionComposition = captureAgentEvolutionRuntimeComposition(
229
+ await this._evolutionCompositionFactory(
230
+ Object.freeze({
231
+ mode: "orchestrate",
232
+ runId: task.id,
233
+ taskId: task.id,
234
+ source: task.source,
235
+ cwd: task.cwd,
236
+ }),
237
+ ),
238
+ );
239
+ if (
240
+ evolutionComposition.runId !== task.id ||
241
+ evolutionComposition.evolutionIngress.runId !== task.id ||
242
+ evolutionComposition.evolutionIngress.tenantId !==
243
+ evolutionComposition.tenantId
244
+ ) {
245
+ const error = new Error(
246
+ "Orchestrator evolution composition is not bound to the requested Run",
247
+ );
248
+ error.code = "CC_AGENT_EVOLUTION_INGRESS_FAILED";
249
+ throw error;
250
+ }
251
+ await evolutionComposition.evolutionIngress.start();
252
+ await evolutionComposition.evolutionIngress.ingestUserPrompt({
253
+ content: task.description,
254
+ context: task.context,
255
+ taskId: task.id,
256
+ source: `orchestrate:${task.source}`,
257
+ });
258
+ }
259
+ } catch (error) {
260
+ task.status = TASK_STATUS.FAILED;
261
+ task.error = error.message;
262
+ this.emit("task:failed", { task, error });
263
+ throw error;
264
+ }
265
+
266
+ await this._orchestrate(
267
+ task,
268
+ evolutionComposition?.evolutionIngress ?? null,
269
+ );
214
270
  return task;
215
271
  }
216
272
 
@@ -257,24 +313,22 @@ export class Orchestrator extends EventEmitter {
257
313
 
258
314
  // ─── Orchestration pipeline ──────────────────────────────────────
259
315
 
260
- async _orchestrate(task) {
316
+ async _orchestrate(task, evolutionIngress = null) {
261
317
  assertCLILegacyMutationAllowed("Orchestrator._orchestrate");
262
318
  try {
263
319
  // Step 1: Decompose
264
- task.subtasks = await this._decompose(task);
320
+ task.subtasks = await this._decompose(task, evolutionIngress);
265
321
  task.status = TASK_STATUS.DISPATCHED;
266
322
 
267
323
  // Step 2: Dispatch to Claude Code agents
268
- task.agentResults = await this._dispatch(task);
324
+ task.agentResults = await this._dispatch(task, evolutionIngress);
269
325
  this._assertSuccessfulAgentResults(task);
270
326
 
271
327
  // Step 3: CI/CD check
272
328
  if (task.runCI) {
273
- await this._ciLoop(task);
329
+ await this._ciLoop(task, evolutionIngress);
274
330
  } else {
275
- task.status = TASK_STATUS.COMPLETED;
276
- task.completedAt = new Date().toISOString();
277
- this.emit("task:complete", task);
331
+ await this._completeTask(task, evolutionIngress);
278
332
  }
279
333
  } catch (err) {
280
334
  task.status = TASK_STATUS.FAILED;
@@ -284,8 +338,26 @@ export class Orchestrator extends EventEmitter {
284
338
  }
285
339
  }
286
340
 
341
+ async _completeTask(task, evolutionIngress, ciResult = null) {
342
+ assertCLILegacyMutationAllowed("Orchestrator._completeTask");
343
+ task.status = TASK_STATUS.FINALIZING;
344
+ if (evolutionIngress !== null) await evolutionIngress.complete();
345
+ if (ciResult !== null && this.notifier.isConfigured && task.notify) {
346
+ await this.notifier.notifySuccess({
347
+ taskId: task.id,
348
+ description: task.description.slice(0, 100),
349
+ agentCount: task.subtasks.length,
350
+ duration: Date.now() - new Date(task.createdAt).getTime(),
351
+ filesChanged: ciResult.filesChanged || [],
352
+ });
353
+ }
354
+ task.completedAt = new Date().toISOString();
355
+ task.status = TASK_STATUS.COMPLETED;
356
+ this.emit("task:complete", task);
357
+ }
358
+
287
359
  /** LLM-driven task decomposition into coding subtasks. */
288
- async _decompose(task) {
360
+ async _decompose(task, evolutionIngress = null) {
289
361
  assertCLILegacyMutationAllowed("Orchestrator._decompose");
290
362
  task.status = TASK_STATUS.DECOMPOSING;
291
363
  this.emit("task:decomposing", task);
@@ -302,7 +374,14 @@ export class Orchestrator extends EventEmitter {
302
374
  (task.context ? `\nAdditional context:\n${task.context}` : "");
303
375
 
304
376
  try {
305
- const raw = await this._chat(
377
+ const chat =
378
+ evolutionIngress === null
379
+ ? this._chat
380
+ : createChatFn({
381
+ ...this._llmOptions,
382
+ evolutionIngress,
383
+ });
384
+ const raw = await chat(
306
385
  [
307
386
  { role: "system", content: systemPrompt },
308
387
  { role: "user", content: userMsg },
@@ -317,7 +396,8 @@ export class Orchestrator extends EventEmitter {
317
396
  this.emit("task:decomposed", { task, subtasks });
318
397
  this._log(`Decomposed into ${subtasks.length} subtask(s)`);
319
398
  return subtasks;
320
- } catch {
399
+ } catch (error) {
400
+ if (isTerminalModelFailure(error)) throw error;
321
401
  // Fallback: treat whole task as single subtask
322
402
  const fallback = [
323
403
  { id: "sub-1", description: task.description, context: task.context },
@@ -328,7 +408,7 @@ export class Orchestrator extends EventEmitter {
328
408
  }
329
409
 
330
410
  /** Dispatch subtasks to the Claude Code pool. */
331
- async _dispatch(task) {
411
+ async _dispatch(task, evolutionIngress = null) {
332
412
  assertCLILegacyMutationAllowed("Orchestrator._dispatch");
333
413
  this.emit("agents:dispatched", { task, count: task.subtasks.length });
334
414
  this._log(
@@ -337,13 +417,14 @@ export class Orchestrator extends EventEmitter {
337
417
 
338
418
  const results = await this._router.dispatch(task.subtasks, {
339
419
  cwd: task.cwd,
420
+ ...(evolutionIngress === null ? {} : { evolutionIngress }),
340
421
  });
341
422
  this.emit("agents:complete", { task, results });
342
423
  return results;
343
424
  }
344
425
 
345
426
  /** Run CI command and retry loop. */
346
- async _ciLoop(task) {
427
+ async _ciLoop(task, evolutionIngress = null) {
347
428
  assertCLILegacyMutationAllowed("Orchestrator._ciLoop");
348
429
  for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
349
430
  task.status = TASK_STATUS.CI_CHECKING;
@@ -356,22 +437,10 @@ export class Orchestrator extends EventEmitter {
356
437
 
357
438
  if (ciResult.pass) {
358
439
  task.status = TASK_STATUS.CI_PASSED;
359
- task.completedAt = new Date().toISOString();
360
440
  this.emit("ci:pass", { task });
361
441
  this._log(`CI passed for task ${task.id}`);
362
442
 
363
- if (this.notifier.isConfigured && task.notify) {
364
- await this.notifier.notifySuccess({
365
- taskId: task.id,
366
- description: task.description.slice(0, 100),
367
- agentCount: task.subtasks.length,
368
- duration: Date.now() - new Date(task.createdAt).getTime(),
369
- filesChanged: ciResult.filesChanged || [],
370
- });
371
- }
372
-
373
- task.status = TASK_STATUS.COMPLETED;
374
- this.emit("task:complete", task);
443
+ await this._completeTask(task, evolutionIngress, ciResult);
375
444
  return;
376
445
  }
377
446
 
@@ -409,6 +478,7 @@ export class Orchestrator extends EventEmitter {
409
478
 
410
479
  task.agentResults = await this._router.dispatch(fixSubtasks, {
411
480
  cwd: task.cwd,
481
+ ...(evolutionIngress === null ? {} : { evolutionIngress }),
412
482
  });
413
483
  this._assertSuccessfulAgentResults(task);
414
484
  this.emit("agents:complete", { task, results: task.agentResults });
@@ -1,10 +1,5 @@
1
1
  import { createHash } from "node:crypto";
2
-
3
- const DISCOVERY_TOOLS = new Set([
4
- "search_files",
5
- "list_dir",
6
- "code_intelligence",
7
- ]);
2
+ import { EXPLORATION_TOOLS } from "./task-progress-tracker.js";
8
3
  const MAX_FILES = 12;
9
4
 
10
5
  function keyFor(filePath, args) {
@@ -34,6 +29,7 @@ export class ReadFileLoopGuard {
34
29
  this.repeatedBatches = 0;
35
30
  this.recoveryOfferedAt = 0;
36
31
  this.batch = null;
32
+ this.largeOutputs = new Set();
37
33
  }
38
34
 
39
35
  startBatch() {
@@ -145,14 +141,40 @@ export class ReadFileLoopGuard {
145
141
  return { ...page, readProgress: { newContent } };
146
142
  }
147
143
 
148
- record(tool, result) {
149
- if (!this.batch || result?.error) return;
144
+ record(tool, result, actionable = true) {
145
+ if (
146
+ !this.batch ||
147
+ result?.error ||
148
+ result?.success === false ||
149
+ result?.isError === true ||
150
+ result?.alreadyApplied === true ||
151
+ result?.changed === false
152
+ )
153
+ return;
150
154
  if (tool === "read_file") {
151
155
  if (result?.readProgress?.newContent === true) this.batch.advanced = true;
152
156
  if (result?.readRecovery?.action === "targeted-review")
153
157
  this.batch.advanced = true;
154
158
  if (result?.readProgress?.newContent === false) this.batch.duplicates++;
155
- } else if (!DISCOVERY_TOOLS.has(tool)) {
159
+ } else if (
160
+ (tool === "run_code" || tool === "run_shell") &&
161
+ typeof result?.output === "string" &&
162
+ result.output.length >= 8000
163
+ ) {
164
+ // Arbitrary code may just dump the same file again. Compare returned
165
+ // evidence, not code spelling or timings. Never cache/skip execution:
166
+ // identical stdout does not imply identical filesystem side effects.
167
+ const fingerprint = createHash("sha256")
168
+ .update(result.output)
169
+ .digest("hex");
170
+ if (this.largeOutputs.has(fingerprint)) this.batch.duplicates++;
171
+ else {
172
+ this.largeOutputs.add(fingerprint);
173
+ this.batch.advanced = true;
174
+ while (this.largeOutputs.size > 64)
175
+ this.largeOutputs.delete(this.largeOutputs.values().next().value);
176
+ }
177
+ } else if (actionable && !EXPLORATION_TOOLS.has(tool)) {
156
178
  this.batch.substantive = true;
157
179
  }
158
180
  }
@@ -163,6 +185,7 @@ export class ReadFileLoopGuard {
163
185
  this.repeatedBatches = 0;
164
186
  this.recoveryOfferedAt = 0;
165
187
  if (this.batch.substantive) {
188
+ this.largeOutputs.clear();
166
189
  for (const entry of this.progress.values()) entry.rereads.clear();
167
190
  }
168
191
  } else if (this.batch.duplicates) this.repeatedBatches++;
@@ -172,7 +195,7 @@ export class ReadFileLoopGuard {
172
195
 
173
196
  get recoveryHint() {
174
197
  return this.repeatedBatches >= 1
175
- ? "Repeated unchanged file reads detected. The runtime continues unfinished scans automatically and returns use-findings after EOF. Use the retained file outline to locate the relevant work, then implement/verify the user's task. Do not restart a whole-file scan after context compaction. A targeted search does not itself complete the task."
198
+ ? "Repeated file reads or identical large command outputs detected. Do not switch to run_code/run_shell to dump the same file again. Filter/count locally and print only relevant rows, totals and source line numbers, or use a focused search. The runtime continues unfinished read_file scans automatically and returns use-findings after EOF. Use the retained outline to perform the user's task. Do not restart a whole-file scan after context compaction; answer once the requested evidence is sufficient."
176
199
  : null;
177
200
  }
178
201
 
@@ -12,6 +12,8 @@ import crypto from "crypto";
12
12
  import { CLIContextEngineering } from "./cli-context-engineering.js";
13
13
  import { agentLoop, buildSystemPrompt, AGENT_TOOLS } from "./agent-core.js";
14
14
  import { feature } from "./feature-flags.js";
15
+ import { isEvolutionIngressFailure } from "./model-failure-policy.js";
16
+ import { captureAgentEvolutionIngress } from "./evolution/agent-evolution-ingress.js";
15
17
  import {
16
18
  createWorktree,
17
19
  removeWorktree,
@@ -197,6 +199,7 @@ export class SubAgentContext {
197
199
  this.iterationBudget = options.iterationBudget || null; // shared budget from parent
198
200
  this.sessionBudget = options.sessionBudget || null;
199
201
  this.hostResourceBudget = options.hostResourceBudget || null;
202
+ this.taskProgressTracker = options.taskProgressTracker || null;
200
203
  this.tokenBudget = options.tokenBudget || null;
201
204
  this.inheritedContext = options.inheritedContext || null;
202
205
  this.allowedTools = options.allowedTools ?? null; // null = all; [] = none
@@ -589,7 +592,13 @@ export class SubAgentContext {
589
592
  }
590
593
  return result;
591
594
  } catch (err) {
592
- if (err?.runtimeLedgerPersistence === true || this._workflowEffectId) {
595
+ if (
596
+ isEvolutionIngressFailure(err) ||
597
+ err?.runtimeLedgerPersistence === true ||
598
+ this._workflowEffectId
599
+ ) {
600
+ this.status = "failed";
601
+ this.completedAt = new Date().toISOString();
593
602
  throw err;
594
603
  }
595
604
  // If worktree creation fails (e.g. not a git repo), fall back to direct
@@ -635,6 +644,7 @@ export class SubAgentContext {
635
644
  subAgentBudget: this.subAgentBudget,
636
645
  sessionBudget: this.sessionBudget,
637
646
  hostResourceBudget: this.hostResourceBudget,
647
+ taskProgressTracker: this.taskProgressTracker,
638
648
  // This context's effective contract = the ceiling for its nested spawns.
639
649
  subAgentContract: this.subAgentContract,
640
650
  toolAdmission: this.toolAdmission,
@@ -656,6 +666,7 @@ export class SubAgentContext {
656
666
  options.subAgentContract = this.subAgentContract;
657
667
  options.sessionBudget = this.sessionBudget;
658
668
  options.hostResourceBudget = this.hostResourceBudget;
669
+ options.taskProgressTracker = this.taskProgressTracker;
659
670
  if (this._runAbortController) {
660
671
  options.signal = this._runAbortController.signal;
661
672
  }
@@ -875,12 +886,21 @@ export class SubAgentContext {
875
886
  options.approvalGate = this._approvalGate;
876
887
  }
877
888
 
889
+ const evolutionIngress =
890
+ options.evolutionIngress == null
891
+ ? null
892
+ : captureAgentEvolutionIngress(options.evolutionIngress);
893
+ if (evolutionIngress !== null) options.evolutionIngress = evolutionIngress;
894
+
878
895
  try {
879
896
  // Use a separate messages array for the agent loop
880
897
  // The agentLoop will append to this.messages directly
881
898
  const gen = agentLoop(this.messages, options);
882
899
 
883
900
  for await (const event of gen) {
901
+ if (evolutionIngress !== null) {
902
+ await evolutionIngress.ingestAgentEvent(event);
903
+ }
884
904
  this._iterationCount++;
885
905
 
886
906
  if (event.type === "run-started" && event.runId) {
@@ -1099,6 +1119,13 @@ export class SubAgentContext {
1099
1119
  this._tokenCount += Math.ceil((lastContent.length || 0) / 4);
1100
1120
  }
1101
1121
 
1122
+ if (event.type === "run-ended" && event.reason !== "complete") {
1123
+ this.forceComplete(event.reason || "unknown-terminal-reason", {
1124
+ partialContent: lastContent,
1125
+ artifacts,
1126
+ });
1127
+ }
1128
+
1102
1129
  // Emit progress to consumer if callback provided
1103
1130
  if (this._onProgress) {
1104
1131
  try {
@@ -1161,7 +1188,13 @@ export class SubAgentContext {
1161
1188
  throw error;
1162
1189
  }
1163
1190
  } catch (err) {
1164
- if (err?.runtimeLedgerPersistence === true || this._workflowEffectId) {
1191
+ if (
1192
+ isEvolutionIngressFailure(err) ||
1193
+ err?.runtimeLedgerPersistence === true ||
1194
+ this._workflowEffectId
1195
+ ) {
1196
+ this.status = "failed";
1197
+ this.completedAt = new Date().toISOString();
1165
1198
  throw err;
1166
1199
  }
1167
1200
  if (this.isAborted()) {
@@ -1295,6 +1328,8 @@ export class SubAgentContext {
1295
1328
  : "";
1296
1329
  this.result = {
1297
1330
  summary: `(Sub-agent force-completed: ${reason})${partialText}`,
1331
+ incomplete: true,
1332
+ completionReason: reason,
1298
1333
  artifacts: Array.isArray(partial.artifacts) ? partial.artifacts : [],
1299
1334
  tokenCount: this._tokenCount,
1300
1335
  toolsUsed: [...new Set(this._toolsUsed)],
@@ -0,0 +1,223 @@
1
+ import { createHash } from "node:crypto";
2
+
3
+ // Discovery and bookkeeping are useful, but are not evidence that the task
4
+ // advanced. In particular, dispatching a child must not buy a fresh budget.
5
+ export const EXPLORATION_TOOLS = new Set([
6
+ "read_file",
7
+ "search_files",
8
+ "list_dir",
9
+ "code_intelligence",
10
+ "tool_search",
11
+ "list_skills",
12
+ "web_search",
13
+ "web_fetch",
14
+ "todo_write",
15
+ "spawn_sub_agent",
16
+ "notify",
17
+ "check_shell",
18
+ ]);
19
+
20
+ export const TASK_RECOVERY_TOOLS = [
21
+ "read_file",
22
+ "list_dir",
23
+ "todo_write",
24
+ "spawn_sub_agent",
25
+ "tool_search",
26
+ ];
27
+
28
+ // The runtime admits at most 32 spawned agents plus the root. Keep bounded
29
+ // per-owner evidence so busy children cannot evict their parent's checkpoint.
30
+ const MAX_CHECKPOINT_OWNERS = 33;
31
+
32
+ function boundedText(value, limit) {
33
+ return typeof value === "string" ? value.slice(0, limit) : "";
34
+ }
35
+
36
+ function remember(map, key, value, limit) {
37
+ map.delete(key);
38
+ map.set(key, value);
39
+ while (map.size > limit) map.delete(map.keys().next().value);
40
+ }
41
+
42
+ /**
43
+ * Run-tree exploration accounting, separate from file coverage and permissions.
44
+ * This object is shared by parent/child loops, not serialized into model input.
45
+ * New file pages advance coverage but do not reset the exploration counter.
46
+ * Interventions are advisory / one-request tool narrowing, never completion
47
+ * verdicts or a hard deadline for legitimate research and monitoring tasks.
48
+ */
49
+ export class TaskProgressTracker {
50
+ constructor({ now = Date.now } = {}) {
51
+ this.now = now;
52
+ this.explorationCalls = 0;
53
+ this.lastProgressAt = now();
54
+ this.epoch = 0;
55
+ this.commandOutputs = new Map();
56
+ this.plans = new Map();
57
+ this.childFindings = new Map();
58
+ this.lastActions = [];
59
+ }
60
+
61
+ retainChildResult(id, result, owner = "root") {
62
+ const summary = boundedText(result?.summary, 1600);
63
+ if (!summary) return;
64
+ remember(
65
+ this.childFindings,
66
+ JSON.stringify([owner, boundedText(id, 160)]),
67
+ {
68
+ owner,
69
+ id: boundedText(id, 160),
70
+ summary,
71
+ error: boundedText(result?.error, 240) || null,
72
+ },
73
+ MAX_CHECKPOINT_OWNERS * 3 + 1,
74
+ );
75
+ const owned = [...this.childFindings].filter(
76
+ ([, entry]) => entry.owner === owner,
77
+ );
78
+ for (const [key] of owned.slice(0, -3)) this.childFindings.delete(key);
79
+ while (this.childFindings.size > MAX_CHECKPOINT_OWNERS * 3)
80
+ this.childFindings.delete(this.childFindings.keys().next().value);
81
+ }
82
+
83
+ record(tool, result, args = {}, owner = "root") {
84
+ const failed =
85
+ !result ||
86
+ !!result.error ||
87
+ result.success === false ||
88
+ result.isError === true ||
89
+ (Number.isInteger(result.exitCode) && result.exitCode !== 0);
90
+ const noChange =
91
+ result?.alreadyApplied === true ||
92
+ result?.changed === false ||
93
+ (tool === "edit_file" &&
94
+ typeof args.old_string === "string" &&
95
+ args.old_string === args.new_string);
96
+
97
+ if (tool === "spawn_sub_agent")
98
+ this.retainChildResult(result?.subAgentId, result, owner);
99
+ if (tool === "todo_write" && !failed && Array.isArray(args.todos)) {
100
+ // Retain current plan data through compaction without treating a model's
101
+ // status claims as verified task completion. Keep parent/child plans apart.
102
+ remember(
103
+ this.plans,
104
+ boundedText(owner, 120),
105
+ args.todos.slice(0, 8).map((todo) => ({
106
+ content: boundedText(todo?.content, 240),
107
+ status: boundedText(todo?.status, 40),
108
+ })),
109
+ MAX_CHECKPOINT_OWNERS,
110
+ );
111
+ }
112
+
113
+ let exploration = EXPLORATION_TOOLS.has(tool);
114
+ if (tool === "run_code" || tool === "run_shell") {
115
+ // Repeated short dumps must not evade the large-output loop guard. These
116
+ // fingerprints affect guidance only: every authorized command still runs.
117
+ const output = typeof result?.output === "string" ? result.output : "";
118
+ const digest = createHash("sha256").update(output).digest("hex");
119
+ exploration = output.length >= 8000 || this.commandOutputs.has(digest);
120
+ if (!failed) remember(this.commandOutputs, digest, true, 64);
121
+ }
122
+ if (
123
+ failed ||
124
+ noChange ||
125
+ exploration ||
126
+ result?.background === true ||
127
+ result?.status === "running"
128
+ ) {
129
+ this.explorationCalls++;
130
+ return false;
131
+ }
132
+
133
+ // This is an observed tool outcome, not a semantic proof that the user's
134
+ // objective was met. Never count prose, TODO completion, or spawn handles.
135
+ this.lastActions.push({
136
+ owner,
137
+ tool,
138
+ path: boundedText(result.path || args.path, 320),
139
+ output: boundedText(result.output, 400),
140
+ });
141
+ const ownedActions = this.lastActions
142
+ .filter((entry) => entry.owner === owner)
143
+ .slice(-4);
144
+ this.lastActions = [
145
+ ...this.lastActions.filter((entry) => entry.owner !== owner),
146
+ ...ownedActions,
147
+ ].slice(-MAX_CHECKPOINT_OWNERS * 4);
148
+ this.explorationCalls = 0;
149
+ this.lastProgressAt = this.now();
150
+ this.epoch++;
151
+ return true;
152
+ }
153
+
154
+ get intervention() {
155
+ const calls = this.explorationCalls;
156
+ const elapsedMs = Math.max(0, this.now() - this.lastProgressAt);
157
+ // Clock-only hints require several observations, so a slow first read or
158
+ // an intentional wait cannot immediately trigger a recovery request.
159
+ if (calls < 12 && !(calls >= 4 && elapsedMs >= 300000)) return null;
160
+ const stage = Math.max(1, Math.floor(calls / 12));
161
+ const recovery = stage >= 2;
162
+ const message =
163
+ `Task progress: ${calls} exploration/coordination calls across this run and its sub-agents ` +
164
+ `since the last actionable tool outcome (${Math.floor(elapsedMs / 60000)} min). ` +
165
+ (recovery
166
+ ? "Use the retained findings now to choose a concrete action."
167
+ : "Consolidate findings and choose the smallest concrete next step.");
168
+ return {
169
+ key: `${this.epoch}:${stage}`,
170
+ recovery,
171
+ message,
172
+ guidance:
173
+ message +
174
+ " For an implementation task, make the smallest justified, authorized change and validate it. " +
175
+ "For research/review, synthesize evidence-backed findings; do not write files merely to clear this warning. " +
176
+ "If evidence is insufficient, name the exact missing fact and use a focused search or bounded computation. " +
177
+ "Do not restart general investigation, rewrite the plan, or delegate the same research. " +
178
+ "A child exhausting its budget is not task completion. Preserve useful partial findings and continue the original task. " +
179
+ "Normal tool availability resumes on the next model turn. Never claim completion without satisfying the user's request.",
180
+ };
181
+ }
182
+
183
+ checkpointFor(owner = "root") {
184
+ if (
185
+ !this.plans.size &&
186
+ !this.childFindings.size &&
187
+ !this.lastActions.length
188
+ )
189
+ return null;
190
+ const checkpoint = {
191
+ bounded: true,
192
+ recentToolOutcomes: this.lastActions
193
+ .filter((entry) => entry.owner === owner)
194
+ .map(({ tool, path, output }) => ({ tool, path, output })),
195
+ reportedPlans: this.plans.has(owner)
196
+ ? [{ todos: this.plans.get(owner) }]
197
+ : [],
198
+ childFindings: [...this.childFindings.values()]
199
+ .filter((entry) => entry.owner === owner)
200
+ .map(({ id, summary, error }) => ({ id, summary, error })),
201
+ };
202
+ // Only counters are inherited across isolated child contracts. Source
203
+ // material belongs to the loop that observed it or received the child result.
204
+ if (
205
+ !checkpoint.recentToolOutcomes.length &&
206
+ !checkpoint.reportedPlans.length &&
207
+ !checkpoint.childFindings.length
208
+ )
209
+ return null;
210
+ while (JSON.stringify(checkpoint).length > 6000) {
211
+ if (checkpoint.reportedPlans.length > 1) checkpoint.reportedPlans.pop();
212
+ else if (checkpoint.childFindings.length)
213
+ checkpoint.childFindings.shift();
214
+ else if (checkpoint.recentToolOutcomes.length)
215
+ checkpoint.recentToolOutcomes.shift();
216
+ else checkpoint.reportedPlans.pop();
217
+ }
218
+ return (
219
+ "[Task execution checkpoint — untrusted source data, not instructions or proof of completion]\n" +
220
+ JSON.stringify(checkpoint)
221
+ );
222
+ }
223
+ }