chainlesschain 0.166.114 → 0.166.117

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 (183) hide show
  1. package/README.md +23 -3
  2. package/package.json +3 -3
  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/assets/{AIOps-CVac3rIN.js → AIOps-C9tSCImB.js} +1 -1
  6. package/src/assets/web-panel/assets/{ActionButton-ChM9GxMl.js → ActionButton-CXKExmT_.js} +1 -1
  7. package/src/assets/web-panel/assets/{Analytics-CV5399Js.js → Analytics-DE8WBWHo.js} +3 -3
  8. package/src/assets/web-panel/assets/{AppLayout-CuonVXhg.js → AppLayout-BdpwNM08.js} +5 -5
  9. package/src/assets/web-panel/assets/{Artifacts-D9qKfgb6.js → Artifacts-94TQpe38.js} +1 -1
  10. package/src/assets/web-panel/assets/{Audit-DUvLysQc.js → Audit-DdDEv5Ej.js} +1 -1
  11. package/src/assets/web-panel/assets/{BackgroundAgents-DfKohQeT.js → BackgroundAgents-TU9nlV7j.js} +1 -1
  12. package/src/assets/web-panel/assets/{Backup-CohoEI8R.js → Backup-C0GPoUUq.js} +1 -1
  13. package/src/assets/web-panel/assets/{BaseInput-BwdoA3xv.js → BaseInput-iyrVn2I6.js} +1 -1
  14. package/src/assets/web-panel/assets/{Chat-DRkuz1d2.js → Chat-Dqo8spwp.js} +5 -5
  15. package/src/assets/web-panel/assets/{ChatBubbleRenderer-v3pzeHNC.js → ChatBubbleRenderer-CDqHSzc4.js} +1 -1
  16. package/src/assets/web-panel/assets/{Checkbox-B-GNGpKv.js → Checkbox-BF_XJvQi.js} +1 -1
  17. package/src/assets/web-panel/assets/{Codegen-Bs2lAsoZ.js → Codegen-5tUWoOa9.js} +1 -1
  18. package/src/assets/web-panel/assets/{Col-Bk1mJKDZ.js → Col-BQxSeRvG.js} +1 -1
  19. package/src/assets/web-panel/assets/{Community-B_FDSCOo.js → Community-B2Ra7w-J.js} +1 -1
  20. package/src/assets/web-panel/assets/{Compact-No1qSLLH.js → Compact-GjxJwlr0.js} +1 -1
  21. package/src/assets/web-panel/assets/{Compliance-CcrG43-d.js → Compliance-BTUP6RTA.js} +1 -1
  22. package/src/assets/web-panel/assets/{Cowork-DLkj2ywK.js → Cowork-DiwfL16s.js} +3 -3
  23. package/src/assets/web-panel/assets/{Cron-sQHELVEz.js → Cron-1ceOo5ux.js} +2 -2
  24. package/src/assets/web-panel/assets/{Crosschain-CRTZ3GZg.js → Crosschain-aHYxLu0u.js} +1 -1
  25. package/src/assets/web-panel/assets/{DID-Ds2bjvxE.js → DID-eeTjzOLV.js} +2 -2
  26. package/src/assets/web-panel/assets/{Dashboard-DOONG2NX.js → Dashboard-CT3fpkvX.js} +2 -2
  27. package/src/assets/web-panel/assets/{Dropdown-Br3PNA2L.js → Dropdown-B3UpOy-N.js} +1 -1
  28. package/src/assets/web-panel/assets/{EmailListRenderer-DT6UUqjZ.js → EmailListRenderer-Ba2Rvoru.js} +1 -1
  29. package/src/assets/web-panel/assets/{EvolutionSettings-BSLuEjlT.js → EvolutionSettings-CGtn93on.js} +1 -1
  30. package/src/assets/web-panel/assets/{FamilyGuardDashboard-2aEM9avE.js → FamilyGuardDashboard-C0IUdHQt.js} +1 -1
  31. package/src/assets/web-panel/assets/{Federation-D3B0tlQU.js → Federation-1QIDwemn.js} +1 -1
  32. package/src/assets/web-panel/assets/{FormItemContext-DTVkVVQP.js → FormItemContext-NGbSsdje.js} +1 -1
  33. package/src/assets/web-panel/assets/{GenericCardRenderer-BgFEgP4y.js → GenericCardRenderer-DzVZc2Ba.js} +1 -1
  34. package/src/assets/web-panel/assets/{Git-3t71m6Xd.js → Git-B_1TDbSr.js} +2 -2
  35. package/src/assets/web-panel/assets/{Governance-DS7WvlaX.js → Governance-BDl_ySyI.js} +1 -1
  36. package/src/assets/web-panel/assets/{Inference-CeT-xWrI.js → Inference-CAp-wcCK.js} +1 -1
  37. package/src/assets/web-panel/assets/{KnowledgeGraph-BQzMncp5.js → KnowledgeGraph-DRjRcxul.js} +1 -1
  38. package/src/assets/web-panel/assets/{Logs-CC5DOKhV.js → Logs-qSuwMwk7.js} +2 -2
  39. package/src/assets/web-panel/assets/MarkdownRenderer-BgnYTegK.js +1 -0
  40. package/src/assets/web-panel/assets/{Marketplace-CpYDyy3o.js → Marketplace-DfiXL6UO.js} +1 -1
  41. package/src/assets/web-panel/assets/{McpTools-DRdAZPMr.js → McpTools-D9rIvFjN.js} +3 -3
  42. package/src/assets/web-panel/assets/{Memory-CBLRr-l8.js → Memory-D-p7yDzj.js} +2 -2
  43. package/src/assets/web-panel/assets/{MobileBridge-Bnj9veNN.js → MobileBridge-D0XT5B6m.js} +1 -1
  44. package/src/assets/web-panel/assets/{MobileProjects-lYFPD24p.js → MobileProjects-CL9cHVIk.js} +1 -1
  45. package/src/assets/web-panel/assets/{Mtc-BMU_C9vD.js → Mtc-CME4kDmC.js} +2 -2
  46. package/src/assets/web-panel/assets/{MtcAudit-DQV-zumU.js → MtcAudit-BjGOXFnn.js} +4 -4
  47. package/src/assets/web-panel/assets/{Multisig-LpqpqV1d.js → Multisig-CSzc53e0.js} +3 -3
  48. package/src/assets/web-panel/assets/{NLProgramming-C4OMklSO.js → NLProgramming-BYjZnaH8.js} +1 -1
  49. package/src/assets/web-panel/assets/{Notes-Cg0QCinP.js → Notes-BUPOYE0C.js} +3 -3
  50. package/src/assets/web-panel/assets/{NotificationSettings-amoZoMna.js → NotificationSettings-BK8YADru.js} +1 -1
  51. package/src/assets/web-panel/assets/{OrderTableRenderer-CxNvhf5n.js → OrderTableRenderer-B5F8bnWt.js} +1 -1
  52. package/src/assets/web-panel/assets/{Organization-BetJmyX5.js → Organization-B0WNlhMd.js} +4 -4
  53. package/src/assets/web-panel/assets/{Overflow-DbeoPtVD.js → Overflow-CED6ZO87.js} +1 -1
  54. package/src/assets/web-panel/assets/{P2P-B5sitQWT.js → P2P-CBdc8fkP.js} +2 -2
  55. package/src/assets/web-panel/assets/{PdhVaultBrowser-AP9SG2ic.js → PdhVaultBrowser-DuauYi03.js} +3 -3
  56. package/src/assets/web-panel/assets/{Permissions-Bc7fgNKx.js → Permissions-kfgY0ukN.js} +4 -4
  57. package/src/assets/web-panel/assets/{PersonalDataHub-BwdGMcWZ.js → PersonalDataHub-CDY3I1Do.js} +3 -3
  58. package/src/assets/web-panel/assets/{Pipeline-DVuJA9BA.js → Pipeline-B9x0wKSK.js} +1 -1
  59. package/src/assets/web-panel/assets/{Privacy-BGzwOYRG.js → Privacy-Cqhcr_Qv.js} +1 -1
  60. package/src/assets/web-panel/assets/{ProjectInit-BpHcC5br.js → ProjectInit-CFhoyo57.js} +2 -2
  61. package/src/assets/web-panel/assets/{ProjectSettings-BI5G5gsc.js → ProjectSettings-DCBjV2Hm.js} +2 -2
  62. package/src/assets/web-panel/assets/Projects-C51w0LnM.js +1 -0
  63. package/src/assets/web-panel/assets/{Providers-CRHCcLFS.js → Providers-BuCIWZY1.js} +1 -1
  64. package/src/assets/web-panel/assets/{QrScannerModal-qSeg5xag.js → QrScannerModal-CEXNL5CB.js} +1 -1
  65. package/src/assets/web-panel/assets/{QuickAsk-CA8oSceR.js → QuickAsk-DgK8aLAU.js} +1 -1
  66. package/src/assets/web-panel/assets/{Recommend-DMvPodNo.js → Recommend-BxEYQRAs.js} +1 -1
  67. package/src/assets/web-panel/assets/{RemoteSession-BWsapEyN.js → RemoteSession-PRsxNsYU.js} +2 -2
  68. package/src/assets/web-panel/assets/{Reputation-BZJETVmC.js → Reputation-S-tQH70r.js} +1 -1
  69. package/src/assets/web-panel/assets/{Row-CUE1OSMp.js → Row-U1Ws3CJl.js} +1 -1
  70. package/src/assets/web-panel/assets/{RssFeed-DvMazcUD.js → RssFeed-BftCyeii.js} +3 -3
  71. package/src/assets/web-panel/assets/{Search-e1c-NXWv.js → Search-o4gK0cPy.js} +1 -1
  72. package/src/assets/web-panel/assets/{Security-Dc9GZsx2.js → Security-U2ZRpsbA.js} +3 -3
  73. package/src/assets/web-panel/assets/{Services-AFz6ke-4.js → Services-D0tRjWl_.js} +2 -2
  74. package/src/assets/web-panel/assets/{Skeleton-gow6MYcY.js → Skeleton-DzZ8TFsB.js} +1 -1
  75. package/src/assets/web-panel/assets/{Skills-h6AxYjUP.js → Skills-B1cC7rju.js} +1 -1
  76. package/src/assets/web-panel/assets/{Sla-Cr4CkJ0O.js → Sla-CtIHOR0J.js} +1 -1
  77. package/src/assets/web-panel/assets/{SpeechSettings-Bd5yuBtH.js → SpeechSettings-CD8ZlQpW.js} +1 -1
  78. package/src/assets/web-panel/assets/{SyncSettings-1t4QZMLW.js → SyncSettings-BilFQWQk.js} +2 -2
  79. package/src/assets/web-panel/assets/{Tasks-u-DrjLRM.js → Tasks-Bmg2qLXl.js} +1 -1
  80. package/src/assets/web-panel/assets/{Templates-C0yLUC9b.js → Templates-D6yofyC1.js} +1 -1
  81. package/src/assets/web-panel/assets/{Tenant-ds1YT5iS.js → Tenant-BzttD-Gp.js} +1 -1
  82. package/src/assets/web-panel/assets/{Terminal-BoIskW2m.js → Terminal-DyRXeYuH.js} +2 -2
  83. package/src/assets/web-panel/assets/{TimelineRenderer-BkdVK24X.js → TimelineRenderer-Bdmkx-Tr.js} +1 -1
  84. package/src/assets/web-panel/assets/{Tokens-djyDgmfk.js → Tokens-10RcVAVJ.js} +1 -1
  85. package/src/assets/web-panel/assets/{Trigger-CYefDS3H.js → Trigger-CKV-9DdV.js} +1 -1
  86. package/src/assets/web-panel/assets/{Trust-CE_dbep_.js → Trust-BEc-sW1q.js} +1 -1
  87. package/src/assets/web-panel/assets/{UkeySign-DwVs_fey.js → UkeySign-BSql8piX.js} +1 -1
  88. package/src/assets/web-panel/assets/{VideoEditing-BTUqMHAV.js → VideoEditing-C4OH2f4s.js} +1 -1
  89. package/src/assets/web-panel/assets/{Wallet-Bu_E7Rrc.js → Wallet-BSSvWKmv.js} +4 -4
  90. package/src/assets/web-panel/assets/{WebAuthn-DTbre5AB.js → WebAuthn-LxIzXo9d.js} +5 -5
  91. package/src/assets/web-panel/assets/{WorkflowEditor-BsBzd3gt.js → WorkflowEditor-DWwdfcte.js} +1 -1
  92. package/src/assets/web-panel/assets/{chat-tdifQQvu.js → chat-DWxYYLD5.js} +1 -1
  93. package/src/assets/web-panel/assets/{colors-D3SNW2Vx.js → colors-BxEcQqtg.js} +1 -1
  94. package/src/assets/web-panel/assets/{compact-item-UBlCjrAW.js → compact-item-DNbezFOJ.js} +1 -1
  95. package/src/assets/web-panel/assets/{createContext-DKsnEnFt.js → createContext-DaJXc5nx.js} +1 -1
  96. package/src/assets/web-panel/assets/devWarning-CRyXoGo9.js +1 -0
  97. package/src/assets/web-panel/assets/{hasIn-BkeySXWe.js → hasIn-BMrw3sg3.js} +1 -1
  98. package/src/assets/web-panel/assets/{index-CXkn77ZN.js → index-2c0bL3SE.js} +1 -1
  99. package/src/assets/web-panel/assets/{index-DtxUSZSS.js → index-6W0V5G2t.js} +1 -1
  100. package/src/assets/web-panel/assets/{index-DFMrIEIt.js → index-7zzLqfvI.js} +1 -1
  101. package/src/assets/web-panel/assets/{index-D9m1HQzl.js → index-B9b6UaZl.js} +1 -1
  102. package/src/assets/web-panel/assets/{index-bOIcWW8F.js → index-BAV07GDK.js} +1 -1
  103. package/src/assets/web-panel/assets/{index-BV2zQteq.js → index-BCCd8Rj6.js} +1 -1
  104. package/src/assets/web-panel/assets/{index-DlO6HdD9.js → index-BNZDGV2q.js} +1 -1
  105. package/src/assets/web-panel/assets/{index-DfrW-iVs.js → index-BR4nWOmR.js} +1 -1
  106. package/src/assets/web-panel/assets/{index-PWScrdlX.js → index-B_b9_6wQ.js} +1 -1
  107. package/src/assets/web-panel/assets/{index-SpQ26gD6.js → index-BaByEdBj.js} +1 -1
  108. package/src/assets/web-panel/assets/{index-D5Umd_Z-.js → index-BcuytRTa.js} +1 -1
  109. package/src/assets/web-panel/assets/{index-Dg8-Duze.js → index-Bs2QyMPQ.js} +1 -1
  110. package/src/assets/web-panel/assets/{index-DlEIp1gJ.js → index-Bum_aSyd.js} +1 -1
  111. package/src/assets/web-panel/assets/index-C-W0Ntk_.js +1 -0
  112. package/src/assets/web-panel/assets/{index-D6es7MSG.js → index-C25ig6EV.js} +1 -1
  113. package/src/assets/web-panel/assets/index-CCk_qhBx.js +1 -0
  114. package/src/assets/web-panel/assets/{index-Bw0k3VgD.js → index-CL-36X3A.js} +1 -1
  115. package/src/assets/web-panel/assets/{index-DYFjOyTH.js → index-Ca2hwPMo.js} +1 -1
  116. package/src/assets/web-panel/assets/{index-BVvz3ntc.js → index-CaxzeSIM.js} +1 -1
  117. package/src/assets/web-panel/assets/{index-D9um0YVl.js → index-CiEdfbB9.js} +1 -1
  118. package/src/assets/web-panel/assets/{index-DugZRCiI.js → index-Cm9DYzhC.js} +1 -1
  119. package/src/assets/web-panel/assets/{index-pgGKNvmm.js → index-CpwgF7vh.js} +1 -1
  120. package/src/assets/web-panel/assets/{index-P-ailFQY.js → index-DEvdSKT4.js} +1 -1
  121. package/src/assets/web-panel/assets/{index-C9ImNw5O.js → index-DL0k35f0.js} +1 -1
  122. package/src/assets/web-panel/assets/{index-DSCiZJXb.js → index-DarVV5yG.js} +1 -1
  123. package/src/assets/web-panel/assets/{index-BIeFLaMV.js → index-DpSp97J8.js} +1 -1
  124. package/src/assets/web-panel/assets/{index-C-KTHSUE.js → index-Dr18agDl.js} +1 -1
  125. package/src/assets/web-panel/assets/{index-DiDgwRty.js → index-Dwg38xTG.js} +1 -1
  126. package/src/assets/web-panel/assets/{index-D93iSDUw.js → index-DzZHBzCb.js} +1 -1
  127. package/src/assets/web-panel/assets/{index-6Nvzgytx.js → index-IX0g0s2t.js} +1 -1
  128. package/src/assets/web-panel/assets/{index-CG_b1xyX.js → index-LRb0QX6S.js} +1 -1
  129. package/src/assets/web-panel/assets/{index-Cuz2QCFT.js → index-NEW5EN2w.js} +1 -1
  130. package/src/assets/web-panel/assets/{index-CUjyL0ZS.js → index-T4T84G6X.js} +1 -1
  131. package/src/assets/web-panel/assets/{index-DdyTv6yc.js → index-VD-dTYQE.js} +1 -1
  132. package/src/assets/web-panel/assets/{index-BEiHKah0.js → index-cCqCEa9X.js} +3 -3
  133. package/src/assets/web-panel/assets/{index-DD6dD3LV.js → index-cKBpcInt.js} +1 -1
  134. package/src/assets/web-panel/assets/{index-TLBpgN30.js → index-hPy_f08G.js} +1 -1
  135. package/src/assets/web-panel/assets/{index-DSe_7MSy.js → index-pzYLf5qu.js} +1 -1
  136. package/src/assets/web-panel/assets/{index-CZ6JUooI.js → index-rFaCnjXi.js} +1 -1
  137. package/src/assets/web-panel/assets/{initDefaultProps-CVCXG2Hv.js → initDefaultProps-BWVLgWhF.js} +1 -1
  138. package/src/assets/web-panel/assets/{motion-Dv00jw87.js → motion-KJZ1xfDE.js} +1 -1
  139. package/src/assets/web-panel/assets/{move-BFz51iHf.js → move-DGqU6H7M.js} +1 -1
  140. package/src/assets/web-panel/assets/{mtc-parser-BK2woIDE.js → mtc-parser-Dg0xkI5J.js} +1 -1
  141. package/src/assets/web-panel/assets/{omit-D2X_Gwoo.js → omit-B6RnMJAQ.js} +1 -1
  142. package/src/assets/web-panel/assets/{pickAttrs-CLmFyJ1q.js → pickAttrs-Ctw2i3jb.js} +1 -1
  143. package/src/assets/web-panel/assets/{placementArrow-CCzPddQm.js → placementArrow-D3F3x8Jm.js} +1 -1
  144. package/src/assets/web-panel/assets/{responsiveObserve-hcm_Zlxd.js → responsiveObserve-W6eHE0nM.js} +1 -1
  145. package/src/assets/web-panel/assets/{slide-BxfZEFVp.js → slide-BlFf8sY5.js} +1 -1
  146. package/src/assets/web-panel/assets/{statusUtils-kzB9pT-t.js → statusUtils-Cd6LMwmy.js} +1 -1
  147. package/src/assets/web-panel/assets/{styleChecker-CDFd7YCI.js → styleChecker-Bg5-U4Y1.js} +1 -1
  148. package/src/assets/web-panel/assets/{useFlexGapSupport-Czl7NNhS.js → useFlexGapSupport-DTkLS3tn.js} +1 -1
  149. package/src/assets/web-panel/assets/{useFs-y0SAzirG.js → useFs-CwYGzoBt.js} +1 -1
  150. package/src/assets/web-panel/assets/{usePersonalDataHub-BvdPznrA.js → usePersonalDataHub-PCgFQXZP.js} +1 -1
  151. package/src/assets/web-panel/assets/{vnode-D8mNbyZ7.js → vnode-CJM7MkrB.js} +1 -1
  152. package/src/assets/web-panel/assets/{zoom-_hun6w9W.js → zoom-CP0mgaFi.js} +1 -1
  153. package/src/assets/web-panel/index.html +1 -1
  154. package/src/commands/compact.js +7 -2
  155. package/src/data/changelog.json +28 -2
  156. package/src/harness/jsonl-session-store.js +78 -73
  157. package/src/harness/prompt-compressor.js +57 -3
  158. package/src/lib/context-memory-kernel/context-image-transport.js +248 -0
  159. package/src/lib/context-memory-kernel/jsonl-session-context-port.js +4 -1
  160. package/src/lib/context-memory-kernel/live-compaction.js +40 -10
  161. package/src/lib/context-memory-kernel/message-adapter.js +80 -10
  162. package/src/lib/context-memory-kernel/message-bundle-store.js +1140 -0
  163. package/src/lib/context-memory-kernel/provider-context.js +23 -8
  164. package/src/lib/evolution/agent-evolution-ingress.js +62 -12
  165. package/src/lib/evolution/agent-model-projection.js +90 -18
  166. package/src/lib/evolution/evidence-json-text.js +279 -42
  167. package/src/lib/evolution/evolution-evidence-projector.js +169 -26
  168. package/src/lib/evolution/governed-model-turn.js +2 -2
  169. package/src/lib/evolution/local-ui-evolution-deployment.js +2 -2
  170. package/src/lib/evolution/local-ui-evolution-runtime.js +4 -4
  171. package/src/lib/evolution/opaque-hex-id.js +8 -0
  172. package/src/lib/image-token-estimate.js +59 -0
  173. package/src/lib/read-file-loop-guard.js +9 -6
  174. package/src/lib/session-history-origins.js +25 -5
  175. package/src/lib/session-transcript-history.js +5 -1
  176. package/src/lib/tool-result-preview.js +276 -0
  177. package/src/runtime/agent-core.js +85 -78
  178. package/src/runtime/headless-stream.js +32 -17
  179. package/src/assets/web-panel/assets/MarkdownRenderer-5jYM4kYG.js +0 -1
  180. package/src/assets/web-panel/assets/Projects-Ce92-l1V.js +0 -1
  181. package/src/assets/web-panel/assets/devWarning-BBnVfJHh.js +0 -1
  182. package/src/assets/web-panel/assets/index-B2w_3mtS.js +0 -1
  183. package/src/assets/web-panel/assets/index-BoHurydC.js +0 -1
