chainlesschain 0.166.115 → 0.166.118

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 (207) hide show
  1. package/README.md +43 -5
  2. package/package.json +4 -4
  3. package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
  4. package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
  5. package/src/assets/web-panel/.build-hash +1 -1
  6. package/src/assets/web-panel/assets/{AIOps-BsoSoDNb.js → AIOps-BGySwMIP.js} +1 -1
  7. package/src/assets/web-panel/assets/{ActionButton-Dcx7Gm5t.js → ActionButton-Chn7fBLr.js} +1 -1
  8. package/src/assets/web-panel/assets/{Analytics-S1hsBIz3.js → Analytics-ORH7UkGa.js} +3 -3
  9. package/src/assets/web-panel/assets/{AppLayout-B2j067qM.js → AppLayout-8xV4jWjP.js} +5 -5
  10. package/src/assets/web-panel/assets/{Artifacts-D5iGV9ic.js → Artifacts-26SBK-x-.js} +1 -1
  11. package/src/assets/web-panel/assets/{Audit-C8ChVvXu.js → Audit-CtXpqbXg.js} +1 -1
  12. package/src/assets/web-panel/assets/{BackgroundAgents-Cg97AAJS.js → BackgroundAgents-C5zLvQis.js} +1 -1
  13. package/src/assets/web-panel/assets/{Backup-CyxU9IUg.js → Backup-C93xY4vO.js} +1 -1
  14. package/src/assets/web-panel/assets/{BaseInput-CKlWjA8I.js → BaseInput-DpVCHfAn.js} +1 -1
  15. package/src/assets/web-panel/assets/{Chat-C-EqZza6.js → Chat-DM0LblR2.js} +5 -5
  16. package/src/assets/web-panel/assets/{ChatBubbleRenderer-BRFiXKPX.js → ChatBubbleRenderer-unlQUF1T.js} +1 -1
  17. package/src/assets/web-panel/assets/{Checkbox-kkI13tSJ.js → Checkbox-BsAt3cKR.js} +1 -1
  18. package/src/assets/web-panel/assets/{Codegen-NlqEDwHK.js → Codegen-E_kp4KFd.js} +1 -1
  19. package/src/assets/web-panel/assets/{Col-CfepEu79.js → Col-6msR3T6I.js} +1 -1
  20. package/src/assets/web-panel/assets/{Community-BRo0qLXM.js → Community-PyX9c5D-.js} +1 -1
  21. package/src/assets/web-panel/assets/{Compact-BMu8TP0E.js → Compact-7G1bVDSH.js} +1 -1
  22. package/src/assets/web-panel/assets/{Compliance-B7Q3Moef.js → Compliance-DcHN7GlD.js} +1 -1
  23. package/src/assets/web-panel/assets/{Cowork-BVwt7Xmc.js → Cowork-WUIHJYDx.js} +3 -3
  24. package/src/assets/web-panel/assets/{Cron-CgBv20Qy.js → Cron-CWgCbptg.js} +2 -2
  25. package/src/assets/web-panel/assets/{Crosschain-CwcSBJk2.js → Crosschain-BzKZ6roD.js} +1 -1
  26. package/src/assets/web-panel/assets/{DID-d20rCiIm.js → DID-r7zxeItn.js} +2 -2
  27. package/src/assets/web-panel/assets/{Dashboard-PpZaUYpS.js → Dashboard-D3pBiN2H.js} +2 -2
  28. package/src/assets/web-panel/assets/{Dropdown-DjsLdX_Z.js → Dropdown-C4otRJlZ.js} +1 -1
  29. package/src/assets/web-panel/assets/{EmailListRenderer-CaPkrtxn.js → EmailListRenderer-CzDTC8lm.js} +1 -1
  30. package/src/assets/web-panel/assets/{EvolutionSettings-DDY8cQnE.js → EvolutionSettings-DGkXiIs-.js} +1 -1
  31. package/src/assets/web-panel/assets/{FamilyGuardDashboard-VQavMjyj.js → FamilyGuardDashboard-BKdEyuiR.js} +1 -1
  32. package/src/assets/web-panel/assets/{Federation-D0GvKQgI.js → Federation-dsI-xcpf.js} +1 -1
  33. package/src/assets/web-panel/assets/{FormItemContext-Dl_TWHmb.js → FormItemContext-CEEb1fMR.js} +1 -1
  34. package/src/assets/web-panel/assets/{GenericCardRenderer-Bny2uagG.js → GenericCardRenderer-D_mfO3Ts.js} +1 -1
  35. package/src/assets/web-panel/assets/{Git-B01KXq47.js → Git-CBwr2ZI3.js} +2 -2
  36. package/src/assets/web-panel/assets/{Governance-F4c4Vwo1.js → Governance-D-Wy2Jjr.js} +1 -1
  37. package/src/assets/web-panel/assets/{Inference-_025Q-8K.js → Inference-B4Yk_IRx.js} +1 -1
  38. package/src/assets/web-panel/assets/{KnowledgeGraph-DwbTmQb1.js → KnowledgeGraph-DoI7bi6m.js} +1 -1
  39. package/src/assets/web-panel/assets/{Logs-CnNo0hCm.js → Logs-Ce1IiKAj.js} +2 -2
  40. package/src/assets/web-panel/assets/MarkdownRenderer-GND_8y0V.js +1 -0
  41. package/src/assets/web-panel/assets/{Marketplace-Dkz5bv7F.js → Marketplace-CsIEByzK.js} +1 -1
  42. package/src/assets/web-panel/assets/{McpTools-CBtRwDW_.js → McpTools-_DRzjcIn.js} +3 -3
  43. package/src/assets/web-panel/assets/{Memory-Y9jnyTb7.js → Memory-zvLpyi__.js} +2 -2
  44. package/src/assets/web-panel/assets/{MobileBridge-Br1urkOz.js → MobileBridge-DXd1ik2Z.js} +1 -1
  45. package/src/assets/web-panel/assets/{MobileProjects-DnsyuerX.js → MobileProjects-DKh2q-Y9.js} +1 -1
  46. package/src/assets/web-panel/assets/{Mtc-he3ZzieF.js → Mtc-Ct-fhtIx.js} +4 -4
  47. package/src/assets/web-panel/assets/{MtcAudit-BadphAuN.js → MtcAudit-J4zY3Oqk.js} +2 -2
  48. package/src/assets/web-panel/assets/{Multisig-3_pVLymK.js → Multisig-B2HJMCKe.js} +3 -3
  49. package/src/assets/web-panel/assets/{NLProgramming-DmtmHfsI.js → NLProgramming-CwcSmU4q.js} +1 -1
  50. package/src/assets/web-panel/assets/{Notes-CE4L2O55.js → Notes-Da53L6wb.js} +4 -4
  51. package/src/assets/web-panel/assets/{NotificationSettings-B7QmfJn9.js → NotificationSettings-BxhufdrA.js} +1 -1
  52. package/src/assets/web-panel/assets/{OrderTableRenderer-O0wRSyJ0.js → OrderTableRenderer-BoFwohAi.js} +1 -1
  53. package/src/assets/web-panel/assets/{Organization-BrlMSsyT.js → Organization-MIsMrUes.js} +4 -4
  54. package/src/assets/web-panel/assets/{Overflow-CY4ULPrZ.js → Overflow-Dy2P4v3q.js} +1 -1
  55. package/src/assets/web-panel/assets/{P2P-kIANZYKd.js → P2P-CD9Sxn2y.js} +2 -2
  56. package/src/assets/web-panel/assets/{PdhVaultBrowser-DEgB4rvF.js → PdhVaultBrowser-BvBWgfG0.js} +5 -5
  57. package/src/assets/web-panel/assets/{Permissions-CWxywRp5.js → Permissions-CwOlDRis.js} +4 -4
  58. package/src/assets/web-panel/assets/{PersonalDataHub-DAg7iCbr.js → PersonalDataHub-CZYaxEpv.js} +4 -4
  59. package/src/assets/web-panel/assets/{Pipeline-Brc6ONnR.js → Pipeline-kLU7PUbB.js} +1 -1
  60. package/src/assets/web-panel/assets/{Privacy-CcinYTL8.js → Privacy-BVRycSiI.js} +1 -1
  61. package/src/assets/web-panel/assets/{ProjectInit-Bz8XEsom.js → ProjectInit-DP3pr7uJ.js} +2 -2
  62. package/src/assets/web-panel/assets/{ProjectSettings-CsOMlSTZ.js → ProjectSettings-CACaDYjs.js} +2 -2
  63. package/src/assets/web-panel/assets/Projects-CB1k4zTC.js +1 -0
  64. package/src/assets/web-panel/assets/{Providers-CeunOQiH.js → Providers-D7Y9WHRE.js} +1 -1
  65. package/src/assets/web-panel/assets/{QrScannerModal-CN2a2_Fb.js → QrScannerModal-CeP8xzs1.js} +1 -1
  66. package/src/assets/web-panel/assets/{QuickAsk-CVeLif3e.js → QuickAsk-iJVFrhZ2.js} +1 -1
  67. package/src/assets/web-panel/assets/{Recommend-1k9WOEGM.js → Recommend-DmTpnagw.js} +1 -1
  68. package/src/assets/web-panel/assets/{RemoteSession-Q8UCqIMw.js → RemoteSession-C6ek8Uni.js} +2 -2
  69. package/src/assets/web-panel/assets/{Reputation-CkrCgXKM.js → Reputation-CPfwc9de.js} +1 -1
  70. package/src/assets/web-panel/assets/{Row-JFdvuTzi.js → Row-C1wwtSMJ.js} +1 -1
  71. package/src/assets/web-panel/assets/{RssFeed-C74JHCmk.js → RssFeed-BiDJsqaH.js} +3 -3
  72. package/src/assets/web-panel/assets/{Search-DrJiVO1T.js → Search-BF6Aon95.js} +1 -1
  73. package/src/assets/web-panel/assets/{Security-BJzNlSJq.js → Security-Bps0XnV4.js} +3 -3
  74. package/src/assets/web-panel/assets/{Services-D4TLMnJm.js → Services-uf92smGR.js} +2 -2
  75. package/src/assets/web-panel/assets/{Skeleton-cswTDqhh.js → Skeleton-DQd4eVWW.js} +1 -1
  76. package/src/assets/web-panel/assets/{Skills-Bv0rM1BS.js → Skills-DgamiYa5.js} +1 -1
  77. package/src/assets/web-panel/assets/{Sla-D9rE7hNh.js → Sla-CF1IVIrm.js} +1 -1
  78. package/src/assets/web-panel/assets/SpeechSettings-Bzxmjbpc.js +1 -0
  79. package/src/assets/web-panel/assets/{SyncSettings-BwnMG8kq.js → SyncSettings-B8zKauiq.js} +2 -2
  80. package/src/assets/web-panel/assets/{Tasks-wJvU24cB.js → Tasks-DPKV_xSt.js} +1 -1
  81. package/src/assets/web-panel/assets/{Templates-CZbRU3tN.js → Templates-BikeSZIF.js} +1 -1
  82. package/src/assets/web-panel/assets/{Tenant-_jbpFJPZ.js → Tenant-CEaUaDkJ.js} +1 -1
  83. package/src/assets/web-panel/assets/{Terminal-BzNm5WKZ.js → Terminal-ZPgOSQ_q.js} +3 -3
  84. package/src/assets/web-panel/assets/{TimelineRenderer-bmybWjuS.js → TimelineRenderer-DmyB4Udk.js} +1 -1
  85. package/src/assets/web-panel/assets/{Tokens-o1WDcqVQ.js → Tokens-g85Pm5TO.js} +1 -1
  86. package/src/assets/web-panel/assets/{Trigger-BB1D6sIB.js → Trigger-D202hx9a.js} +1 -1
  87. package/src/assets/web-panel/assets/{Trust-CLxdCfy2.js → Trust-DzvQYVFy.js} +1 -1
  88. package/src/assets/web-panel/assets/{UkeySign-B9LS6vS0.js → UkeySign-KRzwddVg.js} +1 -1
  89. package/src/assets/web-panel/assets/{VideoEditing-Bg0-wxjz.js → VideoEditing-IRBXLO2z.js} +1 -1
  90. package/src/assets/web-panel/assets/{Wallet-Bw0G2F6P.js → Wallet-DSf5KPgQ.js} +4 -4
  91. package/src/assets/web-panel/assets/{WebAuthn-irEiNY9b.js → WebAuthn-DNPxLTCc.js} +5 -5
  92. package/src/assets/web-panel/assets/{WorkflowEditor-Bh08FbJs.js → WorkflowEditor-C3wAtVcK.js} +1 -1
  93. package/src/assets/web-panel/assets/{addon-fit-CK6X9sAG.js → addon-fit-CbkjSUJl.js} +1 -1
  94. package/src/assets/web-panel/assets/{chat-De-FPjVT.js → chat-q3XXUtv2.js} +1 -1
  95. package/src/assets/web-panel/assets/{colors-ygdyvinU.js → colors-CF54SNei.js} +1 -1
  96. package/src/assets/web-panel/assets/{compact-item-BQ9jH9KV.js → compact-item-BaRkvZuT.js} +1 -1
  97. package/src/assets/web-panel/assets/{createContext-BFuVSyox.js → createContext-CDR9hsfs.js} +1 -1
  98. package/src/assets/web-panel/assets/devWarning-1LO-NplX.js +1 -0
  99. package/src/assets/web-panel/assets/{hasIn-i19GtR1P.js → hasIn-DlC--S8R.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-DS1IwwGL.js → index-B0Ptc7yu.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-B1IsP_JO.js → index-B0V9rgdu.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-CWfgeaG4.js → index-BEiUlFKb.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-DTY20pWu.js → index-BJO0n1LQ.js} +1 -1
  104. package/src/assets/web-panel/assets/index-BLaJsev4.js +1 -0
  105. package/src/assets/web-panel/assets/index-BLmviChG.js +1 -0
  106. package/src/assets/web-panel/assets/{index-IXkif6J_.js → index-BU5DJqk7.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-BVhtukYX.js → index-BY-Tf3OM.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-BKlU5VZy.js → index-BZrE0Go8.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Bw5pTpnI.js → index-BizdX2X5.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-BGMxK155.js → index-C87Yr3h1.js} +1 -1
  111. package/src/assets/web-panel/assets/{index-DVnFgasM.js → index-C9Wypz9e.js} +1 -1
  112. package/src/assets/web-panel/assets/{index-C61w3omz.js → index-CAoG_E-q.js} +1 -1
  113. package/src/assets/web-panel/assets/{index-l5-J0jHx.js → index-CAxSyMrF.js} +1 -1
  114. package/src/assets/web-panel/assets/{index-28DjsABm.js → index-CC5HjNM6.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-BPUCvc8i.js → index-CNZQEZ9g.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-CpdXhhMY.js → index-CPvIhha6.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-DAboGZTw.js → index-CR_wqMGy.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-DL7ewjD2.js → index-CSClXoB3.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-Bhf-MuUh.js → index-CZ8azVgB.js} +3 -3
  120. package/src/assets/web-panel/assets/{index-BaaydJcC.js → index-Ccc5z8eJ.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-B2LieObB.js → index-CeiKbM3a.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-We2nK3ju.js → index-Cl6av3X7.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-m8waSAyv.js → index-CtGfeD7E.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-cDJsyAkI.js → index-Ctid12Gq.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DlwxUZQL.js → index-D0H-N0uG.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-BBYiCI1d.js → index-D0vIgprF.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-_9tUBcLm.js → index-D4wUDFRg.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-4HoFz1MA.js → index-DJFipyK7.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-Cq9k4-Ws.js → index-DX2REKNp.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-DuuOX5u3.js → index-Dc3gD0cw.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-DgjLaB7k.js → index-DiQzer2R.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-CMNjaSir.js → index-DntKLOs9.js} +1 -1
  133. package/src/assets/web-panel/assets/{index-vXtH3o6O.js → index-Dplhl6gh.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-BLMtCKAY.js → index-Dq8q_PWB.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-CXrk8OYO.js → index-IVQdOBNN.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-CBVcGaxk.js → index-Kerduyao.js} +1 -1
  137. package/src/assets/web-panel/assets/{index-BKblSCL9.js → index-W6cLGjpW.js} +1 -1
  138. package/src/assets/web-panel/assets/{index-CgoSgmjK.js → index-qZDNFll9.js} +1 -1
  139. package/src/assets/web-panel/assets/{initDefaultProps-B_EZHeqN.js → initDefaultProps-Ccz7v71u.js} +1 -1
  140. package/src/assets/web-panel/assets/{markdown-Yo_c6Krv.js → markdown-Bq2x0XsR.js} +1 -1
  141. package/src/assets/web-panel/assets/markdown-DUKxbhE4.js +51 -0
  142. package/src/assets/web-panel/assets/{motion-BrVb_Gy1.js → motion-BlCLpVDp.js} +1 -1
  143. package/src/assets/web-panel/assets/{move-CKxVRL_J.js → move-B80G7fLU.js} +1 -1
  144. package/src/assets/web-panel/assets/{mtc-parser-C80rvQ1J.js → mtc-parser-Djw08NJh.js} +1 -1
  145. package/src/assets/web-panel/assets/{omit-De5vD7BR.js → omit-Bg_G1eUr.js} +1 -1
  146. package/src/assets/web-panel/assets/{pickAttrs-BTyEDjth.js → pickAttrs-Df9zYUg2.js} +1 -1
  147. package/src/assets/web-panel/assets/{placementArrow-BWR94AjR.js → placementArrow-DjCDLhJ4.js} +1 -1
  148. package/src/assets/web-panel/assets/{responsiveObserve-1g-Vnibk.js → responsiveObserve--Naz7NgY.js} +1 -1
  149. package/src/assets/web-panel/assets/{slide-Dmg6dYuF.js → slide-CHn3ald-.js} +1 -1
  150. package/src/assets/web-panel/assets/{statusUtils-Ddj6rSab.js → statusUtils-BiGwoIK_.js} +1 -1
  151. package/src/assets/web-panel/assets/{styleChecker-DyP1mPDf.js → styleChecker-Zf2dQx1j.js} +1 -1
  152. package/src/assets/web-panel/assets/{useFlexGapSupport-D3d_0YuY.js → useFlexGapSupport-sLES8nyD.js} +1 -1
  153. package/src/assets/web-panel/assets/{useFs-M3vq-gE2.js → useFs-DV1Hl4qu.js} +1 -1
  154. package/src/assets/web-panel/assets/{usePersonalDataHub-GtP2TgtK.js → usePersonalDataHub-CZXr2Qxg.js} +1 -1
  155. package/src/assets/web-panel/assets/{vnode-BurE2ATQ.js → vnode-e8Eo3Oyl.js} +1 -1
  156. package/src/assets/web-panel/assets/{xterm-BZcWGsqw.js → xterm-zbskxxGA.js} +1 -1
  157. package/src/assets/web-panel/assets/{zoom-Ch-ViiDe.js → zoom-B8A6xKMF.js} +1 -1
  158. package/src/assets/web-panel/index.html +1 -1
  159. package/src/commands/compact.js +7 -2
  160. package/src/data/changelog.json +27 -1
  161. package/src/harness/jsonl-session-store.js +80 -74
  162. package/src/harness/prompt-compressor.js +57 -3
  163. package/src/lib/artifact-store.js +129 -20
  164. package/src/lib/bounded-artifact-file-read.js +128 -46
  165. package/src/lib/context-memory-kernel/context-image-transport.js +248 -0
  166. package/src/lib/context-memory-kernel/jsonl-session-context-port.js +4 -1
  167. package/src/lib/context-memory-kernel/live-compaction.js +40 -10
  168. package/src/lib/context-memory-kernel/message-adapter.js +80 -10
  169. package/src/lib/context-memory-kernel/message-bundle-store.js +1140 -0
  170. package/src/lib/context-memory-kernel/provider-context.js +23 -8
  171. package/src/lib/evolution/agent-evolution-ingress.js +103 -19
  172. package/src/lib/evolution/agent-evolution-runtime-composition.js +65 -27
  173. package/src/lib/evolution/agent-model-projection.js +90 -18
  174. package/src/lib/evolution/evidence-json-text.js +341 -42
  175. package/src/lib/evolution/evolution-artifact-ports.js +1005 -83
  176. package/src/lib/evolution/evolution-evidence-artifact-adapter.js +59 -15
  177. package/src/lib/evolution/evolution-evidence-projector.js +153 -16
  178. package/src/lib/evolution/evolution-evidence-storage-layout.js +115 -0
  179. package/src/lib/evolution/evolution-file-witness.js +7 -3
  180. package/src/lib/evolution/evolution-ledger-file-manifest-catalog.js +6 -2
  181. package/src/lib/evolution/evolution-ledger-file-manifest-head-store.js +6 -2
  182. package/src/lib/evolution/evolution-ledger.js +226 -55
  183. package/src/lib/evolution/evolution-private-storage.js +20 -0
  184. package/src/lib/evolution/evolution-run-ledger-adapter.js +298 -11
  185. package/src/lib/evolution/evolution-windows-directory-durability.js +215 -32
  186. package/src/lib/evolution/local-ui-evolution-runtime.js +3 -38
  187. package/src/lib/evolution/local-ui-signing-authority.js +69 -0
  188. package/src/lib/image-token-estimate.js +59 -0
  189. package/src/lib/ollama-provider-fetch.js +33 -0
  190. package/src/lib/provider-stream.js +14 -13
  191. package/src/lib/read-file-loop-guard.js +7 -4
  192. package/src/lib/session-history-origins.js +94 -35
  193. package/src/lib/session-message-provenance.js +26 -2
  194. package/src/lib/session-runtime-retention.js +10 -1
  195. package/src/lib/session-transcript-history.js +5 -1
  196. package/src/lib/session-transcript-migration.js +67 -12
  197. package/src/lib/storage-failure-cause-codes.js +449 -0
  198. package/src/lib/tool-result-preview.js +276 -0
  199. package/src/runtime/agent-core.js +111 -92
  200. package/src/runtime/headless-stream.js +121 -27
  201. package/src/assets/web-panel/assets/MarkdownRenderer-D8_iZief.js +0 -1
  202. package/src/assets/web-panel/assets/Projects-BeSOM6wi.js +0 -1
  203. package/src/assets/web-panel/assets/SpeechSettings-Bfhvin8B.js +0 -1
  204. package/src/assets/web-panel/assets/devWarning-c2I2Rn4_.js +0 -1
  205. package/src/assets/web-panel/assets/index-CTs4dYcV.js +0 -1
  206. package/src/assets/web-panel/assets/index-DeuvaW15.js +0 -1
  207. package/src/assets/web-panel/assets/markdown-CsiA8-E5.js +0 -50
@@ -11,6 +11,11 @@ import {
11
11
  memoryRecordsToContextItems,
12
12
  messagesToContextItems,
13
13
  } from "./message-adapter.js";
14
+ import {
15
+ adjustContextImageTokenEstimates,
16
+ captureContextImageTransport,
17
+ restoreContextImageTransport,
18
+ } from "./context-image-transport.js";
14
19
 
15
20
  export const SEMANTIC_CANDIDATE_REQUEST_SCHEMA =
16
21
  "chainlesschain.context-memory-semantic-candidate-request/v1";
@@ -217,12 +222,17 @@ export async function prepareCanonicalProviderContext(
217
222
  ),
218
223
  ...(semanticCandidates === undefined ? {} : { semanticCandidates }),
219
224
  });
220
- const messageItems = messagesToContextItems(messages, {
221
- sessionId,
222
- allowedSinks: [sink],
223
- trustCurrentSystemPolicy: true,
224
- trustedSystemIndexes: options.contextMemoryTrustedSystemIndexes,
225
- });
225
+ const imageTransport = captureContextImageTransport(messages);
226
+ const messageItems = adjustContextImageTokenEstimates(
227
+ messagesToContextItems(imageTransport.messages, {
228
+ sessionId,
229
+ allowedSinks: [sink],
230
+ trustCurrentSystemPolicy: true,
231
+ trustedSystemIndexes: options.contextMemoryTrustedSystemIndexes,
232
+ allowExternalization: false,
233
+ }),
234
+ imageTransport.captures,
235
+ );
226
236
  const memoryItems = memoryRecordsToContextItems(
227
237
  recall.results.map((entry) => entry.record),
228
238
  { insertionSequence: Math.max(0, messages.length - 1) },
@@ -290,9 +300,14 @@ export async function prepareCanonicalProviderContext(
290
300
  sessionHead,
291
301
  memoryRevision: recall.memoryRevision,
292
302
  });