@@ -0,0 +1,276 @@
1
+ import {
2
+ createEvidenceJsonTextBoundary,
3
+ AGENT_CODE_TEXT_RESULT_TOOLS,
4
+ } from "./evolution/evidence-json-text.js";
5
+ import { createHash } from "node:crypto";
6
+
7
+ // Keep host identity outside the JSON evidence object. External JSON results
8
+ // cannot nominate a digest or borrow an earlier command's output identity.
9
+ const HOST_OUTPUT_IDENTITIES = new WeakMap();
10
+ export function registerHostToolOutput(result, output) {
11
+ HOST_OUTPUT_IDENTITIES.set(
12
+ result,
13
+ Object.freeze({
14
+ chars: output.length,
15
+ digest: createHash("sha256").update(output).digest("hex"),
16
+ visibleOutput: result.output,
17
+ }),
18
+ );
19
+ return result;
20
+ }
21
+ export function copyHostToolOutputIdentity(result, source) {
22
+ const identity = HOST_OUTPUT_IDENTITIES.get(source);
23
+ if (identity) HOST_OUTPUT_IDENTITIES.set(result, identity);
24
+ return result;
25
+ }
26
+ export function hostToolOutputIdentity(result) {
27
+ const identity = HOST_OUTPUT_IDENTITIES.get(result);
28
+ return identity?.visibleOutput === result?.output ? identity : undefined;
29
+ }
30
+
31
+ const PREVIEW_HINT =
32
+ "Tool output truncated. Narrow the request: filter/count locally, select fields, search_files, or read_file with offset/limit. Omitted text is not full-output evidence.";
33
+
34
+ /** Check only host-created excerpts; original uncut tool text still reaches ingress. */
35
+ function completeExcerpt(text, tool) {
36
+ const scan = createEvidenceJsonTextBoundary((message) => new Error(message));
37
+ const visit = (value, layer) => {
38
+ if (typeof value === "string") return project(value, layer);
39
+ if (Array.isArray(value)) return value.map((child) => visit(child, layer));
40
+ if (value && typeof value === "object") {
41
+ return Object.fromEntries(
42
+ Object.entries(value).map(([key, child]) => [key, visit(child, layer)]),
43
+ );
44
+ }
45
+ return value;
46
+ };
47
+ const project = (value, layer = 0) =>
48
+ scan(value, {
49
+ layer,
50
+ codeText: AGENT_CODE_TEXT_RESULT_TOOLS.includes(tool),
51
+ visit,
52
+ plain: (plain) => plain,
53
+ equal: (left, right) => JSON.stringify(left) === JSON.stringify(right),
54
+ });
55
+ try {
56
+ project(text);
57
+ return true;
58
+ } catch {
59
+ return false;
60
+ }
61
+ }
62
+
63
+ function omitted(chars) {
64
+ return `Text omitted (${chars} chars); narrow the request to inspect a complete value.`;
65
+ }
66
+
67
+ const STATUS_KEYS = new Set([
68
+ "success",
69
+ "error",
70
+ "exitCode",
71
+ "status",
72
+ "code",
73
+ "signal",
74
+ "path",
75
+ "range",
76
+ "nextRead",
77
+ "duration",
78
+ "language",
79
+ ]);
80
+
81
+ // Native JSON.parse is used only after checking its lossy cases: duplicate
82
+ // decoded keys and non-finite/unsafe numbers must never turn into a safe-looking
83
+ // preview. This pass does not repair syntax or decode text leaves.
84
+ function parsePreviewJson(text) {
85
+ const value = JSON.parse(text);
86
+ const stack = [];
87
+ for (let index = 0; index < text.length; index++) {
88
+ const char = text[index];
89
+ if (char === '"') {
90
+ const start = index;
91
+ while (++index < text.length) {
92
+ if (text[index] === "\\") index++;
93
+ else if (text[index] === '"') break;
94
+ }
95
+ const object = stack.at(-1);
96
+ if (object?.key) {
97
+ const key = JSON.parse(text.slice(start, index + 1));
98
+ if (object.keys.has(key)) throw new TypeError("Ambiguous JSON keys");
99
+ object.keys.add(key);
100
+ object.key = false;
101
+ }
102
+ } else if (char === "{") stack.push({ keys: new Set(), key: true });
103
+ else if (char === "[") stack.push(null);
104
+ else if (char === "}" || char === "]") stack.pop();
105
+ else if (char === "," && stack.at(-1)) stack.at(-1).key = true;
106
+ else if (/[\d-]/u.test(char)) {
107
+ const token = /^-?(?:0|[1-9]\d*)(?:\.\d+)?(?:[eE][+-]?\d+)?/u.exec(
108
+ text.slice(index),
109
+ )[0];
110
+ const number = Number(token);
111
+ if (
112
+ !Number.isFinite(number) ||
113
+ (Number.isInteger(number) && !Number.isSafeInteger(number))
114
+ )
115
+ throw new TypeError("Unsafe JSON number");
116
+ index += token.length - 1;
117
+ }
118
+ }
119
+ return value;
120
+ }
121
+
122
+ /** Produce complete JSON values, never prefixes of a JSON leaf. */
123
+ export function boundedToolResultText(text, max) {
124
+ if (text.length <= max) return text;
125
+ let original;
126
+ try {
127
+ original = parsePreviewJson(text);
128
+ } catch {
129
+ // Plain output can retain a prefix only when it cannot contain a sliced
130
+ // structured span. In particular, do not hide broken JSON in a preview.
131
+ if (!/[{}\[\]"']/u.test(text)) {
132
+ const marker = `\nTool output truncated (${text.length} chars). Narrow the request.`;
133
+ if (marker.length < max) {
134
+ let end = max - marker.length;
135
+ if (/[\uD800-\uDBFF]/u.test(text[end - 1] ?? "")) end--;
136
+ return text.slice(0, end) + marker;
137
+ }
138
+ }
139
+ original = omitted(text.length);
140
+ }
141
+
142
+ for (const limit of [8192, 2048, 512, 128, 0]) {
143
+ let nodes = 0;
144
+ const preview = (value, depth = 0) => {
145
+ if (++nodes > 128 || depth > 6)
146
+ return "Value omitted; select a smaller subtree.";
147
+ if (typeof value === "string")
148
+ return JSON.stringify(value).length > limit
149
+ ? omitted(value.length)
150
+ : value;
151
+ if (!value || typeof value !== "object") return value;
152
+ if (Array.isArray(value)) {
153
+ const kept = [];
154
+ for (const child of value) {
155
+ if (kept.length >= 32 || nodes >= 128) break;
156
+ kept.push(preview(child, depth + 1));
157
+ }
158
+ if (kept.length < value.length)
159
+ kept.push(
160
+ `Items omitted (${value.length - kept.length}); narrow the request.`,
161
+ );
162
+ return kept;
163
+ }
164
+ const kept = Object.create(null);
165
+ const entries = Object.entries(value).sort(
166
+ ([a], [b]) => Number(STATUS_KEYS.has(b)) - Number(STATUS_KEYS.has(a)),
167
+ );
168
+ let count = 0;
169
+ for (const [key, child] of entries) {
170
+ if (count >= 32 || nodes >= 128) break;
171
+ if (key.length > 256) continue;
172
+ Object.defineProperty(kept, key, {
173
+ enumerable: true,
174
+ value: preview(child, depth + 1),
175
+ });
176
+ count++;
177
+ }
178
+ if (count < entries.length) {
179
+ let marker = "_omittedFields";
180
+ while (Object.hasOwn(kept, marker)) marker += "_";
181
+ Object.defineProperty(kept, marker, {
182
+ enumerable: true,
183
+ value: entries.length - count,
184
+ });
185
+ }
186
+ return kept;
187
+ };
188
+ const value = preview(original);
189
+ const result =
190
+ value && !Array.isArray(value) && typeof value === "object"
191
+ ? value
192
+ : { preview: value };
193
+ let marker = "_toolOutputPreview";
194
+ while (Object.hasOwn(result, marker)) marker += "_";
195
+ Object.defineProperty(result, marker, {
196
+ enumerable: true,
197
+ value: {
198
+ truncated: true,
199
+ originalChars: text.length,
200
+ hint: PREVIEW_HINT,
201
+ },
202
+ });
203
+ const serialized = JSON.stringify(result);
204
+ if (serialized.length <= max) return serialized;
205
+ }
206
+ const summary = JSON.stringify({
207
+ truncated: true,
208
+ originalChars: text.length,
209
+ hint: PREVIEW_HINT,
210
+ });
211
+ if (summary.length <= max) return summary;
212
+ if (max >= 18) return '{"truncated":true}';
213
+ return max >= 4 ? "null" : max >= 2 ? "{}" : "0";
214
+ }
215
+
216
+ /** Keep cursors/status, but remove JSON fragments created by host paging. */
217
+ export function safeHostToolResultForModel(tool, result) {
218
+ if (!result || typeof result !== "object" || Array.isArray(result))
219
+ return result;
220
+ const fields = [];
221
+ if (
222
+ tool === "read_file" &&
223
+ (result.truncated || result.range || result.nextRead)
224
+ )
225
+ fields.push("content");
226
+ if (tool === "run_code" && result.truncated) fields.push("output");
227
+ if (tool === "check_shell") fields.push("stdout", "stderr");
228
+ if (tool === "run_shell" || tool === "git") {
229
+ for (const field of ["stdout", "stderr"])
230
+ if (result[`${field}_truncated`])
231
+ fields.push(field, `${field}_diagnostics`);
232
+ }
233
+ let safe = result;
234
+ for (const field of fields) {
235
+ const text = result[field];
236
+ if (typeof text !== "string" || completeExcerpt(text, tool)) continue;
237
+ if (safe === result) safe = { ...result };
238
+ safe[field] = omitted(text.length);
239
+ safe[`${field}Omitted`] = true;
240
+ safe[`${field}OmittedChars`] = text.length;
241
+ }
242
+ return safe;
243
+ }
244
+
245
+ /** Prefer a whole JSON tree over slicing stdout through an embedded value. */
246
+ export function boundedCommandOutput(output, max, tool = "run_code") {
247
+ const encoded = JSON.stringify(output);
248
+ if (encoded.length <= max) return output;
249
+ // If stdout itself is JSON, preview that tree rather than its quoted form.
250
+ let json = false;
251
+ try {
252
+ parsePreviewJson(output);
253
+ json = true;
254
+ } catch {
255
+ /* Plain command text. */
256
+ }
257
+ if (json) {
258
+ const preview = boundedToolResultText(
259
+ output,
260
+ Math.max(1, Math.floor(max / 2)),
261
+ );
262
+ if (JSON.stringify(preview).length <= max && completeExcerpt(preview, tool))
263
+ return preview;
264
+ } else if (!/[{}\[\]"']/u.test(output)) {
265
+ let low = 0;
266
+ let high = Math.min(output.length, max);
267
+ while (low < high) {
268
+ const middle = Math.ceil((low + high) / 2);
269
+ if (JSON.stringify(output.slice(0, middle)).length <= max) low = middle;
270
+ else high = middle - 1;
271
+ }
272
+ if (/[\uD800-\uDBFF]/u.test(output[low - 1] ?? "")) low--;
273
+ return output.slice(0, low);
274
+ }
275
+ return omitted(output.length);
276
+ }
@@ -56,6 +56,13 @@ import { ReadFileLoopGuard } from "../lib/read-file-loop-guard.js";
56
56
  const READ_FILE_REQUEST_CONTEXT = Symbol("read-file-request-context");
57
57
  import { gitToolInputError } from "../lib/git-tool-input.js";
58
58
  import { shellOutputPage, shellOutputPreview } from "../lib/shell-output.js";
59
+ import {
60
+ boundedToolResultText,
61
+ boundedCommandOutput,
62
+ safeHostToolResultForModel,
63
+ registerHostToolOutput,
64
+ copyHostToolOutputIdentity,
65
+ } from "../lib/tool-result-preview.js";
59
66
  import { DIAGNOSTIC_WORKFLOW_GUIDANCE } from "../lib/diagnostic-workflow.js";
60
67
  import { CODING_TASK_QUALITY_GUIDANCE } from "../lib/coding-task-guidance.js";
61
68
  import { RemoteReadLoopGuard } from "../lib/remote-read-loop-guard.js";
@@ -4593,7 +4600,7 @@ export function editNotebookCell(notebookText, args = {}) {
4593
4600
  const out = (summary, cellId) => ({
4594
4601
  text: JSON.stringify(nb, null, 1) + "\n",
4595
4602
  summary,
4596
- cellId,
4603
+ cellId: cellId ?? null,
4597
4604
  });
4598
4605
  const locate = () => {
4599
4606
  if (args.cell_id != null) {
@@ -5725,14 +5732,28 @@ async function executeToolInner(
5725
5732
  descriptor
5726
5733
  ? {
5727
5734
  name: descriptor.name,
5728
- kind: descriptor.kind || descriptor.category || descriptor.source,
5729
- category: descriptor.category,
5735
+ kind:
5736
+ descriptor.kind ||
5737
+ descriptor.category ||
5738
+ descriptor.telemetry?.category ||
5739
+ descriptor.source ||
5740
+ null,
5741
+ category:
5742
+ descriptor.category ??
5743
+ descriptor.telemetry?.category ??
5744
+ descriptor.kind ??
5745
+ null,
5730
5746
  }
5731
5747
  : null;
5732
5748
  const descriptorPayload = buildPayload(runtimeDescriptor);
5733
5749
  const attachDescriptor = (payload, overrideDescriptor = null) => {
5734
5750
  const descriptor = buildPayload(overrideDescriptor || runtimeDescriptor);
5735
- return descriptor ? { ...payload, toolDescriptor: descriptor } : payload;
5751
+ return descriptor
5752
+ ? copyHostToolOutputIdentity(
5753
+ { ...payload, toolDescriptor: descriptor },
5754
+ payload,
5755
+ )
5756
+ : payload;
5736
5757
  };
5737
5758
  const localToolExecutor =
5738
5759
  externalToolExecutors && typeof externalToolExecutors === "object"
@@ -7562,7 +7583,7 @@ async function executeToolInner(
7562
7583
  ? shellOutputPreview(err.stdout, "stdout", 16000)
7563
7584
  : {}),
7564
7585
  ...shellOutputPreview(err.stderr, "stderr", 4000),
7565
- exitCode: err.status,
7586
+ exitCode: err.status ?? null,
7566
7587
  ...(typeof err.code === "string" && err.code
7567
7588
  ? {
7568
7589
  policy: {
@@ -7697,8 +7718,8 @@ async function executeToolInner(
7697
7718
  ) {
7698
7719
  return attachDescriptor({
7699
7720
  success: true,
7700
- stdout: String(res.stdout || "").substring(0, 30000),
7701
- stderr: String(res.stderr || "").substring(0, 2000),
7721
+ ...shellOutputPreview(res.stdout, "stdout", 30000),
7722
+ ...shellOutputPreview(res.stderr, "stderr", 2000),
7702
7723
  exitCode: res.status,
7703
7724
  command: normalizedCommand,
7704
7725
  readOnly: true,
@@ -7707,11 +7728,13 @@ async function executeToolInner(
7707
7728
  });
7708
7729
  }
7709
7730
  if (res.status !== 0) {
7710
- const stderr = String(res.stderr || "").substring(0, 2000);
7731
+ const stderr = String(res.stderr || "");
7711
7732
  return attachDescriptor({
7712
- error: stderr || `git exited with code ${res.status}`,
7713
- stdout: String(res.stdout || "").substring(0, 30000),
7714
- stderr,
7733
+ error:
7734
+ boundedCommandOutput(stderr, 2000) ||
7735
+ `git exited with code ${res.status}`,
7736
+ ...shellOutputPreview(res.stdout, "stdout", 30000),
7737
+ ...shellOutputPreview(stderr, "stderr", 2000),
7715
7738
  exitCode: res.status,
7716
7739
  command: normalizedCommand,
7717
7740
  readOnly,
@@ -7725,7 +7748,7 @@ async function executeToolInner(
7725
7748
  });
7726
7749
  }
7727
7750
  return attachDescriptor({
7728
- stdout: String(res.stdout || "").substring(0, 30000),
7751
+ ...shellOutputPreview(res.stdout, "stdout", 30000),
7729
7752
  exitCode: 0,
7730
7753
  command: normalizedCommand,
7731
7754
  readOnly,
@@ -8000,7 +8023,7 @@ async function executeToolInner(
8000
8023
  const available = discoverCommands(cwd).map((c) => ({
8001
8024
  name: c.name,
8002
8025
  scope: c.scope,
8003
- description: c.description || undefined,
8026
+ ...(c.description ? { description: c.description } : {}),
8004
8027
  }));
8005
8028
  return attachDescriptor({
8006
8029
  error: `Unknown slash command "${head}".`,
@@ -8023,7 +8046,7 @@ async function executeToolInner(
8023
8046
  command: macro.name,
8024
8047
  scope: macro.scope,
8025
8048
  expandedPrompt: expanded,
8026
- warnings: warnings && warnings.length ? warnings : undefined,
8049
+ ...(warnings?.length ? { warnings } : {}),
8027
8050
  instructions:
8028
8051
  "The expandedPrompt is the command's instructions. Carry them out " +
8029
8052
  "now using your normal tools.",
@@ -10301,7 +10324,7 @@ async function _executeRunCode(args, cwd) {
10301
10324
  error: `Invalid package name: "${packageName}"`,
10302
10325
  ...classified,
10303
10326
  language: lang,
10304
- scriptPath: persist ? scriptPath : undefined,
10327
+ ...(persist ? { scriptPath } : {}),
10305
10328
  };
10306
10329
  }
10307
10330
 
@@ -10323,13 +10346,13 @@ async function _executeRunCode(args, cwd) {
10323
10346
  outcome: "disabled",
10324
10347
  });
10325
10348
  return {
10326
- error: (stderr || message).substring(0, 5000),
10327
- stderr: stderr.substring(0, 5000),
10328
- exitCode: err.status,
10349
+ error: boundedCommandOutput(stderr || message, 5000),
10350
+ stderr: boundedCommandOutput(stderr, 5000),
10351
+ exitCode: err.status ?? null,
10329
10352
  language: lang,
10330
10353
  ...classified,
10331
10354
  hint: autoInstallDisabledHint(packageName),
10332
- scriptPath: persist ? scriptPath : undefined,
10355
+ ...(persist ? { scriptPath } : {}),
10333
10356
  };
10334
10357
  }
10335
10358
  if (!isPackageAllowed(packageName, installPolicy.allowlist)) {
@@ -10340,13 +10363,13 @@ async function _executeRunCode(args, cwd) {
10340
10363
  outcome: "blocked",
10341
10364
  });
10342
10365
  return {
10343
- error: (stderr || message).substring(0, 5000),
10344
- stderr: stderr.substring(0, 5000),
10345
- exitCode: err.status,
10366
+ error: boundedCommandOutput(stderr || message, 5000),
10367
+ stderr: boundedCommandOutput(stderr, 5000),
10368
+ exitCode: err.status ?? null,
10346
10369
  language: lang,
10347
10370
  ...classified,
10348
10371
  hint: `Package "${packageName}" is not in runCode.installAllowlist — install it manually or add it to the allowlist.`,
10349
- scriptPath: persist ? scriptPath : undefined,
10372
+ ...(persist ? { scriptPath } : {}),
10350
10373
  };
10351
10374
  }
10352
10375
 
@@ -10396,13 +10419,13 @@ async function _executeRunCode(args, cwd) {
10396
10419
  ),
10397
10420
  );
10398
10421
  return {
10399
- error: (stderr || message).substring(0, 5000),
10400
- stderr: stderr.substring(0, 5000),
10401
- exitCode: err.status,
10422
+ error: boundedCommandOutput(stderr || message, 5000),
10423
+ stderr: boundedCommandOutput(stderr, 5000),
10424
+ exitCode: err.status ?? null,
10402
10425
  language: lang,
10403
10426
  ...classified,
10404
10427
  hint: `Failed to auto-install "${packageName}". ${(installError.stderr || installError.message || "").substring(0, 500)}`,
10405
- scriptPath: persist ? scriptPath : undefined,
10428
+ ...(persist ? { scriptPath } : {}),
10406
10429
  };
10407
10430
  };
10408
10431
 
@@ -10453,14 +10476,13 @@ async function _executeRunCode(args, cwd) {
10453
10476
  );
10454
10477
  const retryDuration = Date.now() - retryStart;
10455
10478
 
10456
- return {
10479
+ return Object.assign(boundedCodeOutput(retryOutput), {
10457
10480
  success: true,
10458
- ...boundedCodeOutput(retryOutput),
10459
10481
  language: lang,
10460
10482
  duration: `${retryDuration}ms`,
10461
10483
  autoInstalled: [packageName],
10462
- scriptPath: persist ? scriptPath : undefined,
10463
- };
10484
+ ...(persist ? { scriptPath } : {}),
10485
+ });
10464
10486
  } catch (retryErr) {
10465
10487
  rethrowRunCodeSandboxFailure(retryErr);
10466
10488
  const retryStderr = (retryErr.stderr || "").toString();
@@ -10472,37 +10494,36 @@ async function _executeRunCode(args, cwd) {
10472
10494
  lang,
10473
10495
  );
10474
10496
  return {
10475
- error: (retryStderr || retryMessage).substring(0, 5000),
10476
- stderr: retryStderr.substring(0, 5000),
10477
- exitCode: retryErr.status,
10497
+ error: boundedCommandOutput(retryStderr || retryMessage, 5000),
10498
+ stderr: boundedCommandOutput(retryStderr, 5000),
10499
+ exitCode: retryErr.status ?? null,
10478
10500
  language: lang,
10479
10501
  ...retryClassified,
10480
10502
  hint: `Package "${packageName}" was installed, but the script retry failed.`,
10481
10503
  autoInstalled: [packageName],
10482
- scriptPath: persist ? scriptPath : undefined,
10504
+ ...(persist ? { scriptPath } : {}),
10483
10505
  };
10484
10506
  }
10485
10507
  }
10486
10508
  }
10487
10509
 
10488
10510
  return {
10489
- error: (stderr || message).substring(0, 5000),
10490
- stderr: stderr.substring(0, 5000),
10491
- exitCode: err.status,
10511
+ error: boundedCommandOutput(stderr || message, 5000),
10512
+ stderr: boundedCommandOutput(stderr, 5000),
10513
+ exitCode: err.status ?? null,
10492
10514
  language: lang,
10493
10515
  ...classified,
10494
- scriptPath: persist ? scriptPath : undefined,
10516
+ ...(persist ? { scriptPath } : {}),
10495
10517
  };
10496
10518
  }
10497
10519
 
10498
10520
  const duration = Date.now() - start;
10499
- return {
10521
+ return Object.assign(boundedCodeOutput(output), {
10500
10522
  success: true,
10501
- ...boundedCodeOutput(output),
10502
10523
  language: lang,
10503
10524
  duration: `${duration}ms`,
10504
- scriptPath: persist ? scriptPath : undefined,
10505
- };
10525
+ ...(persist ? { scriptPath } : {}),
10526
+ });
10506
10527
  } finally {
10507
10528
  // Only clean up if not persisting
10508
10529
  if (!persist) {
@@ -10537,14 +10558,9 @@ export const MAX_SUB_AGENT_DEPTH = 5;
10537
10558
  export const MAX_SUB_AGENTS_PER_RUN = 32;
10538
10559
 
10539
10560
  /**
10540
- * Per-tool-result character cap fed back to the model. One giant tool output (a
10541
- * huge file, a verbose command, an MCP blob) must not blow the context window —
10542
- * but the model is TOLD when output is cut, instead of the old silent
10543
- * `substring(0, 5000)` that sliced mid-content with no marker and undercut even
10544
- * read_file's own 50k self-limit. Tools that self-limit (read_file, notebook
10545
- * render) stay below this; it is the final safety net for the ones that don't
10546
- * (run_shell, search_files, run_code, MCP). CC_MAX_TOOL_RESULT_CHARS may only
10547
- * tighten the host ceiling; it cannot raise or disable it.
10561
+ * Total character cap fed back to the model, including truncation metadata.
10562
+ * Complete JSON previews retain status and small fields while omitting large
10563
+ * leaves. CC_MAX_TOOL_RESULT_CHARS may only tighten the host ceiling.
10548
10564
  */
10549
10565
  export const MAX_TOOL_RESULT_CHARS_HARD_LIMIT = 50000;
10550
10566
 
@@ -10560,47 +10576,38 @@ export const MAX_TOOL_RESULT_CHARS = resolveMaxToolResultChars(
10560
10576
  );
10561
10577
 
10562
10578
  /**
10563
- * Cap a serialized tool result to `max` chars, appending a visible truncation
10564
- * marker (with the original length + how to get the rest) when it overflows —
10565
- * so the model never silently receives a mid-content slice. Pure; exported for
10566
- * tests.
10579
+ * Cap a serialized tool result without splitting JSON values. Plain prefixes
10580
+ * are allowed only when they cannot contain a truncated structured span.
10567
10581
  */
10568
10582
  export function capToolResultString(serialized, max = MAX_TOOL_RESULT_CHARS) {
10569
10583
  const s = String(serialized ?? "");
10570
10584
  const effectiveMax = resolveMaxToolResultChars(max);
10571
- if (s.length <= effectiveMax) return s;
10572
- return (
10573
- s.slice(0, effectiveMax) +
10574
- `\n…[tool output truncated: showing the first ${effectiveMax} of ${s.length} chars` +
10575
- ` — narrow the request (read a line range, grep, or paginate) to see the rest]`
10576
- );
10585
+ return boundedToolResultText(s, effectiveMax);
10577
10586
  }
10578
10587
 
10579
10588
  /** Leave room for JSON escaping and execution metadata, including the hint. */
10580
10589
  export function boundedCodeOutput(value) {
10581
10590
  const output = String(value ?? "");
10582
10591
  const budget = Math.max(0, MAX_TOOL_RESULT_CHARS - 4096);
10583
- let low = 0;
10584
- let high = Math.min(output.length, 50000);
10585
- while (low < high) {
10586
- const mid = Math.ceil((low + high) / 2);
10587
- if (JSON.stringify(output.slice(0, mid)).length <= budget) low = mid;
10588
- else high = mid - 1;
10589
- }
10590
- if (low === output.length) return { output };
10591
- if (low > 0 && /[\uD800-\uDBFF]/.test(output[low - 1])) low--;
10592
- return {
10593
- truncated: true,
10594
- outputChars: output.length,
10595
- returnedChars: low,
10596
- hint: "Only an output prefix is shown. Do not rerun the same full-file print: filter/count locally and print a bounded summary with source line numbers, or use read_file with offset/limit for a missing section. This prefix is not evidence of the entire file.",
10597
- output: output.slice(0, low),
10598
- };
10592
+ if (JSON.stringify(output).length <= budget) return { output };
10593
+ const preview = boundedCommandOutput(output, Math.max(1, budget));
10594
+ return registerHostToolOutput(
10595
+ {
10596
+ truncated: true,
10597
+ outputChars: output.length,
10598
+ returnedChars: preview.length,
10599
+ hint: "Output is incomplete. Do not rerun the same full-file print: filter/count locally and print a bounded summary with source line numbers, or use read_file with offset/limit for a missing section. Omitted text is not evidence of the entire file.",
10600
+ output: preview,
10601
+ },
10602
+ output,
10603
+ );
10599
10604
  }
10600
10605
 
10601
10606
  /** Avoid injecting the same file page twice while its original is still visible. */
10602
10607
  export function toolResultForModel(tool, result, messages) {
10603
- const serialized = capToolResultString(safeStringifyToolResult(result));
10608
+ const serialized = capToolResultString(
10609
+ safeStringifyToolResult(safeHostToolResultForModel(tool, result)),
10610
+ );
10604
10611
  if (
10605
10612
  (tool === "run_code" || tool === "run_shell") &&
10606
10613
  !result?.error &&