303
+ const selectedMessages = contextItemsToMessages(
304
+ plan.selected.filter((item) => item.kind !== "tool-schema"),
305
+ { sessionId },
306
+ );
293
307
  return {
294
- messages: contextItemsToMessages(
295
- plan.selected.filter((item) => item.kind !== "tool-schema"),
308
+ messages: restoreContextImageTransport(
309
+ selectedMessages,
310
+ imageTransport.captures,
296
311
  ),
297
312
  selectedToolNames: toolItems
298
313
  .filter((item) => plan.selectedItemIds.includes(item.itemId))
@@ -1,6 +1,7 @@
1
1
  import crypto from "node:crypto";
2
2
  import { types } from "node:util";
3
3
  import evolutionRun from "@chainlesschain/session-core/evolution-run";
4
+ import { storageFailureCauseSuffix } from "../storage-failure-cause-codes.js";
4
5
 
5
6
  import { EvolutionEvidenceArtifactAdapter } from "./evolution-evidence-artifact-adapter.js";
6
7
  import {
@@ -8,13 +9,21 @@ import {
8
9
  EVOLUTION_SKILL_DECISION_PROJECTION_RULESET_DIGEST,
9
10
  EVOLUTION_PROJECTION_RULESET_DIGEST,
10
11
  } from "./evolution-evidence-projector.js";
11
- import { EvolutionRunLedgerAdapter } from "./evolution-run-ledger-adapter.js";
12
+ import {
13
+ EvolutionRunLedgerAdapter,
14
+ captureEvolutionRunAppendNext,
15
+ } from "./evolution-run-ledger-adapter.js";
16
+ import {
17
+ evidenceStorageLayoutForRun,
18
+ validateEvidenceStorageLayout,
19
+ } from "./evolution-evidence-storage-layout.js";
12
20
  import { captureEvolutionRunWikiMaintenanceProducer } from "./evolution-run-wiki-maintenance-source.js";
13
21
  import { WIKI_MAINTENANCE_TRIGGER_KIND } from "./wiki-maintenance-trigger-ledger-adapter.js";
14
22
  import { captureEvolutionReleaseTrain } from "./evolution-release-train.js";
15
23
  import {
16
24
  snapshotAgentModelRequest,
17
25
  buildAgentModelRequest,
26
+ projectAgentOpaqueTransportBlock,
18
27
  } from "./agent-model-projection.js";
19
28
  import {
20
29
  snapshotSkillDecisionRequest,
@@ -28,8 +37,7 @@ export const AGENT_EVOLUTION_INGRESS_SCHEMA =
28
37
  export const AGENT_EVOLUTION_INGRESS_FAILED_CODE =
29
38
  "CC_AGENT_EVOLUTION_INGRESS_FAILED";
30
39
 
31
- const RESPONSE_CACHE_RECORD_SCHEMA =
32
- "chainlesschain.model-response-cache/v2";
40
+ const RESPONSE_CACHE_RECORD_SCHEMA = "chainlesschain.model-response-cache/v2";
33
41
  const LEGACY_RESPONSE_CACHE_RECORD_SCHEMA =
34
42
  "chainlesschain.model-response-cache/v1";
35
43
  const RESPONSE_CACHE_IDENTIFIER_BINDING_SCHEMA =
@@ -152,6 +160,7 @@ function ingressFailure(cause) {
152
160
  `Agent evolution ingress failed: ${cause?.message || String(cause)}`,
153
161
  { cause },
154
162
  );
163
+ error.message += storageFailureCauseSuffix(cause);
155
164
  error.code = AGENT_EVOLUTION_INGRESS_FAILED_CODE;
156
165
  return error;
157
166
  }
@@ -165,6 +174,7 @@ function guardIngress(operation) {
165
174
  export function createAgentEvolutionIngress({
166
175
  evidenceAdapter,
167
176
  runAdapter,
177
+ evidenceStorageLayout = "legacy",
168
178
  sourceEnvelopeAuthority,
169
179
  openCacheSourceRun = null,
170
180
  wikiMaintenanceProducer = null,
@@ -173,6 +183,7 @@ export function createAgentEvolutionIngress({
173
183
  now = () => new Date(),
174
184
  idGenerator = () => crypto.randomUUID(),
175
185
  } = {}) {
186
+ validateEvidenceStorageLayout(evidenceStorageLayout);
176
187
  if (!(evidenceAdapter instanceof EvolutionEvidenceArtifactAdapter)) {
177
188
  throw new TypeError("an EvolutionEvidenceArtifactAdapter is required");
178
189
  }
@@ -245,10 +256,24 @@ export function createAgentEvolutionIngress({
245
256
  return timestamp(iso, "ingress timestamp");
246
257
  };
247
258
 
259
+ const assertLoadedLayout = (loaded) => {
260
+ if (
261
+ evidenceStorageLayoutForRun(loaded.events, evidenceStorageLayout) !==
262
+ evidenceStorageLayout
263
+ )
264
+ throw new Error("Authenticated Run Evidence storage layout changed");
265
+ };
266
+
248
267
  const appendStarted = () => {
249
268
  const loaded = runAdapter.load();
269
+ assertLoadedLayout(loaded);
250
270
  if (loaded.events.length > 0) return loaded.projection;
251
271
  const occurredAt = currentTimestamp();
272
+ const data = {
273
+ occurredAt,
274
+ runtime: "agent",
275
+ ...(evidenceStorageLayout === "legacy" ? {} : { evidenceStorageLayout }),
276
+ };
252
277
  return runAdapter.appendEvent({
253
278
  schema: EVOLUTION_RUN_EVENT_SCHEMA,
254
279
  tenantId: descriptor.tenantId,
@@ -257,10 +282,10 @@ export function createAgentEvolutionIngress({
257
282
  sequence: 1,
258
283
  type: EVENT_TYPES.RUN_STARTED,
259
284
  subjectId: descriptor.runId,
260
- payloadDigest: digest({ occurredAt, runtime: "agent" }),
285
+ payloadDigest: digest(data),
261
286
  artifactRef: null,
262
287
  keyRef: null,
263
- data: { occurredAt, runtime: "agent" },
288
+ data,
264
289
  }).projection;
265
290
  };
266
291
 
@@ -294,8 +319,7 @@ export function createAgentEvolutionIngress({
294
319
  const payload = cacheRecord
295
320
  ? {
296
321
  schema: RESPONSE_CACHE_RECORD_SCHEMA,
297
- identifierBindingSchema:
298
- RESPONSE_CACHE_IDENTIFIER_BINDING_SCHEMA,
322
+ identifierBindingSchema: RESPONSE_CACHE_IDENTIFIER_BINDING_SCHEMA,
299
323
  requestKeyBinding: cacheIdentifierBinding(
300
324
  "request key",
301
325
  evidence.requestKey,
@@ -348,13 +372,14 @@ export function createAgentEvolutionIngress({
348
372
  "Agent evidence persistence returned an unbound result",
349
373
  );
350
374
  }
351
- const current = runAdapter.load();
352
- const appended = runAdapter.appendEvent({
375
+ const appendNext = captureEvolutionRunAppendNext(runAdapter);
376
+ // Custom ports keep their established load-before-append phase.
377
+ const current = appendNext === null ? runAdapter.load() : null;
378
+ const event = {
353
379
  schema: EVOLUTION_RUN_EVENT_SCHEMA,
354
380
  tenantId: descriptor.tenantId,
355
381
  runId: descriptor.runId,
356
382
  eventId,
357
- sequence: current.events.length + 1,
358
383
  type: EVENT_TYPES.RAW_EVENT_REFERENCED,
359
384
  subjectId: persisted.evidenceId,
360
385
  payloadDigest: persisted.manifest.digest,
@@ -372,7 +397,14 @@ export function createAgentEvolutionIngress({
372
397
  candidateSetDigest: skillDecisionRequest.candidateSetDigest,
373
398
  }),
374
399
  },
375
- });
400
+ };
401
+ const appended =
402
+ appendNext !== null
403
+ ? appendNext(event)
404
+ : runAdapter.appendEvent({
405
+ ...event,
406
+ sequence: current.events.length + 1,
407
+ });
376
408
  if (kind === "model-input") {
377
409
  lastModelResponse = null;
378
410
  modelAdmissionPending = true;
@@ -537,12 +569,11 @@ export function createAgentEvolutionIngress({
537
569
  throw new Error(
538
570
  "Cache response projection is not safe or request-bound",
539
571
  );
540
- const responseEvent = loaded.events.find(
541
- (item) =>
542
- legacyRecord
543
- ? item.eventId === record.sourceEventId
544
- : cacheIdentifierBinding("source event ID", item.eventId) ===
545
- record.sourceEventIdBinding,
572
+ const responseEvent = loaded.events.find((item) =>
573
+ legacyRecord
574
+ ? item.eventId === record.sourceEventId
575
+ : cacheIdentifierBinding("source event ID", item.eventId) ===
576
+ record.sourceEventIdBinding,
546
577
  );
547
578
  if (
548
579
  responseEvent?.data?.evidenceKind !== "response-completed" ||
@@ -589,8 +620,60 @@ export function createAgentEvolutionIngress({
589
620
  }
590
621
  return ingest("model-input", snapshot, {}, snapshot);
591
622
  },
592
- ingestUserPrompt: async (input, options) =>
593
- ingest("user-prompt", { input: cloneEvidence(input) }, options),
623
+ ingestUserPrompt: async (input, options) => {
624
+ const snapshot = cloneEvidence(input);
625
+ try {
626
+ if (
627
+ Array.isArray(snapshot?.messages) &&
628
+ typeof snapshot.source === "string"
629
+ ) {
630
+ const captured = snapshotAgentModelRequest({
631
+ messages: snapshot.messages,
632
+ tools: [],
633
+ });
634
+ // User-prompt is a small event, not a second image transport. Bind
635
+ // each image to its complete original block; model-input admission
636
+ // separately retains the original image in encrypted Raw evidence.
637
+ snapshot.messages = captured.messages.map(
638
+ (message, messageIndex) => ({
639
+ ...message,
640
+ ...(Array.isArray(message.content)
641
+ ? {
642
+ content: message.content.map((block, blockIndex) =>
643
+ block.type === "image_url"
644
+ ? projectAgentOpaqueTransportBlock(
645
+ block,
646
+ `messages.${messageIndex}.content.${blockIndex}`,
647
+ )
648
+ : block,
649
+ ),
650
+ }
651
+ : {}),
652
+ }),
653
+ );
654
+ } else if (Array.isArray(snapshot?.content)) {
655
+ const captured = snapshotAgentModelRequest({
656
+ messages: [{ role: "user", content: snapshot.content }],
657
+ tools: [],
658
+ });
659
+ // REPL callers pass the current user content directly, without a
660
+ // source label or a messages wrapper. Apply the same image binding.
661
+ snapshot.content = captured.messages[0].content.map(
662
+ (block, blockIndex) =>
663
+ block.type === "image_url"
664
+ ? projectAgentOpaqueTransportBlock(
665
+ block,
666
+ `messages.0.content.${blockIndex}`,
667
+ )
668
+ : block,
669
+ );
670
+ }
671
+ } catch (error) {
672
+ admissionFailure ??= ingressFailure(error);
673
+ throw admissionFailure;
674
+ }
675
+ return ingest("user-prompt", { input: snapshot }, options);
676
+ },
594
677
  ingestAgentEvent: async (event, options) => {
595
678
  if (admissionFailure !== null) throw admissionFailure;
596
679
  let type;
@@ -627,6 +710,7 @@ export function createAgentEvolutionIngress({
627
710
  serialize(async () => {
628
711
  if (admissionFailure !== null) throw admissionFailure;
629
712
  const loaded = runAdapter.load();
713
+ assertLoadedLayout(loaded);
630
714
  let projection;
631
715
  if (loaded.projection?.status === "completed") {
632
716
  projection = loaded.projection;
@@ -14,6 +14,11 @@ import {
14
14
  EvolutionEvidenceReader,
15
15
  } from "./evolution-evidence-projector.js";
16
16
  import { EvolutionArtifactPorts } from "./evolution-artifact-ports.js";
17
+ import {
18
+ createTypedEvidenceArtifactPorts,
19
+ evidenceStorageLayoutForRun,
20
+ validateEvidenceStorageLayout,
21
+ } from "./evolution-evidence-storage-layout.js";
17
22
  import {
18
23
  captureEvolutionLedgerFileBackend,
19
24
  createEvolutionLedgerFileBackend,
@@ -172,16 +177,14 @@ function layout(stateRootDir, tenantId, runId, initialize = true, fsImpl = fs) {
172
177
  const result = Object.freeze({
173
178
  rootDir,
174
179
  artifactDir: path.join(scope, "artifacts"),
180
+ evidenceArtifactDir: path.join(scope, "evidence-artifacts"),
175
181
  rawDir: path.join(scope, "raw"),
176
182
  ledgerRootDir: path.join(scope, "ledger-events"),
177
183
  ledgerAuthorityRootDir: path.join(scope, "ledger-authority"),
178
184
  witnessFilePath: path.join(scope, "witness", "checkpoint.json"),
179
185
  });
180
186
  if (initialize) {
181
- ensureDirectoryTreeDurable(
182
- fsImpl,
183
- path.dirname(result.witnessFilePath),
184
- );
187
+ ensureDirectoryTreeDurable(fsImpl, path.dirname(result.witnessFilePath));
185
188
  }
186
189
  return result;
187
190
  }
@@ -224,6 +227,7 @@ export function createAgentEvolutionRuntimeComposition({
224
227
  stateRootDir,
225
228
  authorities: authorityInput,
226
229
  evidenceTtlMs,
230
+ evidenceStorageLayout = "legacy",
227
231
  witnessId: witnessIdInput,
228
232
  clock: clockInput = Date.now,
229
233
  evidenceIdGenerator,
@@ -240,6 +244,7 @@ export function createAgentEvolutionRuntimeComposition({
240
244
  witnessMaximumBytes,
241
245
  ledgerV2: ledgerV2Input = null,
242
246
  } = {}) {
247
+ validateEvidenceStorageLayout(evidenceStorageLayout);
243
248
  const ledgerV2 =
244
249
  ledgerV2Input === null
245
250
  ? null
@@ -445,14 +450,6 @@ export function createAgentEvolutionRuntimeComposition({
445
450
  attestationVerifier: ports.attestationVerifier,
446
451
  now: () => new Date(clock()),
447
452
  });
448
- const evidenceAdapter = new EvolutionEvidenceArtifactAdapter({
449
- tenantId,
450
- audience,
451
- projector,
452
- bundleVerifier,
453
- artifactPorts,
454
- ...(evidenceTtlMs === undefined ? {} : { ttlMs: evidenceTtlMs }),
455
- });
456
453
  const ledgerArtifactResolver =
457
454
  artifactPorts.createEvolutionLedgerArtifactResolver({
458
455
  purpose: "evolution-ledger",
@@ -516,6 +513,46 @@ export function createAgentEvolutionRuntimeComposition({
516
513
  ledgerArtifactResolver,
517
514
  now: clock,
518
515
  });
516
+ const createEvidenceAdapter = (run, runStorage, mainPorts, emptyLayout) => {
517
+ const loaded = run.load();
518
+ const selectedLayout = evidenceStorageLayoutForRun(
519
+ loaded.events,
520
+ emptyLayout,
521
+ );
522
+ return {
523
+ selectedLayout,
524
+ adapter: new EvolutionEvidenceArtifactAdapter({
525
+ tenantId,
526
+ audience,
527
+ projector,
528
+ bundleVerifier,
529
+ ...(selectedLayout === "legacy"
530
+ ? { artifactPorts: mainPorts }
531
+ : {
532
+ typedArtifactPorts: createTypedEvidenceArtifactPorts({
533
+ rootDir: runStorage.evidenceArtifactDir,
534
+ tenantId,
535
+ audience,
536
+ artifactAuthority: {
537
+ envelopeSigner: ports.artifactEnvelopeSigner,
538
+ envelopeVerifier: ports.artifactEnvelopeVerifier,
539
+ currentAuthorityResolver:
540
+ ports.artifactCurrentAuthorityResolver,
541
+ },
542
+ now: clock,
543
+ existingRun: loaded.events.length > 0,
544
+ }),
545
+ }),
546
+ ...(evidenceTtlMs === undefined ? {} : { ttlMs: evidenceTtlMs }),
547
+ }),
548
+ };
549
+ };
550
+ const { adapter: evidenceAdapter, selectedLayout } = createEvidenceAdapter(
551
+ runAdapter,
552
+ storage,
553
+ artifactPorts,
554
+ evidenceStorageLayout,
555
+ );
519
556
  let wikiMaintenance = null;
520
557
  let wikiMaintainer = null;
521
558
  if (wikiConfiguration !== null) {
@@ -707,6 +744,7 @@ export function createAgentEvolutionRuntimeComposition({
707
744
  const evolutionIngress = createAgentEvolutionIngress({
708
745
  evidenceAdapter,
709
746
  runAdapter,
747
+ evidenceStorageLayout: selectedLayout,
710
748
  openCacheSourceRun: (input) => {
711
749
  const sourceRunId = identifier(input, "cache source runId");
712
750
  const sourceStorage = layout(
@@ -758,22 +796,22 @@ export function createAgentEvolutionRuntimeComposition({
758
796
  ...(lockTimeoutMs === undefined ? {} : { lockTimeoutMs }),
759
797
  ...(witnessMaximumBytes === undefined ? {} : { witnessMaximumBytes }),
760
798
  });
799
+ const sourceRunAdapter = new EvolutionRunLedgerAdapter({
800
+ descriptor: { ...runAdapter.descriptor, runId: sourceRunId },
801
+ artifactPorts: sourcePorts,
802
+ ledger: sourceBackend.ledger,
803
+ ledgerArtifactResolver: sourceResolver,
804
+ now: clock,
805
+ });
806
+ const sourceEvidence = createEvidenceAdapter(
807
+ sourceRunAdapter,
808
+ sourceStorage,
809
+ sourcePorts,
810
+ "legacy",
811
+ );
761
812
  return {
762
- runAdapter: new EvolutionRunLedgerAdapter({
763
- descriptor: { ...runAdapter.descriptor, runId: sourceRunId },
764
- artifactPorts: sourcePorts,
765
- ledger: sourceBackend.ledger,
766
- ledgerArtifactResolver: sourceResolver,
767
- now: clock,
768
- }),
769
- evidenceAdapter: new EvolutionEvidenceArtifactAdapter({
770
- tenantId,
771
- audience,
772
- projector,
773
- bundleVerifier,
774
- artifactPorts: sourcePorts,
775
- ...(evidenceTtlMs === undefined ? {} : { ttlMs: evidenceTtlMs }),
776
- }),
813
+ runAdapter: sourceRunAdapter,
814
+ evidenceAdapter: sourceEvidence.adapter,
777
815
  };
778
816
  },
779
817
  sourceEnvelopeAuthority: ports.sourceEnvelope,
@@ -1,9 +1,26 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { types } from "node:util";
3
3
  import { isAgentToolArgumentsPath } from "./evidence-json-text.js";
4
+ import {
5
+ MAX_INPUT_IMAGES,
6
+ MAX_INPUT_IMAGE_BYTES,
7
+ } from "../image-file-boundary.js";
4
8
 
5
- const MAX_NODES = 32_768;
6
- const MAX_BYTES = 1024 * 1024;
9
+ export const AGENT_MODEL_REQUEST_LIMITS = Object.freeze({
10
+ maxNodes: 32_768,
11
+ maxBytes: 1024 * 1024,
12
+ maxDepth: 24,
13
+ });
14
+ export const AGENT_MODEL_IMAGE_LIMITS = Object.freeze({
15
+ maxImageBytes: MAX_INPUT_IMAGE_BYTES,
16
+ maxMessageImageBytes: MAX_INPUT_IMAGE_BYTES,
17
+ maxMessageImages: MAX_INPUT_IMAGES,
18
+ maxRequestImageBytes: 40 * 1024 * 1024,
19
+ // Includes bounded base64 expansion, the text allocation and URL headers.
20
+ maxCanonicalRequestBytes: 56 * 1024 * 1024,
21
+ });
22
+ const MAX_NODES = AGENT_MODEL_REQUEST_LIMITS.maxNodes;
23
+ const MAX_BYTES = AGENT_MODEL_REQUEST_LIMITS.maxBytes;
7
24
  const MESSAGE_KEYS = new Set([
8
25
  "role",
9
26
  "content",
@@ -59,6 +76,32 @@ function blockDigest(value) {
59
76
  .digest("hex")}`;
60
77
  }
61
78
 
79
+ function imageDataUrlBudget(url) {
80
+ if (
81
+ typeof url !== "string" ||
82
+ url.length > Math.ceil(AGENT_MODEL_IMAGE_LIMITS.maxImageBytes / 3) * 4 + 128
83
+ )
84
+ throw new TypeError(
85
+ `Agent image exceeds its ${AGENT_MODEL_IMAGE_LIMITS.maxImageBytes / 1024 / 1024} MiB image byte budget`,
86
+ );
87
+ const match = /^data:([^;,]+);base64,([A-Za-z0-9+/]*={0,2})$/u.exec(url);
88
+ if (!match || !IMAGE_MEDIA_TYPES.has(match[1]) || match[2].length % 4 !== 0)
89
+ throw new TypeError(
90
+ "Agent image block requires a supported base64 data URL",
91
+ );
92
+ const decodedBytes =
93
+ (match[2].length / 4) * 3 -
94
+ (match[2].endsWith("==") ? 2 : match[2].endsWith("=") ? 1 : 0);
95
+ if (decodedBytes > AGENT_MODEL_IMAGE_LIMITS.maxImageBytes)
96
+ throw new TypeError(
97
+ `Agent image exceeds its ${AGENT_MODEL_IMAGE_LIMITS.maxImageBytes / 1024 / 1024} MiB image byte budget`,
98
+ );
99
+ const decoded = Buffer.from(match[2], "base64");
100
+ if (!decoded.length || decoded.toString("base64") !== match[2])
101
+ throw new TypeError("Agent image block contains non-canonical base64");
102
+ return { decodedBytes, encodedBytes: match[2].length };
103
+ }
104
+
62
105
  function imageBlock(value) {
63
106
  if (!exactKeys(value, new Set(["type", "image_url"]))) return null;
64
107
  const imageKeys = new Set(
@@ -74,18 +117,7 @@ function imageBlock(value) {
74
117
  ) {
75
118
  throw new TypeError("Agent image block has an unsupported protocol shape");
76
119
  }
77
- const match = /^data:([^;,]+);base64,([A-Za-z0-9+/]*={0,2})$/u.exec(
78
- value.image_url.url,
79
- );
80
- if (!match || !IMAGE_MEDIA_TYPES.has(match[1]) || match[2].length % 4 !== 0) {
81
- throw new TypeError(
82
- "Agent image block requires a supported base64 data URL",
83
- );
84
- }
85
- const decoded = Buffer.from(match[2], "base64");
86
- if (!decoded.length || decoded.toString("base64") !== match[2]) {
87
- throw new TypeError("Agent image block contains non-canonical base64");
88
- }
120
+ imageDataUrlBudget(value.image_url.url);
89
121
  return value;
90
122
  }
91
123
 
@@ -319,18 +351,54 @@ export function snapshotAgentModelRequest(
319
351
  ) {
320
352
  let nodes = 0;
321
353
  let bytes = 0;
354
+ let imageBytes = 0;
355
+ let encodedImageBytes = 0;
356
+ const messageImageBudgets = new Map();
322
357
  const seen = new Set();
323
358
  const visit = (entry, depth, path = "") => {
324
- if (++nodes > MAX_NODES || depth > 24) {
359
+ if (++nodes > MAX_NODES || depth > AGENT_MODEL_REQUEST_LIMITS.maxDepth) {
325
360
  throw new TypeError("Agent model request exceeds the input budget");
326
361
  }
327
362
  if (typeof entry === "string") {
328
- if (entry.length > 8192 && !textPath(path, allowStructuredArgumentText)) {
363
+ const imageUrl = /^messages\.\d+\.content\.\d+\.image_url\.url$/u.test(
364
+ path,
365
+ );
366
+ let imageBudget = null;
367
+ if (imageUrl) {
368
+ imageBudget = imageDataUrlBudget(entry);
369
+ const messageIndex = path.split(".")[1];
370
+ const messageBudget = messageImageBudgets.get(messageIndex) ?? {
371
+ bytes: 0,
372
+ count: 0,
373
+ };
374
+ messageBudget.bytes += imageBudget.decodedBytes;
375
+ messageBudget.count++;
376
+ messageImageBudgets.set(messageIndex, messageBudget);
377
+ if (
378
+ messageBudget.bytes > AGENT_MODEL_IMAGE_LIMITS.maxMessageImageBytes ||
379
+ messageBudget.count > AGENT_MODEL_IMAGE_LIMITS.maxMessageImages
380
+ )
381
+ throw new TypeError(
382
+ `Agent images exceed the per-message image budget (${AGENT_MODEL_IMAGE_LIMITS.maxMessageImages} images / ${AGENT_MODEL_IMAGE_LIMITS.maxMessageImageBytes / 1024 / 1024} MiB)`,
383
+ );
384
+ imageBytes += imageBudget.decodedBytes;
385
+ encodedImageBytes += imageBudget.encodedBytes;
386
+ if (imageBytes > AGENT_MODEL_IMAGE_LIMITS.maxRequestImageBytes)
387
+ throw new TypeError(
388
+ `Agent images exceed the ${AGENT_MODEL_IMAGE_LIMITS.maxRequestImageBytes / 1024 / 1024} MiB request image byte budget`,
389
+ );
390
+ }
391
+ if (
392
+ entry.length > 8192 &&
393
+ !imageUrl &&
394
+ !textPath(path, allowStructuredArgumentText)
395
+ ) {
329
396
  throw new TypeError(
330
397
  "Agent model protocol metadata exceeds the text budget",
331
398
  );
332
399
  }
333
- bytes += Buffer.byteLength(entry, "utf8");
400
+ bytes +=
401
+ Buffer.byteLength(entry, "utf8") - (imageBudget?.encodedBytes ?? 0);
334
402
  if (bytes > MAX_BYTES)
335
403
  throw new TypeError("Agent model request is too large");
336
404
  return entry;
@@ -405,7 +473,11 @@ export function snapshotAgentModelRequest(
405
473
  );
406
474
  // Include escaping, punctuation and numeric values in the transport/storage
407
475
  // budget, not just string values. Whole fields are never split or truncated.
408
- if (Buffer.byteLength(JSON.stringify(request), "utf8") > MAX_BYTES) {
476
+ const canonicalBytes = Buffer.byteLength(JSON.stringify(request), "utf8");
477
+ if (
478
+ canonicalBytes - encodedImageBytes > MAX_BYTES ||
479
+ canonicalBytes > AGENT_MODEL_IMAGE_LIMITS.maxCanonicalRequestBytes
480
+ ) {
409
481
  throw new TypeError("Agent model request is too large");
410
482
  }
411
483
  return request;