zidane 7.2.5 → 8.0.4

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 (376) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +34 -6
  3. package/dist/{acp-D-tVyUjw.js → acp-DQDhi2dj.js} +230 -77
  4. package/dist/acp-DQDhi2dj.js.map +1 -0
  5. package/dist/acp-cli.d.ts +1 -1
  6. package/dist/acp-cli.js +9 -66
  7. package/dist/acp-cli.js.map +1 -1
  8. package/dist/acp.d.ts +10 -590
  9. package/dist/acp.d.ts.map +1 -1
  10. package/dist/acp.js +3 -3
  11. package/dist/{agent-D0zZnGbt.js → agent-DSLNmBp0.js} +14401 -13214
  12. package/dist/agent-DSLNmBp0.js.map +1 -0
  13. package/dist/agent.d.ts +1 -1
  14. package/dist/agent.js +3 -2
  15. package/dist/aliasing-lVFbm81n.js +217 -0
  16. package/dist/aliasing-lVFbm81n.js.map +1 -0
  17. package/dist/{anthropic-C2aole0G.js → anthropic-CD00LhUP.js} +1442 -1264
  18. package/dist/anthropic-CD00LhUP.js.map +1 -0
  19. package/dist/artifacts-CV2hUKnL.js.map +1 -1
  20. package/dist/{atomic-write-B7zr1ddF.js → atomic-write-Ijgf2Mhc.js} +13 -3
  21. package/dist/atomic-write-Ijgf2Mhc.js.map +1 -0
  22. package/dist/call-tool-dHlbGOIY.js +70 -0
  23. package/dist/call-tool-dHlbGOIY.js.map +1 -0
  24. package/dist/chat/pure.d.ts +372 -6
  25. package/dist/chat/pure.d.ts.map +1 -1
  26. package/dist/chat/pure.js +35 -244
  27. package/dist/chat/pure.js.map +1 -1
  28. package/dist/{approvals-DKaJZYlm.js → chat-JPJJ8uu5.js} +15879 -14631
  29. package/dist/chat-JPJJ8uu5.js.map +1 -0
  30. package/dist/chat.d.ts +4 -6
  31. package/dist/chat.js +23 -12
  32. package/dist/cli-shared-C-YCaglL.js +159 -0
  33. package/dist/cli-shared-C-YCaglL.js.map +1 -0
  34. package/dist/client-core-BQSyDALT.d.ts +2115 -0
  35. package/dist/client-core-BQSyDALT.d.ts.map +1 -0
  36. package/dist/codemode-worker.d.ts +1 -0
  37. package/dist/codemode-worker.js +155 -0
  38. package/dist/codemode-worker.js.map +1 -0
  39. package/dist/codemode.d.ts +352 -0
  40. package/dist/codemode.d.ts.map +1 -0
  41. package/dist/codemode.js +5 -0
  42. package/dist/connection-Dr-Js4yZ.d.ts +28 -0
  43. package/dist/connection-Dr-Js4yZ.d.ts.map +1 -0
  44. package/dist/connection-loop-gdh22LTI.js +112 -0
  45. package/dist/connection-loop-gdh22LTI.js.map +1 -0
  46. package/dist/context-segments-BHKlagL6.js +1016 -0
  47. package/dist/context-segments-BHKlagL6.js.map +1 -0
  48. package/dist/{context-transport-T_6AYIvy.js → context-transport-DSMTUsK1.js} +3 -3
  49. package/dist/{context-transport-T_6AYIvy.js.map → context-transport-DSMTUsK1.js.map} +1 -1
  50. package/dist/contexts/daytona.d.ts +19 -8
  51. package/dist/contexts/daytona.d.ts.map +1 -1
  52. package/dist/contexts/daytona.js +1 -440
  53. package/dist/contexts/docker.d.ts +36 -7
  54. package/dist/contexts/docker.d.ts.map +1 -1
  55. package/dist/contexts/docker.js +1 -456
  56. package/dist/contexts/e2b.d.ts +68 -13
  57. package/dist/contexts/e2b.d.ts.map +1 -1
  58. package/dist/contexts/e2b.js +1 -382
  59. package/dist/contexts/sandbox.d.ts +1 -1
  60. package/dist/contexts/sandbox.js +5 -0
  61. package/dist/contexts/sandbox.js.map +1 -1
  62. package/dist/{contexts-CRE9pw07.js → contexts-d7UolYot.js} +1059 -524
  63. package/dist/contexts-d7UolYot.js.map +1 -0
  64. package/dist/contexts.d.ts +3 -3
  65. package/dist/contexts.js +1 -1
  66. package/dist/cred-keys-GpBg71cP.js +105 -0
  67. package/dist/cred-keys-GpBg71cP.js.map +1 -0
  68. package/dist/{auth-BG2rVKSt.js → credentials-JttEuRON.js} +55 -206
  69. package/dist/credentials-JttEuRON.js.map +1 -0
  70. package/dist/{cursor-iojRXHF9.js → cursor-CdjaQTBW.js} +3 -3
  71. package/dist/{cursor-iojRXHF9.js.map → cursor-CdjaQTBW.js.map} +1 -1
  72. package/dist/daemon-cli.d.ts +1 -1
  73. package/dist/daemon-cli.js +3 -2
  74. package/dist/daemon-cli.js.map +1 -1
  75. package/dist/daytona-DG3omipZ.js +513 -0
  76. package/dist/daytona-DG3omipZ.js.map +1 -0
  77. package/dist/defaults-Cx3zvDOV.js +23 -0
  78. package/dist/defaults-Cx3zvDOV.js.map +1 -0
  79. package/dist/dispatcher-BMlu2BmZ.js +4941 -0
  80. package/dist/dispatcher-BMlu2BmZ.js.map +1 -0
  81. package/dist/docker-BZhMMJUp.js +727 -0
  82. package/dist/docker-BZhMMJUp.js.map +1 -0
  83. package/dist/e2b-CEVOdRib.js +480 -0
  84. package/dist/e2b-CEVOdRib.js.map +1 -0
  85. package/dist/edit-utils-EGosADZq.js +234 -0
  86. package/dist/edit-utils-EGosADZq.js.map +1 -0
  87. package/dist/environment-8wsKE2Ln.js +214 -0
  88. package/dist/environment-8wsKE2Ln.js.map +1 -0
  89. package/dist/eval-BNcvle_J.js +1595 -0
  90. package/dist/eval-BNcvle_J.js.map +1 -0
  91. package/dist/eval.d.ts +2 -2
  92. package/dist/eval.js +1 -1489
  93. package/dist/executor-Cx5-8yqi.js +621 -0
  94. package/dist/executor-Cx5-8yqi.js.map +1 -0
  95. package/dist/extension-authoring-DyGGmq9V.js +385 -0
  96. package/dist/extension-authoring-DyGGmq9V.js.map +1 -0
  97. package/dist/extensions.d.ts +2 -2
  98. package/dist/extensions.js +3 -3
  99. package/dist/{fetch-url-DX75gpL0.js → fetch-url-Ct2TjDWt.js} +4 -4
  100. package/dist/{fetch-url-DX75gpL0.js.map → fetch-url-Ct2TjDWt.js.map} +1 -1
  101. package/dist/{format-BF745pLL.js → format-C2NQEVUH.js} +39 -2
  102. package/dist/format-C2NQEVUH.js.map +1 -0
  103. package/dist/format-bytes-C7tfc3Zm.js +55 -0
  104. package/dist/format-bytes-C7tfc3Zm.js.map +1 -0
  105. package/dist/headless-C_rNUuYC.js +960 -0
  106. package/dist/headless-C_rNUuYC.js.map +1 -0
  107. package/dist/headless.d.ts +1 -1
  108. package/dist/headless.js +1 -413
  109. package/dist/{history-search-C4bk1Wz_.js → history-search-CcYzF8-0.js} +7 -3
  110. package/dist/history-search-CcYzF8-0.js.map +1 -0
  111. package/dist/history-search-worker.d.ts +1 -1
  112. package/dist/history-search-worker.js +1 -1
  113. package/dist/host-D7NrI03V.js +378 -0
  114. package/dist/host-D7NrI03V.js.map +1 -0
  115. package/dist/host-signals-BcP5QKUD.js +118 -0
  116. package/dist/host-signals-BcP5QKUD.js.map +1 -0
  117. package/dist/identity-CwfO8K-t.js +26 -0
  118. package/dist/identity-CwfO8K-t.js.map +1 -0
  119. package/dist/{index-BgN1T3lk.d.ts → index-BGe1fQT7.d.ts} +10987 -9320
  120. package/dist/index-BGe1fQT7.d.ts.map +1 -0
  121. package/dist/index-BVQsIKGn.d.ts +448 -0
  122. package/dist/index-BVQsIKGn.d.ts.map +1 -0
  123. package/dist/{index-C6NEd5y_.d.ts → index-CHABJd-L.d.ts} +3386 -502
  124. package/dist/index-CHABJd-L.d.ts.map +1 -0
  125. package/dist/{index-C37_ppWv.d.ts → index-D6a7qXpg.d.ts} +2 -3
  126. package/dist/index-D6a7qXpg.d.ts.map +1 -0
  127. package/dist/index.d.ts +6 -6
  128. package/dist/index.js +27 -23
  129. package/dist/{completion-core-BRo86R_L.js → inline-ghost-BVRQeGoL.js} +50 -2
  130. package/dist/inline-ghost-BVRQeGoL.js.map +1 -0
  131. package/dist/ipc/remote.d.ts +313 -0
  132. package/dist/ipc/remote.d.ts.map +1 -0
  133. package/dist/ipc/remote.js +4 -0
  134. package/dist/ipc.d.ts +6 -964
  135. package/dist/ipc.js +403 -4
  136. package/dist/ipc.js.map +1 -0
  137. package/dist/{isolation-Kfoof0MM.d.ts → isolation-D9L650W5.d.ts} +100 -15
  138. package/dist/isolation-D9L650W5.d.ts.map +1 -0
  139. package/dist/json-rpc--HXQti1E.js +350 -0
  140. package/dist/json-rpc--HXQti1E.js.map +1 -0
  141. package/dist/links-j8rED1sR.js +603 -0
  142. package/dist/links-j8rED1sR.js.map +1 -0
  143. package/dist/local-terminal-D8QThwo_.js +252 -0
  144. package/dist/local-terminal-D8QThwo_.js.map +1 -0
  145. package/dist/{logger--C1VQjwJ.js → logger-Gtqlayx8.js} +199 -173
  146. package/dist/logger-Gtqlayx8.js.map +1 -0
  147. package/dist/logs-view-CWG8aUAG.js.map +1 -1
  148. package/dist/{mcp-CgNd-f3F.js → mcp-_wecH9Qe.js} +608 -562
  149. package/dist/mcp-_wecH9Qe.js.map +1 -0
  150. package/dist/mcp.d.ts +2 -2
  151. package/dist/mcp.js +2 -2
  152. package/dist/media-sniff-UKijEaiQ.js.map +1 -1
  153. package/dist/{messages-2jcOA_5R.js → messages-BqiwcD2Q.js} +1017 -1014
  154. package/dist/messages-BqiwcD2Q.js.map +1 -0
  155. package/dist/{oauth-DxHO17JE.js → oauth-Px_pBB9W.js} +5 -5
  156. package/dist/{oauth-DxHO17JE.js.map → oauth-Px_pBB9W.js.map} +1 -1
  157. package/dist/{openai-compat-Dy56weK8.js → openai-compat-CFrpH7uq.js} +432 -589
  158. package/dist/openai-compat-CFrpH7uq.js.map +1 -0
  159. package/dist/orchestration-BCGmB8Ps.js +511 -0
  160. package/dist/orchestration-BCGmB8Ps.js.map +1 -0
  161. package/dist/output/stream-json.d.ts +1 -2
  162. package/dist/output/stream-json.d.ts.map +1 -1
  163. package/dist/output/stream-json.js +1 -1
  164. package/dist/output/terminal.d.ts +1 -2
  165. package/dist/output/terminal.d.ts.map +1 -1
  166. package/dist/output/terminal.js +13 -7
  167. package/dist/output/terminal.js.map +1 -1
  168. package/dist/{plugins-gbI7SBA6.js → plugins-DS7mahzZ.js} +20 -101
  169. package/dist/plugins-DS7mahzZ.js.map +1 -0
  170. package/dist/plugins.d.ts +1 -1
  171. package/dist/plugins.js +1 -2
  172. package/dist/prelude-Cxo4t74B.js +517 -0
  173. package/dist/prelude-Cxo4t74B.js.map +1 -0
  174. package/dist/presets.d.ts +1 -1
  175. package/dist/presets.js +1 -2
  176. package/dist/project-root-B8zADr4o.js +167 -0
  177. package/dist/project-root-B8zADr4o.js.map +1 -0
  178. package/dist/project-user-paths-BSgtrRxl.js +58 -0
  179. package/dist/project-user-paths-BSgtrRxl.js.map +1 -0
  180. package/dist/{prompts-Pqc3JdW_.d.ts → prompts-DYcvqShf.d.ts} +14 -11
  181. package/dist/prompts-DYcvqShf.d.ts.map +1 -0
  182. package/dist/protocol-DnhqqSmE.js +13 -0
  183. package/dist/protocol-DnhqqSmE.js.map +1 -0
  184. package/dist/providers/anthropic.d.ts +2 -2
  185. package/dist/providers/anthropic.js +1 -2
  186. package/dist/providers/arcee.d.ts +1 -1
  187. package/dist/providers/arcee.js +1 -1
  188. package/dist/providers/baseten.d.ts +1 -1
  189. package/dist/providers/baseten.js +1 -1
  190. package/dist/providers/cerebras.d.ts +1 -1
  191. package/dist/providers/cerebras.js +3 -2
  192. package/dist/providers/cerebras.js.map +1 -1
  193. package/dist/providers/local.d.ts +1 -1
  194. package/dist/providers/local.js +1 -1
  195. package/dist/providers/openai-compat.d.ts +1 -1
  196. package/dist/providers/openai-compat.js +1 -2
  197. package/dist/providers/openai.d.ts +1 -1
  198. package/dist/providers/openai.js +15 -12
  199. package/dist/providers/openai.js.map +1 -1
  200. package/dist/providers/openrouter.d.ts +1 -1
  201. package/dist/providers/openrouter.js +3 -2
  202. package/dist/providers/openrouter.js.map +1 -1
  203. package/dist/providers/xai.d.ts +1 -1
  204. package/dist/providers/xai.js +3 -3
  205. package/dist/{providers-BVhnFyiY.js → providers-XUR7F4Hi.js} +4 -4
  206. package/dist/{providers-BVhnFyiY.js.map → providers-XUR7F4Hi.js.map} +1 -1
  207. package/dist/providers.d.ts +1 -1
  208. package/dist/providers.js +4 -4
  209. package/dist/registry-D6ShBWJU.js +5234 -0
  210. package/dist/registry-D6ShBWJU.js.map +1 -0
  211. package/dist/remote-hosts-BtA_9ZGp.js +97 -0
  212. package/dist/remote-hosts-BtA_9ZGp.js.map +1 -0
  213. package/dist/restate.d.ts +2 -3
  214. package/dist/restate.d.ts.map +1 -1
  215. package/dist/restate.js +631 -572
  216. package/dist/restate.js.map +1 -1
  217. package/dist/run-summary-CklLiZ4y.js +288 -0
  218. package/dist/run-summary-CklLiZ4y.js.map +1 -0
  219. package/dist/{sandbox-BH0WQkXn.d.ts → sandbox-C5dR5DwQ.d.ts} +6 -3
  220. package/dist/sandbox-C5dR5DwQ.d.ts.map +1 -0
  221. package/dist/session/sqlite.d.ts +1 -2
  222. package/dist/session/sqlite.d.ts.map +1 -1
  223. package/dist/session/sqlite.js +1 -616
  224. package/dist/session-factory-BUGY5P40.js +1576 -0
  225. package/dist/session-factory-BUGY5P40.js.map +1 -0
  226. package/dist/{session-BqRP1hS7.js → session-xh9JXu6i.js} +94 -52
  227. package/dist/session-xh9JXu6i.js.map +1 -0
  228. package/dist/session.d.ts +1 -1
  229. package/dist/session.js +2 -2
  230. package/dist/settings-keys-Ckf29NeM.js +677 -0
  231. package/dist/settings-keys-Ckf29NeM.js.map +1 -0
  232. package/dist/shell-path-Dqaoow2J.js +412 -0
  233. package/dist/shell-path-Dqaoow2J.js.map +1 -0
  234. package/dist/{skills-BC3dodWp.js → skills-DKqZJm4X.js} +430 -470
  235. package/dist/skills-DKqZJm4X.js.map +1 -0
  236. package/dist/skills.d.ts +2 -2
  237. package/dist/skills.js +1 -2
  238. package/dist/source-mPExaUm8.js +381 -0
  239. package/dist/source-mPExaUm8.js.map +1 -0
  240. package/dist/sqlite-DV1DQzN2.js +698 -0
  241. package/dist/sqlite-DV1DQzN2.js.map +1 -0
  242. package/dist/{src-CkNQKFKr.js → src-BRMYRJib.js} +903 -1121
  243. package/dist/src-BRMYRJib.js.map +1 -0
  244. package/dist/{stdio-DPpBDPx5.js → stdio-C6YyoW3I.js} +4 -4
  245. package/dist/{stdio-DPpBDPx5.js.map → stdio-C6YyoW3I.js.map} +1 -1
  246. package/dist/{stdio-loader-Bbx19dMZ.js → stdio-loader-C830Vg-Z.js} +4 -4
  247. package/dist/{stdio-loader-Bbx19dMZ.js.map → stdio-loader-C830Vg-Z.js.map} +1 -1
  248. package/dist/system-prompt-MNVHatSD.d.ts.map +1 -1
  249. package/dist/timeout-DEaqslLO.d.ts.map +1 -1
  250. package/dist/todo-edits-Dn251YUP.js +1790 -0
  251. package/dist/todo-edits-Dn251YUP.js.map +1 -0
  252. package/dist/{turn-operations-DrbJlpq9.js → tool-formatters-IQFDrdrs.js} +1456 -2120
  253. package/dist/tool-formatters-IQFDrdrs.js.map +1 -0
  254. package/dist/tool-state-Dku6YqAB.js +989 -0
  255. package/dist/tool-state-Dku6YqAB.js.map +1 -0
  256. package/dist/tools/fetch-url.d.ts +1 -2
  257. package/dist/tools/fetch-url.d.ts.map +1 -1
  258. package/dist/tools/fetch-url.js +1 -2
  259. package/dist/tools/prompts.d.ts +1 -1
  260. package/dist/tools/prompts.js +7 -7
  261. package/dist/tools/prompts.js.map +1 -1
  262. package/dist/tools/web-search.d.ts +1 -2
  263. package/dist/tools/web-search.d.ts.map +1 -1
  264. package/dist/tools/web-search.js +2 -2
  265. package/dist/tools/web-search.js.map +1 -1
  266. package/dist/tools-_DnT3AGM.js +578 -0
  267. package/dist/tools-_DnT3AGM.js.map +1 -0
  268. package/dist/tools.d.ts +3 -3
  269. package/dist/tools.js +4 -2
  270. package/dist/tui.d.ts +534 -517
  271. package/dist/tui.d.ts.map +1 -1
  272. package/dist/tui.js +34933 -27243
  273. package/dist/tui.js.map +1 -1
  274. package/dist/turn-operations-B8sokwi5.js +333 -0
  275. package/dist/turn-operations-B8sokwi5.js.map +1 -0
  276. package/dist/turn-operations-DQX5ZZni.d.ts +3089 -0
  277. package/dist/turn-operations-DQX5ZZni.d.ts.map +1 -0
  278. package/dist/types-C7ZFOztE.d.ts +132 -0
  279. package/dist/types-C7ZFOztE.d.ts.map +1 -0
  280. package/dist/types-CH5XpIHw.js +114 -0
  281. package/dist/types-CH5XpIHw.js.map +1 -0
  282. package/dist/{types-CWgENVLY.js → types-Cu0ZGDu9.js} +10 -6
  283. package/dist/types-Cu0ZGDu9.js.map +1 -0
  284. package/dist/types-IqegbJEE.d.ts +624 -0
  285. package/dist/types-IqegbJEE.d.ts.map +1 -0
  286. package/dist/types.d.ts +4 -4
  287. package/dist/types.js +1 -1
  288. package/dist/url-D8HCl65b.js +1259 -0
  289. package/dist/url-D8HCl65b.js.map +1 -0
  290. package/dist/wasm-BVT-j5cl.js +33 -0
  291. package/dist/wasm-BVT-j5cl.js.map +1 -0
  292. package/dist/workspace-exec-stream-SV2R9d5S.js +355 -0
  293. package/dist/workspace-exec-stream-SV2R9d5S.js.map +1 -0
  294. package/dist/ws-CIHMvlSh.js +952 -0
  295. package/dist/ws-CIHMvlSh.js.map +1 -0
  296. package/dist/ws-client-N7NxzvQp.js +230 -0
  297. package/dist/ws-client-N7NxzvQp.js.map +1 -0
  298. package/dist/{xai-CazjStOK.js → xai-CvJTeLrI.js} +165 -5
  299. package/dist/xai-CvJTeLrI.js.map +1 -0
  300. package/dist/xdg-zweed0-t.js +117 -0
  301. package/dist/xdg-zweed0-t.js.map +1 -0
  302. package/docs/ACP.md +52 -0
  303. package/docs/ARCHITECTURE.md +103 -6
  304. package/docs/ARTIFACTS.md +8 -4
  305. package/docs/CHAT.md +165 -14
  306. package/docs/EXECUTION_CONTEXT.md +8 -0
  307. package/docs/EXTENSIONS.md +123 -2
  308. package/docs/HEADLESS.md +2 -0
  309. package/docs/IPC.md +775 -64
  310. package/docs/MACHINES.md +456 -0
  311. package/docs/PANELS.md +3 -0
  312. package/docs/README.md +4 -0
  313. package/docs/RESTATE.md +3 -2
  314. package/docs/RUN_IN_BACKGROUND.md +10 -2
  315. package/docs/SERVER.md +1085 -0
  316. package/docs/SKILL.md +6 -1
  317. package/docs/TERMINAL.md +75 -0
  318. package/docs/TUI.md +65 -14
  319. package/package.json +58 -26
  320. package/scripts/eval.ts +4 -0
  321. package/dist/acp-D-tVyUjw.js.map +0 -1
  322. package/dist/agent-D0zZnGbt.js.map +0 -1
  323. package/dist/anthropic-C2aole0G.js.map +0 -1
  324. package/dist/approvals-DKaJZYlm.js.map +0 -1
  325. package/dist/atomic-write-B7zr1ddF.js.map +0 -1
  326. package/dist/auth-BG2rVKSt.js.map +0 -1
  327. package/dist/completion-core-BRo86R_L.js.map +0 -1
  328. package/dist/contexts/daytona.js.map +0 -1
  329. package/dist/contexts/docker.js.map +0 -1
  330. package/dist/contexts/e2b.js.map +0 -1
  331. package/dist/contexts-CRE9pw07.js.map +0 -1
  332. package/dist/eval.js.map +0 -1
  333. package/dist/format-BF745pLL.js.map +0 -1
  334. package/dist/glob-DluQFSw1.js +0 -270
  335. package/dist/glob-DluQFSw1.js.map +0 -1
  336. package/dist/headless.js.map +0 -1
  337. package/dist/history-search-C4bk1Wz_.js.map +0 -1
  338. package/dist/index-BgN1T3lk.d.ts.map +0 -1
  339. package/dist/index-C37_ppWv.d.ts.map +0 -1
  340. package/dist/index-C6NEd5y_.d.ts.map +0 -1
  341. package/dist/ipc-BKVIIOqH.js +0 -331
  342. package/dist/ipc-BKVIIOqH.js.map +0 -1
  343. package/dist/ipc.d.ts.map +0 -1
  344. package/dist/isolation-Kfoof0MM.d.ts.map +0 -1
  345. package/dist/json-rpc-rSWMUh9b.js +0 -192
  346. package/dist/json-rpc-rSWMUh9b.js.map +0 -1
  347. package/dist/logger--C1VQjwJ.js.map +0 -1
  348. package/dist/mcp-CgNd-f3F.js.map +0 -1
  349. package/dist/messages-2jcOA_5R.js.map +0 -1
  350. package/dist/openai-compat-Dy56weK8.js.map +0 -1
  351. package/dist/output-cap-C9zukcCj.js +0 -100
  352. package/dist/output-cap-C9zukcCj.js.map +0 -1
  353. package/dist/panels-B6gRk4bf.js +0 -789
  354. package/dist/panels-B6gRk4bf.js.map +0 -1
  355. package/dist/plugins-gbI7SBA6.js.map +0 -1
  356. package/dist/prompts-Pqc3JdW_.d.ts.map +0 -1
  357. package/dist/run-summary-BU_NgwUT.js +0 -269
  358. package/dist/run-summary-BU_NgwUT.js.map +0 -1
  359. package/dist/sandbox-BH0WQkXn.d.ts.map +0 -1
  360. package/dist/session/sqlite.js.map +0 -1
  361. package/dist/session-BqRP1hS7.js.map +0 -1
  362. package/dist/shell-path-DfdXrGg9.js +0 -1549
  363. package/dist/shell-path-DfdXrGg9.js.map +0 -1
  364. package/dist/skills-BC3dodWp.js.map +0 -1
  365. package/dist/src-CkNQKFKr.js.map +0 -1
  366. package/dist/todo-edits-UOwgxGKu.js +0 -528
  367. package/dist/todo-edits-UOwgxGKu.js.map +0 -1
  368. package/dist/tool-formatters-DoRLnfuD.d.ts +0 -759
  369. package/dist/tool-formatters-DoRLnfuD.d.ts.map +0 -1
  370. package/dist/transcript-anchors-BeudMbXx.d.ts +0 -1762
  371. package/dist/transcript-anchors-BeudMbXx.d.ts.map +0 -1
  372. package/dist/turn-operations-C8bMBDl_.d.ts +0 -1258
  373. package/dist/turn-operations-C8bMBDl_.d.ts.map +0 -1
  374. package/dist/turn-operations-DrbJlpq9.js.map +0 -1
  375. package/dist/types-CWgENVLY.js.map +0 -1
  376. package/dist/xai-CazjStOK.js.map +0 -1
@@ -1,19 +1,16 @@
1
- import { t as defineSkill } from "./skills-BC3dodWp.js";
2
- import { h as McpOAuthProvider, m as sseToJsonFetchIfNeeded, o as expandMcpConfigEnv, p as createTolerantClient, v as isOAuthTokenRejectionError } from "./mcp-CgNd-f3F.js";
3
- import { createRequire } from "node:module";
1
+ import { g as McpOAuthProvider, h as createTolerantClient, l as expandMcpConfigEnv, s as sseToJsonFetchIfNeeded, y as isOAuthTokenRejectionError } from "./mcp-_wecH9Qe.js";
2
+ import { readdirSync } from "node:fs";
4
3
  import { basename, dirname, isAbsolute, join, resolve } from "node:path";
5
- import { existsSync, readdirSync } from "node:fs";
6
4
  import { homedir } from "node:os";
7
- import { fileURLToPath } from "node:url";
8
5
  import { createServer } from "node:http";
9
6
  //#region src/behaviors/local-reliability.ts
10
7
  const DEFAULT_LOCAL_RELIABILITY = {
11
8
  maxConcurrentTools: 3,
12
9
  readFileDefaults: {
13
10
  limit: 400,
14
- maxBytes: 64 * 1024
11
+ maxBytes: 65536
15
12
  },
16
- toolOutputBudget: 32 * 1024,
13
+ toolOutputBudget: 32768,
17
14
  textToolCallRescue: { mode: "steer" },
18
15
  thinkingOverrunPolicy: {
19
16
  mode: "steer-next-turn",
@@ -105,6 +102,39 @@ function commandSteps(command) {
105
102
  return [];
106
103
  }
107
104
  /**
105
+ * The one `/` command merge every host uses: builtins, then extension
106
+ * commands, then markdown file commands. First registration wins,
107
+ * case-insensitive; aliases reserve names so a later command named like an
108
+ * earlier alias stays unreachable rather than ambiguous.
109
+ */
110
+ function mergeCommands(layers, onDrop) {
111
+ const merged = [];
112
+ const seen = /* @__PURE__ */ new Set();
113
+ const add = (command, layer) => {
114
+ const key = command.name.toLowerCase();
115
+ if (seen.has(key)) {
116
+ if (layer !== "builtin") onDrop?.(command, layer);
117
+ return;
118
+ }
119
+ seen.add(key);
120
+ for (const alias of command.aliases ?? []) seen.add(alias.toLowerCase());
121
+ merged.push(command);
122
+ };
123
+ for (const command of layers.builtins) add(command, "builtin");
124
+ for (const command of layers.extension) add(command, "extension");
125
+ for (const command of layers.file ?? []) add(command, "file");
126
+ return merged;
127
+ }
128
+ /**
129
+ * Daemon-mode routing: does a resolved command run HOST-SIDE? Every command
130
+ * that is not a TUI builtin (extension or markdown file) does; builtins and
131
+ * an unresolved name stay local. Pass the command resolved from the MERGED
132
+ * registry, so a builtin shadowing an extension of the same name stays local.
133
+ */
134
+ function routesToDaemon(resolved, builtins) {
135
+ return resolved !== void 0 && !builtins.includes(resolved);
136
+ }
137
+ /**
108
138
  * Parse a prompt as a command invocation, but only when the command token is
109
139
  * the LEADING token of the whole prompt and names a known command. This is
110
140
  * what keeps mid-prompt `/skill` mentions routed to the skills provider:
@@ -142,6 +172,36 @@ function parseCommandInvocation(prompt, known) {
142
172
  argv: args.length > 0 ? args.split(/\s+/) : []
143
173
  };
144
174
  }
175
+ function createCommandRunRecord(session, invocation) {
176
+ let runId;
177
+ const persist = async () => {
178
+ const record = runId ? session.runs.find((r) => r.id === runId) : void 0;
179
+ if (record) await session.updateRun(record).catch(() => void 0);
180
+ };
181
+ return {
182
+ async ensure() {
183
+ if (runId) return runId;
184
+ runId = `cmd_${crypto.randomUUID()}`;
185
+ session.startRun(runId, `/${invocation.name}${invocation.args ? ` ${invocation.args}` : ""}`, { depth: 0 });
186
+ const record = session.runs.find((r) => r.id === runId);
187
+ if (record) record.origin = { kind: "command" };
188
+ await persist();
189
+ return runId;
190
+ },
191
+ async finish(outcome) {
192
+ if (!runId) return;
193
+ const stats = {
194
+ turns: 0,
195
+ tokensIn: 0,
196
+ tokensOut: 0
197
+ };
198
+ if (outcome.error !== void 0) session.errorRun(runId, outcome.error, stats);
199
+ else if (outcome.aborted) session.abortRun(runId, stats);
200
+ else session.completeRun(runId, stats);
201
+ await persist();
202
+ }
203
+ };
204
+ }
145
205
  /**
146
206
  * Run a command's steps in order, threading `ctx.data`. Stops at the first
147
207
  * step that throws (error isolated + returned, not rethrown) or when the
@@ -195,12 +255,12 @@ function isStandardSchema(value) {
195
255
  async function resolveSchemaInput(schema) {
196
256
  if (!isStandardSchema(schema)) return schema;
197
257
  const vendor = schema["~standard"].vendor;
198
- if (vendor !== "zod") throw new Error(`unsupported schema vendor "${vendor}" — pass a zod v4 schema or a plain JSON Schema object`);
258
+ if (vendor !== "zod") throw new Error(`unsupported schema vendor "${vendor}". Pass a zod v4 schema or a plain JSON Schema object.`);
199
259
  let toJSONSchema;
200
260
  try {
201
261
  toJSONSchema = (await import("zod")).z.toJSONSchema;
202
262
  } catch {
203
- throw new Error("a zod schema was passed but the \"zod\" package could not be imported — install zod >= 4");
263
+ throw new Error("a zod schema was passed but the \"zod\" package could not be imported. Install zod >= 4");
204
264
  }
205
265
  return zodToJsonSchema(toJSONSchema(schema));
206
266
  }
@@ -422,7 +482,7 @@ function cleanTitle(raw) {
422
482
  if (s.length === 0) throw new Error("Model returned an empty title.");
423
483
  if (/^\[.*\]$/.test(s)) throw new Error("Model returned a placeholder instead of a title.");
424
484
  if (ANSWER_SHAPED_OPENER.test(s)) throw new Error("Model answered the conversation instead of titling it.");
425
- return s.length > TITLE_MAX_CHARS ? `${s.slice(0, TITLE_MAX_CHARS - 1)}…` : s;
485
+ return s.length > TITLE_MAX_CHARS ? `${s.slice(0, 59)}…` : s;
426
486
  }
427
487
  function clip(text, max) {
428
488
  return text.length > max ? `${text.slice(0, max)}…` : text;
@@ -581,429 +641,6 @@ function createPathAutocompleteProvider(opts = {}) {
581
641
  }
582
642
  };
583
643
  }
584
- /**
585
- * Optimistically transform the current ghost across a buffer edit so it
586
- * stays visible while the debounced provider re-query is in flight —
587
- * without this, every keystroke inside a completable token blinks the
588
- * ghost (hide → 120 ms → reshow).
589
- *
590
- * Two edits are reconcilable (everything else returns null and waits for
591
- * the authoritative result):
592
- * - typing FORWARD along the suggestion (`bi` → `bin` with ghost
593
- * `n/`): candidates are filtered to those starting with the typed
594
- * chars and trimmed;
595
- * - deleting BACKWARD within the token (`bin` → `bi` with ghost `/`):
596
- * the deleted chars are re-prepended to every candidate. Guarded to
597
- * non-whitespace so crossing a token boundary drops the ghost.
598
- *
599
- * The patched ghost is provisional — the provider's answer replaces it
600
- * (and may add candidates the patch couldn't know about).
601
- */
602
- function patchInlineGhost(prev, text, cursor) {
603
- if (!prev) return null;
604
- if (text === prev.text && cursor === prev.cursor) return prev;
605
- if (text.slice(cursor) !== prev.text.slice(prev.cursor)) return null;
606
- if (cursor > prev.cursor) {
607
- if (text.slice(0, prev.cursor) !== prev.text.slice(0, prev.cursor)) return null;
608
- const typed = text.slice(prev.cursor, cursor);
609
- const shown = prev.suffixes[prev.index];
610
- const suffixes = prev.suffixes.filter((s) => s.startsWith(typed) && s.length > typed.length).map((s) => s.slice(typed.length));
611
- if (suffixes.length === 0) return null;
612
- const shownTrimmed = shown.startsWith(typed) ? shown.slice(typed.length) : null;
613
- return {
614
- suffixes,
615
- index: shownTrimmed !== null ? Math.max(0, suffixes.indexOf(shownTrimmed)) : 0,
616
- text,
617
- cursor
618
- };
619
- }
620
- if (prev.text.slice(0, cursor) !== text.slice(0, cursor)) return null;
621
- const deleted = prev.text.slice(cursor, prev.cursor);
622
- if (deleted.length === 0 || /\s/.test(deleted)) return null;
623
- return {
624
- suffixes: prev.suffixes.map((s) => deleted + s),
625
- index: prev.index,
626
- text,
627
- cursor
628
- };
629
- }
630
- //#endregion
631
- //#region src/extension-authoring.ts
632
- /**
633
- * Session-metadata key marking an "edit / create extension" session. The value
634
- * is an {@link ExtensionEditMarker}. Both hosts stamp it at session creation so
635
- * the agent build can scope the docs skill to exactly these sessions (and it
636
- * survives reload because metadata is persisted).
637
- */
638
- const EXTENSION_EDIT_METADATA_KEY = "zidane.extensionEdit";
639
- /** Name of the inline docs skill auto-activated in extension edit sessions. */
640
- const ZIDANE_EXTENSION_SKILL_NAME = "zidane-extension";
641
- /**
642
- * Session-metadata key marking an "edit skill" session — the skill-editing
643
- * counterpart of {@link EXTENSION_EDIT_METADATA_KEY}. The value is a
644
- * {@link SkillEditMarker}. Stamped at session creation by both hosts (via
645
- * {@link editSessionMetadata}); persisted metadata means it survives reload.
646
- */
647
- const SKILL_EDIT_METADATA_KEY = "zidane.skillEdit";
648
- /** Name of the inline preset skill auto-activated in skill edit sessions. */
649
- const ZIDANE_SKILL_EDIT_SKILL_NAME = "zidane-skill";
650
- /**
651
- * THE canonical seed for "open an editing session with preset context" —
652
- * the session metadata both hosts stamp at creation time. The engines read
653
- * the marker back and inject + auto-activate the matching inline preset
654
- * skill ({@link buildZidaneExtensionSkill} / {@link buildZidaneSkillEditSkill}),
655
- * so the preset rides as real conversation context from turn one.
656
- */
657
- function editSessionMetadata(target) {
658
- return target.kind === "extension" ? { [EXTENSION_EDIT_METADATA_KEY]: { dir: target.dir } } : { [SKILL_EDIT_METADATA_KEY]: {
659
- dir: target.dir,
660
- name: target.name
661
- } };
662
- }
663
- /**
664
- * Parse a persisted {@link SkillEditMarker} back out of session metadata.
665
- * Tolerant: anything that isn't `{ dir: string, name: string }` → `null`
666
- * (older sessions, manual metadata edits, type drift).
667
- */
668
- function readSkillEditMarker(raw) {
669
- if (typeof raw !== "object" || raw === null) return null;
670
- const { dir, name } = raw;
671
- if (typeof dir !== "string" || dir.length === 0 || typeof name !== "string" || name.length === 0) return null;
672
- return {
673
- dir,
674
- name
675
- };
676
- }
677
- /**
678
- * Minimal valid extension module for a freshly-created extension. `name` MUST
679
- * equal the folder name or the loader rejects it (see `src/extensions/discovery`).
680
- * Does nothing by default — the author registers contributions via `ctx.*`
681
- * inside `setup`; the auto-activated docs skill guides them from there.
682
- */
683
- function extensionScaffold(name) {
684
- return `import { defineExtension } from 'zidane'
685
-
686
- /**
687
- * ${name} — a zidane extension.
688
- *
689
- * Register tools / hooks / skills / MCP servers / subagents / config / themes /
690
- * agents / keybindings via the \`ctx\` surface inside \`setup\`.
691
- *
692
- * Authoring reference: activate the \`${ZIDANE_EXTENSION_SKILL_NAME}\` skill — it carries
693
- * the full \`ctx\` API + invariants and is available whenever you open this
694
- * folder in zidane (or run \`zidane\` from inside it).
695
- */
696
- export default defineExtension({
697
- name: '${name}',
698
- setup(ctx) {
699
- // e.g. ctx.registerTool('${name}_hello', {
700
- // spec: { name: '${name}_hello', description: 'say hi', inputSchema: { type: 'object', properties: {} } },
701
- // isConcurrencySafe: true,
702
- // async execute() { return 'hello from ${name}' },
703
- // })
704
- },
705
- })
706
- `;
707
- }
708
- /**
709
- * Locate the shipped `docs/` directory (`docs/EXTENSIONS.md` + siblings).
710
- *
711
- * The docs ship via `package.json` `files`, so an installed consumer has
712
- * `<root>/node_modules/zidane/docs` and the repo itself has `<repo>/docs`.
713
- * Returns the first existing candidate, or `null` (the skill then falls back to
714
- * the literal `node_modules/zidane/docs` hint, which the model's file tools can
715
- * still attempt from cwd).
716
- */
717
- function resolveExtensionDocsDir(cwd = process.cwd()) {
718
- const candidates = [];
719
- try {
720
- const req = createRequire(import.meta.url);
721
- candidates.push(join(dirname(req.resolve("zidane/package.json")), "docs"));
722
- } catch {}
723
- try {
724
- let dir = dirname(fileURLToPath(import.meta.url));
725
- for (let i = 0; i < 6; i++) {
726
- if (existsSync(join(dir, "docs", "EXTENSIONS.md"))) {
727
- candidates.push(join(dir, "docs"));
728
- break;
729
- }
730
- dir = dirname(dir);
731
- }
732
- } catch {}
733
- candidates.push(join(cwd, "node_modules", "zidane", "docs"));
734
- for (const candidate of candidates) if (existsSync(join(candidate, "EXTENSIONS.md"))) return candidate;
735
- return null;
736
- }
737
- /** Entry-file probe order for an extension dir (mirrors the loader's discovery). */
738
- const EXTENSION_ENTRY_FILES = [
739
- "index.ts",
740
- "index.tsx",
741
- "index.mjs",
742
- "index.js"
743
- ];
744
- /**
745
- * If `cwd` sits inside a zidane extension, return that extension's root dir,
746
- * else `null`. Mirrors the discovery layout
747
- * `<scope>/.{agents,zidane}/extensions/<name>/` — the root is the `<name>` dir
748
- * (parent `extensions`, grandparent `.agents` / `.zidane`) holding an entry
749
- * file. Walks up from `cwd`, so the nearest enclosing extension wins. Lets the
750
- * hosts surface the authoring skill for a plain `zidane` launched from an
751
- * extension folder, not just sessions opened through the edit/create flow.
752
- */
753
- function extensionDirForCwd(cwd = process.cwd()) {
754
- let dir = resolve(cwd);
755
- for (let i = 0; i < 64; i++) {
756
- const parent = dirname(dir);
757
- if (basename(parent) === "extensions" && (basename(dirname(parent)) === ".agents" || basename(dirname(parent)) === ".zidane") && EXTENSION_ENTRY_FILES.some((f) => existsSync(join(dir, f)))) return dir;
758
- if (parent === dir) break;
759
- dir = parent;
760
- }
761
- return null;
762
- }
763
- /**
764
- * The authoring reference embedded into the skill body. Kept INLINE (not a
765
- * filesystem path) on purpose: a `bun build --compile` TUI binary has no
766
- * resolvable `node_modules/zidane/docs`, no real `import.meta.url`, and the
767
- * edited extension's own cwd has no `node_modules` — so a path reference dead-
768
- * ends there. The model gets the API verbatim on activation regardless of host.
769
- *
770
- * Mirrors `ExtensionContext` (src/extensions/types.ts) — keep in sync when the
771
- * `ctx.*` surface changes.
772
- */
773
- const EXTENSION_AUTHORING_CHEATSHEET = `## defineExtension
774
-
775
- A zidane extension is a module at \`<scope>/.{agents,zidane}/extensions/<name>/index.{ts,tsx,mjs,js}\`
776
- that default-exports \`defineExtension({ ... })\`. It runs in-process in the host (TUI / GUI / SDK).
777
-
778
- \`\`\`ts
779
- import { defineExtension } from 'zidane'
780
-
781
- export default defineExtension({
782
- name: 'my-ext', // MUST equal the folder name
783
- apiVersion: 1, // optional; omitted means v1
784
- version: '0.1.0', // optional — shown in Settings → Extensions
785
- displayName: 'My Ext', // optional UI label
786
- description: 'what it does',
787
- capabilities: ['tools'], // optional descriptive manifest labels
788
- permissions: [], // optional descriptive labels; not a sandbox
789
- setup(ctx) { /* register everything here; may be async */ },
790
- teardown() {}, // optional, reserved (no hot-reload yet)
791
- })
792
- \`\`\`
793
-
794
- Zero-import form — required INSIDE compiled binaries, which can't \`import 'zidane'\` at runtime:
795
- \`\`\`ts
796
- import type { ExtensionContext } from 'zidane' // type-only: erased at runtime
797
- export default {
798
- name: 'my-ext',
799
- setup(ctx: ExtensionContext) { /* ... */ },
800
- }
801
- \`\`\`
802
-
803
- ## ctx surface (call everything inside setup)
804
-
805
- Identity / utilities:
806
- - ctx.name / ctx.version / ctx.dir / ctx.scope ('project' | 'user' | 'inline' | 'builtin')
807
- - ctx.logger — Logger namespaced \`extension:<name>\`
808
- - ctx.config — read THIS extension's config, default-first: \`ctx.config.get(key)\`
809
- - ctx.paths — cwd/projectRoot/dataDir/cacheDir/configDir/stateDir
810
- - ctx.storage.path(scope, ...segments) — extension-scoped storage path
811
- - ctx.session — JSON-only per-session state: get / set / delete
812
-
813
- Renderer-agnostic registration:
814
- - ctx.registerTool(name, toolDef)
815
- - ctx.registerHook(event, handler) — an AgentHooks event; fires on the PARENT agent (use child:* for subagents)
816
- - ctx.registerMcpServer(config)
817
- - ctx.registerSkill(skillConfig) — a defineSkill() shape
818
- - ctx.registerCompletionProvider(provider) — single-char '/' '@' '!' trigger
819
- - ctx.tui.notify(text, { tone? }) — one-shot transcript line (info/warn/error); buffered pre-mount
820
- - ctx.tui.setStatus(text | null, { loader?, timeout? }) — single dim status line (transcript-tail slot); loader glyph, auto-clear ms
821
- - ctx.tui.setBanner(lines | null, { timeout? }) — short block above the prompt (stacked with the todo indicator); auto-clear ms
822
- - ctx.submitPrompt(text, { delivery? }) — submit as the user: 'auto' (run-or-queue), 'steer', 'followUp'; false when detached
823
- - ctx.registerToolPolicy({ tools?, decide }) — gate tool calls: allow / { block } / { patch } (patches re-validated by the loop)
824
- - ctx.registerToolResultTransform(fn) — middleware over finished tool results (chained)
825
- - ctx.registerContextTransform(fn) — rewrite wire messages before each provider call
826
- - ctx.registerPromptTransform(fn) — transform or consume submitted prompts (after / commands, before skills)
827
- - ctx.runtime / ctx.sessions — late-bound host controls: model()/thinking()/setThinking(), sessions list/switch/create
828
- - ctx.appendNote(blocks) — durable display-only transcript note (command-output block vocabulary)
829
- - ctx.workspace.exec/readFile/writeFile/listFiles/fileSize — shell + files through the SESSION'S execution context (sandbox-correct; host child_process silently targets the wrong filesystem under docker/e2b). Detached ⇒ rejects; guard with \`await ctx.workspace.available()\`.
830
- - ctx.tui.registerToolRenderer({ tools?, render }) — custom view for tool-result rows; return null to fall through to the default. View-layer only: never persisted, error-bounded per row, TUI-scoped.
831
- - ctx.tui.registerRenderer(id, render) + emit/appendNote \`custom: { renderer, data }\` blocks — custom components in the transcript. \`data\` must be JSON-safe (it persists); the block's \`text\` is the MANDATORY markdown fallback (disabled extension, headless host, GUI, renderer throw). appendNote auto-prefixes bare ids; command emit needs \`<ext>/<id>\`.
832
- - Renderer components: import \`react\` / \`@opentui/react\` BARE (never as your own dependency) — the host maps them to its live instances at load time, so hooks work. Async data: render() stays sync; return a component that fetches with useState/useEffect.
833
- - Renderer async caching: \`useSessionState(id, initial)\` (per-row, session-persisted — rehydrates on reload) + \`useRowVisible()\` (latched viewport gate) from \`zidane/tui\` — fetch once, only when scrolled in.
834
- - ctx.registerCommand(command) — a '/<name>' workflow (handler or steps[]); step ctx: emit (local output),
835
- runAgent (interactive sub-run), generateData (silent zod/JSON-Schema JSON),
836
- session? (read-only turns/runs view), interaction? (confirm / askUser forms /
837
- presentPlan approval — both optional; guard for bare hosts)
838
- - ctx.registerTheme(theme)
839
- - ctx.registerAgent(profile) — extra agent profile in the picker
840
- - ctx.registerSubagent(def) — spawnable subagent (the spawn tool's subagent_type)
841
- - ctx.registerSubagentOverride(name, fn) — edit/delete an existing subagent
842
- - ctx.registerProvider(descriptor)
843
- - ctx.registerSystemPromptFragment(text)
844
- - ctx.registerContextBreakdownSection(fn) — render extension-owned rows in the context panel
845
- - ctx.registerContextPanelSection(section) — richer context panel section with rows/load
846
- - ctx.registerToolResultMetadata(registration) — project namespaced tool-result metadata into context
847
- - ctx.registerRunTransform(fn) — sync rewrite of agent.run options
848
- - ctx.registerBehaviorTransform(fn) — sync rewrite of resolved behavior
849
- - ctx.registerProviderMiddleware(fn) — wrap provider instances
850
- - ctx.registerToolCatalogTransform(fn) — shape/hide/rename tools before disclosure/execution
851
- - ctx.registerMcpConfigTransform(fn) — rewrite MCP server configs before connect
852
- - ctx.registerSkillPolicy(policy) — auto-activate skills by run context
853
- - ctx.registerConfigCategory(category)
854
- - ctx.registerConfigItem([categoryId,] item) — typed setting; supports scope/onChange metadata
855
-
856
- TUI-only (ctx.tui.* — silently ignored on non-TUI hosts):
857
- - ctx.tui.registerKeybinding(binding)
858
- - ctx.tui.registerFooterHint(hint)
859
- - ctx.tui.registerModal(modal) — keep UI lazy: \`node: () => import('./panel')\`
860
-
861
- GUI-only:
862
- - ctx.gui.registerPanel(panel) — collected, not rendered yet
863
-
864
- Completion providers may also implement submit hooks:
865
- - resolveReferences(refs, ctx, signal)
866
- - onSubmit({ text, cursor, references }, signal)
867
- Both TUI and GUI call these before dispatching a submitted prompt.
868
-
869
- ## ToolDef shape
870
- \`\`\`ts
871
- ctx.registerTool('my_tool', {
872
- spec: { name: 'my_tool', description: '...', inputSchema: { type: 'object', properties: {} } },
873
- isConcurrencySafe: true, // default false (barrier/write); true = read-only, fans out in parallel
874
- async execute(args) { return 'result' },
875
- })
876
- \`\`\`
877
-
878
- ## Invariants
879
- - The folder name MUST equal \`name\`, or the loader rejects the extension.
880
- - Optional metadata lives in \`extension.json\` or \`package.json#zidane\`; unsupported \`apiVersion\` is rejected.
881
- - Export as \`default\` (or a named \`extension\` export).
882
- - Register ONLY inside \`setup\` — calls after it resolves are dropped (logger.warn).
883
- - A throw in \`setup\` is caught and shown on the extension's Settings row; the rest of boot continues.
884
- - Discovery order, first per name wins: project \`.agents\` → project \`.zidane\` → \`~/.agents\` → \`~/.zidane\`.
885
- - \`/reload\` is a TRUE hot-reload: re-discover + re-run setup, and each extension's module graph is re-imported fresh — code edits (deep imports included) apply live. Module-level state resets; clean up external resources in \`teardown\`.
886
-
887
- ## Distribution
888
- - Users install via Settings → Extensions → \`ctrl+g\` (source input + scope picker) — GitHub (\`owner/repo[#ref][:sub/dir]\`, tree URLs) or npm (\`pkg[@version]\`, exact versions / dist-tags).
889
- - Update / remove: Settings → Extensions, \`ctrl+u\` / \`ctrl+x\` on the focused row (update replays the recorded \`.install.json\` provenance in place, skipping when the recorded commit/version still matches the remote).
890
- - Shape your repo/package as a root \`index.ts\` (single extension) or \`extensions/<name>/index.*\` dirs (collection).
891
- - Reference packages to copy: \`extensions/git-flow\` in the zidane repo (zero-dep \`/commit\` command) and \`extensions/headroom\` (hooks + tool + config).
892
- - Declare runtime deps in \`package.json#dependencies\` — installed with bun/npm/… WITHOUT lifecycle scripts; don't rely on postinstall.
893
- - The installed folder is named from your exported \`definition.name\` — pick it to be folder-safe ([A-Za-z0-9_.-]).`;
894
- /** Preset preamble for "edit / create extension" sessions. */
895
- const EXTENSION_EDIT_PRESET = "You are authoring / editing a zidane extension. Authoritative API reference:";
896
- /** Preset preamble for "edit skill" sessions — same spirit, skill-flavored. */
897
- function skillEditPreset(marker) {
898
- return `We are going to work on ${marker.name}, in ${marker.dir} directory, next messages will be requests at modifying and improving the skill or understanding how it works better.`;
899
- }
900
- /**
901
- * The inline `zidane-extension` skill. Carries the authoring reference IN its
902
- * body ({@link EXTENSION_AUTHORING_CHEATSHEET}) so it works in every host —
903
- * incl. compiled binaries where the on-disk docs aren't resolvable. The shipped
904
- * `EXTENSIONS.md` (prose long-form) is appended as a "see also" only when found
905
- * on disk. `source: 'inline'` (the `defineSkill` default) survives the
906
- * project-trust gate.
907
- */
908
- function buildZidaneExtensionSkill(opts = {}) {
909
- const docsDir = resolveExtensionDocsDir(opts.cwd);
910
- const seeAlso = docsDir ? `\n\n---\nFull prose reference on disk: ${join(docsDir, "EXTENSIONS.md")}\nSibling docs cover related surfaces (ARCHITECTURE.md, CHAT.md, TUI.md, SKILL.md, HEADLESS.md, …).` : "\n\n---\nFuller prose reference, when present: node_modules/zidane/docs/EXTENSIONS.md (often absent in compiled binaries — the API above is authoritative).";
911
- return defineSkill({
912
- name: ZIDANE_EXTENSION_SKILL_NAME,
913
- description: "Authoring or editing a zidane extension (a module calling defineExtension, under .zidane/extensions/** or .agents/extensions/**). Carries the extension authoring reference.",
914
- instructions: `${EXTENSION_EDIT_PRESET}\n\n${EXTENSION_AUTHORING_CHEATSHEET}${seeAlso}`
915
- });
916
- }
917
- /**
918
- * Inject the `zidane-extension` skill into an already-merged {@link SkillsConfig}.
919
- *
920
- * Call this on the FINAL merged skills object (after folding extension / preset
921
- * skills): `composePresets` is last-wins on `catalog`, so injecting earlier
922
- * would be silently dropped whenever an extension also contributes skills.
923
- *
924
- * Adds the skill to the catalog and, when an `enabled` allowlist is in force,
925
- * force-includes the name so the allowlist filter can't hide it (mirrors how
926
- * extension-contributed skill names are force-included). When skills are fully
927
- * disabled (`enabled === false`), the edit session still gets just this skill.
928
- */
929
- function withZidaneExtensionSkill(skills, opts = {}) {
930
- return injectInlineSkill(skills, buildZidaneExtensionSkill(opts));
931
- }
932
- /**
933
- * Compact skill-authoring reference embedded into the skill-edit skill body.
934
- * Inline for the same reason as {@link EXTENSION_AUTHORING_CHEATSHEET}: works
935
- * in compiled binaries where on-disk docs don't resolve.
936
- */
937
- const SKILL_AUTHORING_CHEATSHEET = `## SKILL.md anatomy
938
-
939
- A skill is a directory holding a \`SKILL.md\` (YAML frontmatter + markdown body)
940
- per the Agent Skills standard (agentskills.io/specification):
941
-
942
- \`\`\`md
943
- ---
944
- name: my-skill # 1-64 chars, lowercase alphanumeric + hyphens; SHOULD match the directory name
945
- description: what it does AND when to use it (drives activation — 1-1024 chars)
946
- license: MIT # optional
947
- compatibility: … # optional environment requirements
948
- allowed-tools: # optional — restricts the agent to these tools while active
949
- - read_file
950
- metadata: # optional flat string map; zidane-specific keys use the \`zidane.\` prefix
951
- some-key: value
952
- ---
953
- The body is the skill's instructions — injected into context when the skill
954
- is activated. Keep it token-lean: move depth into references/.
955
- \`\`\`
956
-
957
- ## Bundled resources (all optional, discovered automatically)
958
- - \`references/\` — docs loaded on demand via \`skills_read\`
959
- - \`scripts/\` — executables run via \`skills_run_script\` (honor shebangs)
960
- - \`assets/\` — templates / static files
961
-
962
- ## Guidance
963
- - The description is the activation trigger — write it for the ROUTER ("use when …"), the body for the ACTIVATED agent.
964
- - Prefer small bodies + lazy references over one giant SKILL.md.
965
- - Shell interpolation (exclamation mark + backtick-quoted command) in the body runs at activation — use sparingly; hosts may gate or disable it.
966
- - Validate names: mismatched frontmatter name vs directory loads with a warning diagnostic.`;
967
- /**
968
- * The inline skill auto-activated in "edit skill" sessions. Body = the
969
- * session preset (which skill, which directory, what the next messages will
970
- * be about) + a compact SKILL.md authoring reference — the skill-editing
971
- * counterpart of {@link buildZidaneExtensionSkill}.
972
- */
973
- function buildZidaneSkillEditSkill(marker, opts = {}) {
974
- const docsDir = resolveExtensionDocsDir(opts.cwd);
975
- const seeAlso = docsDir && existsSync(join(docsDir, "SKILL.md")) ? `\n\n---\nFull prose reference on disk: ${join(docsDir, "SKILL.md")}` : "";
976
- return defineSkill({
977
- name: ZIDANE_SKILL_EDIT_SKILL_NAME,
978
- description: `Editing or improving the "${marker.name}" agent skill (its SKILL.md, references, scripts, and assets). Carries the skill-authoring reference for this edit session.`,
979
- instructions: `${skillEditPreset(marker)}\n\n${SKILL_AUTHORING_CHEATSHEET}${seeAlso}`
980
- });
981
- }
982
- /**
983
- * Inject the skill-edit preset skill into an already-merged {@link SkillsConfig}.
984
- * Same contract as {@link withZidaneExtensionSkill} — call on the FINAL merged
985
- * skills object.
986
- */
987
- function withZidaneSkillEditSkill(skills, marker, opts = {}) {
988
- return injectInlineSkill(skills, buildZidaneSkillEditSkill(marker, opts));
989
- }
990
- /**
991
- * Shared injector: add `skill` to the catalog and, when an `enabled`
992
- * allowlist is in force, force-include its name so the filter can't hide it
993
- * (mirrors how extension-contributed skill names are force-included). When
994
- * skills are fully disabled (`enabled === false`), the edit session still
995
- * gets just this skill.
996
- */
997
- function injectInlineSkill(skills, skill) {
998
- const catalog = [...skills.catalog ?? [], skill];
999
- const enabled = skills.enabled;
1000
- const nextEnabled = enabled === void 0 ? void 0 : Array.isArray(enabled) ? enabled.includes(skill.name) ? enabled : [...enabled, skill.name] : [skill.name];
1001
- return {
1002
- ...skills,
1003
- catalog,
1004
- ...nextEnabled !== void 0 ? { enabled: nextEnabled } : {}
1005
- };
1006
- }
1007
644
  //#endregion
1008
645
  //#region src/mcp/oauth-callback.ts
1009
646
  const DEFAULT_PATH = "/callback";
@@ -1148,7 +785,7 @@ async function startOAuthCallback(opts = {}) {
1148
785
  }
1149
786
  //#endregion
1150
787
  //#region src/mcp/login.ts
1151
- const DEFAULT_LOGIN_TIMEOUT_MS = 5 * 6e4;
788
+ const DEFAULT_LOGIN_TIMEOUT_MS = 3e5;
1152
789
  const DEFAULT_CONNECT_TIMEOUT_MS = 3e4;
1153
790
  /**
1154
791
  * Run the full interactive OAuth flow for `config`. Only supports `sse` and
@@ -1165,13 +802,13 @@ const DEFAULT_CONNECT_TIMEOUT_MS = 3e4;
1165
802
  * failure.
1166
803
  */
1167
804
  async function loginMcpServer(config, options) {
1168
- if (config.transport !== "sse" && config.transport !== "streamable-http") throw new Error(`MCP OAuth: cannot login for transport "${config.transport}" — only sse / streamable-http are supported`);
805
+ if (config.transport !== "sse" && config.transport !== "streamable-http") throw new Error(`MCP OAuth: can't sign in over "${config.transport}". Only sse and streamable-http support it.`);
1169
806
  if (!config.url) throw new Error(`MCP OAuth: server "${config.name}" is missing a url`);
1170
807
  const hooks = options.hooks;
1171
808
  let settled = false;
1172
809
  let callback;
1173
810
  try {
1174
- callback = await startOAuthCallback({
811
+ callback = options.callback ?? await startOAuthCallback({
1175
812
  signal: options.signal,
1176
813
  path: options.callbackPath,
1177
814
  ...options.renderCallbackPage ? { renderPage: options.renderCallbackPage } : {},
@@ -1184,6 +821,7 @@ async function loginMcpServer(config, options) {
1184
821
  redirectUri: handle.redirectUri,
1185
822
  clientName: options.clientName,
1186
823
  scope: options.scope,
824
+ ...options.state !== void 0 ? { state: options.state } : {},
1187
825
  onAuthorizationUrl: async (url) => {
1188
826
  if (settled || options.signal?.aborted) return;
1189
827
  await hooks?.callHook("mcp:auth:url", {
@@ -1201,7 +839,7 @@ async function loginMcpServer(config, options) {
1201
839
  let needsAuth = false;
1202
840
  const connectTimeoutMs = options.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS;
1203
841
  for (let attempt = 0;; attempt++) try {
1204
- await raceAbort(client.connect(transport), options.signal, connectTimeoutMs, `MCP OAuth: "${config.name}" did not respond within ${connectTimeoutMs}ms — the server may be unreachable`);
842
+ await raceAbort(client.connect(transport), options.signal, connectTimeoutMs, `MCP OAuth: "${config.name}" did not respond within ${connectTimeoutMs}ms. The server may be unreachable.`);
1205
843
  break;
1206
844
  } catch (err) {
1207
845
  if (isUnauthorizedError(err)) {
@@ -1325,10 +963,7 @@ async function raceLoginCallback(handle, timeoutMs, signal) {
1325
963
  }
1326
964
  }
1327
965
  //#endregion
1328
- //#region src/metrics.ts
1329
- function prefixed$1(prefix, name) {
1330
- return prefix ? `${prefix}${name}` : name;
1331
- }
966
+ //#region src/metrics-hooks.ts
1332
967
  /**
1333
968
  * Drop `undefined` entries before handing attributes to a metrics
1334
969
  * backend. OTel's `@opentelemetry/api` rejects `undefined` attribute
@@ -1345,6 +980,215 @@ function mergeAttrs(base, extra) {
1345
980
  for (const [k, v] of Object.entries(extra)) if (v !== void 0) out[k] = v;
1346
981
  return out;
1347
982
  }
983
+ /** Build the per-install state: fresh start-time maps + guarded emitters. */
984
+ function createMetricsInstallState(base, onError) {
985
+ const turnStart = /* @__PURE__ */ new Map();
986
+ const toolStart = /* @__PURE__ */ new Map();
987
+ const mcpStart = /* @__PURE__ */ new Map();
988
+ const record = (instrument, value, attrs, kind) => {
989
+ if (!instrument) return;
990
+ try {
991
+ instrument.record(value, mergeAttrs(base, attrs));
992
+ } catch (err) {
993
+ try {
994
+ onError(kind, err);
995
+ } catch {}
996
+ }
997
+ };
998
+ const add = (instrument, value, attrs, kind) => {
999
+ if (!instrument) return;
1000
+ try {
1001
+ instrument.add(value, mergeAttrs(base, attrs));
1002
+ } catch (err) {
1003
+ try {
1004
+ onError(kind, err);
1005
+ } catch {}
1006
+ }
1007
+ };
1008
+ return {
1009
+ turnStart,
1010
+ toolStart,
1011
+ mcpStart,
1012
+ record,
1013
+ add
1014
+ };
1015
+ }
1016
+ /** Agent lifecycle + turn / stream metrics. */
1017
+ function installMetricsRunHooks(hooks, unregisters, m, state) {
1018
+ const { turnDuration, tokenUsage, ttft, runsStarted, runsCompleted, aborts, streamErrors, costMeter, runsActive } = m;
1019
+ const { turnStart, toolStart, mcpStart, record, add } = state;
1020
+ unregisters.push(hooks.hook("agent:start", (ctx) => {
1021
+ const attrs = {
1022
+ "gen_ai.agent.depth": ctx.depth,
1023
+ ...ctx.agentName ? { "gen_ai.agent.name": ctx.agentName } : {}
1024
+ };
1025
+ add(runsStarted, 1, attrs, "runs");
1026
+ add(runsActive, 1, attrs, "runs.active");
1027
+ }));
1028
+ unregisters.push(hooks.hook("agent:done", () => {
1029
+ add(runsCompleted, 1, {}, "runs.completed");
1030
+ add(runsActive, -1, {}, "runs.active");
1031
+ turnStart.clear();
1032
+ toolStart.clear();
1033
+ mcpStart.clear();
1034
+ }));
1035
+ unregisters.push(hooks.hook("agent:abort", () => {
1036
+ add(aborts, 1, {}, "aborts");
1037
+ }));
1038
+ unregisters.push(hooks.hook("turn:before", (ctx) => {
1039
+ turnStart.set(ctx.turnId, Date.now());
1040
+ }));
1041
+ unregisters.push(hooks.hook("turn:after", (ctx) => {
1042
+ const started = turnStart.get(ctx.turnId);
1043
+ turnStart.delete(ctx.turnId);
1044
+ const tagsBase = {
1045
+ "gen_ai.operation.name": "chat",
1046
+ ...ctx.usage.modelId ? { "gen_ai.response.model": ctx.usage.modelId } : {},
1047
+ ...ctx.usage.finishReason ? { "gen_ai.response.finish_reason": ctx.usage.finishReason } : {}
1048
+ };
1049
+ if (typeof started === "number") record(turnDuration, Date.now() - started, tagsBase, "turn.duration");
1050
+ if (typeof ctx.usage.timeToFirstTokenMs === "number") record(ttft, ctx.usage.timeToFirstTokenMs, tagsBase, "ttft");
1051
+ record(tokenUsage, ctx.usage.input, {
1052
+ ...tagsBase,
1053
+ "gen_ai.token.type": "input"
1054
+ }, "token.input");
1055
+ record(tokenUsage, ctx.usage.output, {
1056
+ ...tagsBase,
1057
+ "gen_ai.token.type": "output"
1058
+ }, "token.output");
1059
+ if (typeof ctx.usage.cacheRead === "number" && ctx.usage.cacheRead > 0) record(tokenUsage, ctx.usage.cacheRead, {
1060
+ ...tagsBase,
1061
+ "gen_ai.token.type": "cache_read"
1062
+ }, "token.cache_read");
1063
+ if (typeof ctx.usage.cacheCreation === "number" && ctx.usage.cacheCreation > 0) record(tokenUsage, ctx.usage.cacheCreation, {
1064
+ ...tagsBase,
1065
+ "gen_ai.token.type": "cache_creation"
1066
+ }, "token.cache_creation");
1067
+ if (typeof ctx.usage.cost === "number" && ctx.usage.cost > 0) add(costMeter, ctx.usage.cost, tagsBase, "cost");
1068
+ }));
1069
+ unregisters.push(hooks.hook("stream:error", (ctx) => {
1070
+ add(streamErrors, 1, {
1071
+ "http.response.status_code": ctx.statusCode,
1072
+ "error.type": ctx.err instanceof Error ? ctx.err.name : "unknown"
1073
+ }, "stream.error");
1074
+ }));
1075
+ }
1076
+ /** Native tool, validation, budget, pairing and OAuth metrics. */
1077
+ function installMetricsToolHooks(hooks, unregisters, m, state) {
1078
+ const { toolDuration, toolOutput, toolCalls, toolErrors, validationRejects, validationCoercions, gateBlocks, budgetExceeded, toolBudgetExceeded, pairingRepairs, oauthRefreshes } = m;
1079
+ const { toolStart, record, add } = state;
1080
+ unregisters.push(hooks.hook("tool:before", (ctx) => {
1081
+ toolStart.set(ctx.callId, Date.now());
1082
+ }));
1083
+ unregisters.push(hooks.hook("tool:after", (ctx) => {
1084
+ const started = toolStart.get(ctx.callId);
1085
+ toolStart.delete(ctx.callId);
1086
+ const tags = { "gen_ai.tool.name": ctx.name };
1087
+ if (typeof started === "number") record(toolDuration, Date.now() - started, tags, "tool.duration");
1088
+ record(toolOutput, ctx.outputBytes, tags, "tool.output_bytes");
1089
+ }));
1090
+ unregisters.push(hooks.hook("tool:error", (ctx) => {
1091
+ add(toolErrors, 1, {
1092
+ "gen_ai.tool.name": ctx.name,
1093
+ "error.type": ctx.error.name
1094
+ }, "tool.errors");
1095
+ }));
1096
+ unregisters.push(hooks.hook("tool:cancelled", (ctx) => {
1097
+ toolStart.delete(ctx.callId);
1098
+ }));
1099
+ unregisters.push(hooks.hook("tool:dispatched", (ctx) => {
1100
+ add(toolCalls, 1, {
1101
+ "gen_ai.tool.name": ctx.name,
1102
+ "outcome": ctx.outcome
1103
+ }, "tool.calls");
1104
+ if (ctx.outcome === "gate-block") add(gateBlocks, 1, {
1105
+ "gen_ai.tool.name": ctx.name,
1106
+ ...ctx.reason ? { reason: ctx.reason } : {}
1107
+ }, "gate.blocks");
1108
+ if (ctx.outcome === "unknown") toolStart.delete(ctx.callId);
1109
+ }));
1110
+ unregisters.push(hooks.hook("validation:reject", (ctx) => {
1111
+ add(validationRejects, 1, { "gen_ai.tool.name": ctx.name }, "validation.rejects");
1112
+ }));
1113
+ unregisters.push(hooks.hook("validation:coerce", (ctx) => {
1114
+ add(validationCoercions, 1, {
1115
+ "gen_ai.tool.name": ctx.name,
1116
+ "coercions": ctx.coercions.length
1117
+ }, "validation.coercions");
1118
+ }));
1119
+ unregisters.push(hooks.hook("budget:exceeded", (ctx) => {
1120
+ add(budgetExceeded, 1, {
1121
+ bytes: ctx.bytes,
1122
+ budget: ctx.budget
1123
+ }, "budget.exceeded");
1124
+ }));
1125
+ unregisters.push(hooks.hook("tool-budget:exceeded", (ctx) => {
1126
+ add(toolBudgetExceeded, 1, {
1127
+ "gen_ai.tool.name": ctx.tool,
1128
+ "mode": ctx.mode,
1129
+ "count": ctx.count,
1130
+ "max": ctx.max
1131
+ }, "tool_budget.exceeded");
1132
+ }));
1133
+ unregisters.push(hooks.hook("pairing:repair", (ctx) => {
1134
+ add(pairingRepairs, 1, { mode: ctx.mode }, "pairing.repairs");
1135
+ }));
1136
+ unregisters.push(hooks.hook("oauth:refresh", (ctx) => {
1137
+ add(oauthRefreshes, 1, {
1138
+ provider: ctx.provider,
1139
+ source: ctx.source
1140
+ }, "oauth.refreshes");
1141
+ }));
1142
+ }
1143
+ /** MCP tool / bootstrap / server metrics. */
1144
+ function installMetricsMcpHooks(hooks, unregisters, m, state) {
1145
+ const { mcpToolDuration, mcpBootstrapDuration, mcpToolErrors, mcpErrors, mcpAuthRequired } = m;
1146
+ const { mcpStart, record, add } = state;
1147
+ unregisters.push(hooks.hook("mcp:tool:before", (ctx) => {
1148
+ mcpStart.set(ctx.callId, Date.now());
1149
+ }));
1150
+ unregisters.push(hooks.hook("mcp:tool:after", (ctx) => {
1151
+ const started = mcpStart.get(ctx.callId);
1152
+ mcpStart.delete(ctx.callId);
1153
+ const tags = {
1154
+ "gen_ai.mcp.server": ctx.server,
1155
+ "gen_ai.tool.name": ctx.displayName
1156
+ };
1157
+ if (typeof started === "number") record(mcpToolDuration, Date.now() - started, tags, "mcp.tool.duration");
1158
+ }));
1159
+ unregisters.push(hooks.hook("mcp:tool:error", (ctx) => {
1160
+ mcpStart.delete(ctx.callId);
1161
+ add(mcpToolErrors, 1, {
1162
+ "gen_ai.mcp.server": ctx.server,
1163
+ "gen_ai.tool.name": ctx.displayName,
1164
+ "error.type": ctx.error.name
1165
+ }, "mcp.tool.errors");
1166
+ }));
1167
+ unregisters.push(hooks.hook("mcp:bootstrap:end", (ctx) => {
1168
+ record(mcpBootstrapDuration, ctx.durationMs, {
1169
+ "gen_ai.mcp.server": ctx.name,
1170
+ "ok": ctx.ok
1171
+ }, "mcp.bootstrap.duration");
1172
+ }));
1173
+ unregisters.push(hooks.hook("mcp:error", (ctx) => {
1174
+ add(mcpErrors, 1, {
1175
+ "gen_ai.mcp.server": ctx.name,
1176
+ "error.type": ctx.error.name
1177
+ }, "mcp.errors");
1178
+ }));
1179
+ unregisters.push(hooks.hook("mcp:auth:required", (ctx) => {
1180
+ add(mcpAuthRequired, 1, {
1181
+ "gen_ai.mcp.server": ctx.name,
1182
+ "transport": ctx.transport,
1183
+ "reason": ctx.reason
1184
+ }, "mcp.auth.required");
1185
+ }));
1186
+ }
1187
+ //#endregion
1188
+ //#region src/metrics.ts
1189
+ function prefixed$1(prefix, name) {
1190
+ return prefix ? `${prefix}${name}` : name;
1191
+ }
1348
1192
  /**
1349
1193
  * Build a set of metrics hook handlers that can be installed on an agent.
1350
1194
  *
@@ -1417,186 +1261,39 @@ function createMetricsHooks(options) {
1417
1261
  });
1418
1262
  const runsActive = make.upDown("gen_ai.agent.runs.active", { description: "In-flight agent runs." });
1419
1263
  return { install(hooks) {
1420
- const turnStart = /* @__PURE__ */ new Map();
1421
- const toolStart = /* @__PURE__ */ new Map();
1422
- const mcpStart = /* @__PURE__ */ new Map();
1423
- const unregisters = [];
1424
- const record = (instrument, value, attrs, kind) => {
1425
- if (!instrument) return;
1426
- try {
1427
- instrument.record(value, mergeAttrs(base, attrs));
1428
- } catch (err) {
1429
- try {
1430
- onError(kind, err);
1431
- } catch {}
1432
- }
1433
- };
1434
- const add = (instrument, value, attrs, kind) => {
1435
- if (!instrument) return;
1436
- try {
1437
- instrument.add(value, mergeAttrs(base, attrs));
1438
- } catch (err) {
1439
- try {
1440
- onError(kind, err);
1441
- } catch {}
1442
- }
1264
+ const state = createMetricsInstallState(base, onError);
1265
+ const { turnStart, toolStart, mcpStart } = state;
1266
+ const instruments = {
1267
+ turnDuration,
1268
+ tokenUsage,
1269
+ ttft,
1270
+ toolDuration,
1271
+ toolOutput,
1272
+ mcpToolDuration,
1273
+ mcpBootstrapDuration,
1274
+ runsStarted,
1275
+ runsCompleted,
1276
+ aborts,
1277
+ toolCalls,
1278
+ toolErrors,
1279
+ mcpToolErrors,
1280
+ streamErrors,
1281
+ validationRejects,
1282
+ validationCoercions,
1283
+ gateBlocks,
1284
+ budgetExceeded,
1285
+ toolBudgetExceeded,
1286
+ pairingRepairs,
1287
+ oauthRefreshes,
1288
+ mcpErrors,
1289
+ mcpAuthRequired,
1290
+ costMeter,
1291
+ runsActive
1443
1292
  };
1444
- unregisters.push(hooks.hook("agent:start", (ctx) => {
1445
- const attrs = {
1446
- "gen_ai.agent.depth": ctx.depth,
1447
- ...ctx.agentName ? { "gen_ai.agent.name": ctx.agentName } : {}
1448
- };
1449
- add(runsStarted, 1, attrs, "runs");
1450
- add(runsActive, 1, attrs, "runs.active");
1451
- }));
1452
- unregisters.push(hooks.hook("agent:done", () => {
1453
- add(runsCompleted, 1, {}, "runs.completed");
1454
- add(runsActive, -1, {}, "runs.active");
1455
- turnStart.clear();
1456
- toolStart.clear();
1457
- mcpStart.clear();
1458
- }));
1459
- unregisters.push(hooks.hook("agent:abort", () => {
1460
- add(aborts, 1, {}, "aborts");
1461
- }));
1462
- unregisters.push(hooks.hook("turn:before", (ctx) => {
1463
- turnStart.set(ctx.turnId, Date.now());
1464
- }));
1465
- unregisters.push(hooks.hook("turn:after", (ctx) => {
1466
- const started = turnStart.get(ctx.turnId);
1467
- turnStart.delete(ctx.turnId);
1468
- const tagsBase = {
1469
- "gen_ai.operation.name": "chat",
1470
- ...ctx.usage.modelId ? { "gen_ai.response.model": ctx.usage.modelId } : {},
1471
- ...ctx.usage.finishReason ? { "gen_ai.response.finish_reason": ctx.usage.finishReason } : {}
1472
- };
1473
- if (typeof started === "number") record(turnDuration, Date.now() - started, tagsBase, "turn.duration");
1474
- if (typeof ctx.usage.timeToFirstTokenMs === "number") record(ttft, ctx.usage.timeToFirstTokenMs, tagsBase, "ttft");
1475
- record(tokenUsage, ctx.usage.input, {
1476
- ...tagsBase,
1477
- "gen_ai.token.type": "input"
1478
- }, "token.input");
1479
- record(tokenUsage, ctx.usage.output, {
1480
- ...tagsBase,
1481
- "gen_ai.token.type": "output"
1482
- }, "token.output");
1483
- if (typeof ctx.usage.cacheRead === "number" && ctx.usage.cacheRead > 0) record(tokenUsage, ctx.usage.cacheRead, {
1484
- ...tagsBase,
1485
- "gen_ai.token.type": "cache_read"
1486
- }, "token.cache_read");
1487
- if (typeof ctx.usage.cacheCreation === "number" && ctx.usage.cacheCreation > 0) record(tokenUsage, ctx.usage.cacheCreation, {
1488
- ...tagsBase,
1489
- "gen_ai.token.type": "cache_creation"
1490
- }, "token.cache_creation");
1491
- if (typeof ctx.usage.cost === "number" && ctx.usage.cost > 0) add(costMeter, ctx.usage.cost, tagsBase, "cost");
1492
- }));
1493
- unregisters.push(hooks.hook("stream:error", (ctx) => {
1494
- add(streamErrors, 1, {
1495
- "http.response.status_code": ctx.statusCode,
1496
- "error.type": ctx.err instanceof Error ? ctx.err.name : "unknown"
1497
- }, "stream.error");
1498
- }));
1499
- unregisters.push(hooks.hook("tool:before", (ctx) => {
1500
- toolStart.set(ctx.callId, Date.now());
1501
- }));
1502
- unregisters.push(hooks.hook("tool:after", (ctx) => {
1503
- const started = toolStart.get(ctx.callId);
1504
- toolStart.delete(ctx.callId);
1505
- const tags = { "gen_ai.tool.name": ctx.name };
1506
- if (typeof started === "number") record(toolDuration, Date.now() - started, tags, "tool.duration");
1507
- record(toolOutput, ctx.outputBytes, tags, "tool.output_bytes");
1508
- }));
1509
- unregisters.push(hooks.hook("tool:error", (ctx) => {
1510
- add(toolErrors, 1, {
1511
- "gen_ai.tool.name": ctx.name,
1512
- "error.type": ctx.error.name
1513
- }, "tool.errors");
1514
- }));
1515
- unregisters.push(hooks.hook("tool:cancelled", (ctx) => {
1516
- toolStart.delete(ctx.callId);
1517
- }));
1518
- unregisters.push(hooks.hook("tool:dispatched", (ctx) => {
1519
- add(toolCalls, 1, {
1520
- "gen_ai.tool.name": ctx.name,
1521
- "outcome": ctx.outcome
1522
- }, "tool.calls");
1523
- if (ctx.outcome === "gate-block") add(gateBlocks, 1, {
1524
- "gen_ai.tool.name": ctx.name,
1525
- ...ctx.reason ? { reason: ctx.reason } : {}
1526
- }, "gate.blocks");
1527
- if (ctx.outcome === "unknown") toolStart.delete(ctx.callId);
1528
- }));
1529
- unregisters.push(hooks.hook("validation:reject", (ctx) => {
1530
- add(validationRejects, 1, { "gen_ai.tool.name": ctx.name }, "validation.rejects");
1531
- }));
1532
- unregisters.push(hooks.hook("validation:coerce", (ctx) => {
1533
- add(validationCoercions, 1, {
1534
- "gen_ai.tool.name": ctx.name,
1535
- "coercions": ctx.coercions.length
1536
- }, "validation.coercions");
1537
- }));
1538
- unregisters.push(hooks.hook("budget:exceeded", (ctx) => {
1539
- add(budgetExceeded, 1, {
1540
- bytes: ctx.bytes,
1541
- budget: ctx.budget
1542
- }, "budget.exceeded");
1543
- }));
1544
- unregisters.push(hooks.hook("tool-budget:exceeded", (ctx) => {
1545
- add(toolBudgetExceeded, 1, {
1546
- "gen_ai.tool.name": ctx.tool,
1547
- "mode": ctx.mode,
1548
- "count": ctx.count,
1549
- "max": ctx.max
1550
- }, "tool_budget.exceeded");
1551
- }));
1552
- unregisters.push(hooks.hook("pairing:repair", (ctx) => {
1553
- add(pairingRepairs, 1, { mode: ctx.mode }, "pairing.repairs");
1554
- }));
1555
- unregisters.push(hooks.hook("oauth:refresh", (ctx) => {
1556
- add(oauthRefreshes, 1, {
1557
- provider: ctx.provider,
1558
- source: ctx.source
1559
- }, "oauth.refreshes");
1560
- }));
1561
- unregisters.push(hooks.hook("mcp:tool:before", (ctx) => {
1562
- mcpStart.set(ctx.callId, Date.now());
1563
- }));
1564
- unregisters.push(hooks.hook("mcp:tool:after", (ctx) => {
1565
- const started = mcpStart.get(ctx.callId);
1566
- mcpStart.delete(ctx.callId);
1567
- const tags = {
1568
- "gen_ai.mcp.server": ctx.server,
1569
- "gen_ai.tool.name": ctx.displayName
1570
- };
1571
- if (typeof started === "number") record(mcpToolDuration, Date.now() - started, tags, "mcp.tool.duration");
1572
- }));
1573
- unregisters.push(hooks.hook("mcp:tool:error", (ctx) => {
1574
- mcpStart.delete(ctx.callId);
1575
- add(mcpToolErrors, 1, {
1576
- "gen_ai.mcp.server": ctx.server,
1577
- "gen_ai.tool.name": ctx.displayName,
1578
- "error.type": ctx.error.name
1579
- }, "mcp.tool.errors");
1580
- }));
1581
- unregisters.push(hooks.hook("mcp:bootstrap:end", (ctx) => {
1582
- record(mcpBootstrapDuration, ctx.durationMs, {
1583
- "gen_ai.mcp.server": ctx.name,
1584
- "ok": ctx.ok
1585
- }, "mcp.bootstrap.duration");
1586
- }));
1587
- unregisters.push(hooks.hook("mcp:error", (ctx) => {
1588
- add(mcpErrors, 1, {
1589
- "gen_ai.mcp.server": ctx.name,
1590
- "error.type": ctx.error.name
1591
- }, "mcp.errors");
1592
- }));
1593
- unregisters.push(hooks.hook("mcp:auth:required", (ctx) => {
1594
- add(mcpAuthRequired, 1, {
1595
- "gen_ai.mcp.server": ctx.name,
1596
- "transport": ctx.transport,
1597
- "reason": ctx.reason
1598
- }, "mcp.auth.required");
1599
- }));
1293
+ const unregisters = [];
1294
+ installMetricsRunHooks(hooks, unregisters, instruments, state);
1295
+ installMetricsToolHooks(hooks, unregisters, instruments, state);
1296
+ installMetricsMcpHooks(hooks, unregisters, instruments, state);
1600
1297
  let disposed = false;
1601
1298
  return function uninstall() {
1602
1299
  if (disposed) return;
@@ -1693,7 +1390,7 @@ function createMutationValidationHooks(options) {
1693
1390
  };
1694
1391
  }
1695
1392
  //#endregion
1696
- //#region src/tracing.ts
1393
+ //#region src/tracing-attrs.ts
1697
1394
  /**
1698
1395
  * Stable keys we emit unconditionally — present in BOTH Sentry and OTel
1699
1396
  * conventions with identical semantics, so no `conventions` branching is
@@ -1894,6 +1591,572 @@ function buildUsageAttrs(usage, conventions) {
1894
1591
  }
1895
1592
  return out;
1896
1593
  }
1594
+ //#endregion
1595
+ //#region src/tracing-mcp-hooks.ts
1596
+ /** MCP `execute_tool` span. */
1597
+ function installTracingMcpToolHooks(hooks, unregisters, rt) {
1598
+ const { legacy, conventions, wantSentry, captureContent, mcpSpans, safeStartSpan, safeSetAttrs, safeEnd, redact } = rt;
1599
+ unregisters.push(hooks.hook("mcp:tool:before", (ctx) => {
1600
+ const span = safeStartSpan(`execute_tool ${ctx.server}.${ctx.tool}`, {
1601
+ [GEN_AI.operationName]: "execute_tool",
1602
+ [GEN_AI.system]: rt.activeSystem,
1603
+ [GEN_AI.toolName]: ctx.displayName,
1604
+ [GEN_AI.toolType]: "extension",
1605
+ [GEN_AI.toolCallId]: ctx.callId,
1606
+ [GEN_AI.mcpServer]: ctx.server,
1607
+ "sentry.op": "gen_ai.execute_tool",
1608
+ "gen_ai.mcp.tool": ctx.tool,
1609
+ "gen_ai.agent.turn_id": ctx.turnId,
1610
+ "gen_ai.agent.run.id": ctx.runId,
1611
+ ...legacy ? {
1612
+ server: ctx.server,
1613
+ tool: ctx.tool,
1614
+ displayName: ctx.displayName,
1615
+ turnId: ctx.turnId,
1616
+ callId: ctx.callId
1617
+ } : {}
1618
+ });
1619
+ if (span) {
1620
+ mcpSpans.set(ctx.callId, span);
1621
+ if (captureContent) try {
1622
+ const redacted = redact("mcp-tool-input", JSON.stringify(ctx.input), {
1623
+ server: ctx.server,
1624
+ tool: ctx.tool,
1625
+ callId: ctx.callId
1626
+ });
1627
+ const attrs = {};
1628
+ if (wantSentry) attrs[GEN_AI.toolCallArguments] = redacted;
1629
+ if (conventions === "otel" || conventions === "both") attrs[GEN_AI.toolInputDeprecated] = redacted;
1630
+ safeSetAttrs(span, attrs);
1631
+ } catch {}
1632
+ }
1633
+ }));
1634
+ unregisters.push(hooks.hook("mcp:tool:after", (ctx) => {
1635
+ const span = mcpSpans.get(ctx.callId);
1636
+ safeSetAttrs(span, { "gen_ai.tool.output_bytes": ctx.outputBytes });
1637
+ if (captureContent && typeof ctx.result === "string") {
1638
+ const redacted = redact("mcp-tool-result", ctx.result, {
1639
+ server: ctx.server,
1640
+ tool: ctx.tool,
1641
+ callId: ctx.callId
1642
+ });
1643
+ const attrs = {};
1644
+ if (wantSentry) attrs[GEN_AI.toolCallResult] = redacted;
1645
+ if (conventions === "otel" || conventions === "both") attrs[GEN_AI.toolOutputDeprecated] = redacted;
1646
+ safeSetAttrs(span, attrs);
1647
+ }
1648
+ safeEnd(mcpSpans, ctx.callId);
1649
+ }));
1650
+ unregisters.push(hooks.hook("mcp:tool:error", (ctx) => {
1651
+ safeSetAttrs(mcpSpans.get(ctx.callId), {
1652
+ "error.type": ctx.error.name,
1653
+ "error.message": ctx.error.message
1654
+ });
1655
+ safeEnd(mcpSpans, ctx.callId);
1656
+ }));
1657
+ }
1658
+ /** MCP server bootstrap span + server-level events. */
1659
+ function installTracingMcpServerHooks(hooks, unregisters, rt) {
1660
+ const { bootstrapSpans, safeStartSpan, safeSetAttrs, safeEnd, safeAddEvent } = rt;
1661
+ unregisters.push(hooks.hook("mcp:bootstrap:start", (ctx) => {
1662
+ const span = safeStartSpan(`mcp.bootstrap ${ctx.name}`, {
1663
+ [GEN_AI.operationName]: "mcp.bootstrap",
1664
+ [GEN_AI.system]: rt.activeSystem,
1665
+ [GEN_AI.mcpServer]: ctx.name,
1666
+ "gen_ai.mcp.transport": ctx.transport
1667
+ });
1668
+ if (span) bootstrapSpans.set(ctx.name, span);
1669
+ }));
1670
+ unregisters.push(hooks.hook("mcp:bootstrap:end", (ctx) => {
1671
+ const span = bootstrapSpans.get(ctx.name);
1672
+ const ok = ctx.ok;
1673
+ safeSetAttrs(span, {
1674
+ "gen_ai.mcp.bootstrap.duration_ms": ctx.durationMs,
1675
+ "gen_ai.mcp.bootstrap.ok": ok,
1676
+ ...ok ? {
1677
+ [GEN_AI.mcpToolCount]: ctx.toolCount,
1678
+ "gen_ai.mcp.lazy": ctx.lazy,
1679
+ "gen_ai.mcp.cached": ctx.cached
1680
+ } : {
1681
+ "error.type": ctx.error.name,
1682
+ "error.message": ctx.error.message
1683
+ }
1684
+ });
1685
+ safeEnd(bootstrapSpans, ctx.name);
1686
+ }));
1687
+ unregisters.push(hooks.hook("mcp:auth:required", (ctx) => {
1688
+ const span = bootstrapSpans.get(ctx.name);
1689
+ safeAddEvent(span ?? rt.activeRunSpan, "gen_ai.mcp.auth.required", {
1690
+ server: ctx.name,
1691
+ transport: ctx.transport,
1692
+ reason: ctx.reason
1693
+ });
1694
+ }));
1695
+ unregisters.push(hooks.hook("mcp:error", (ctx) => {
1696
+ safeAddEvent(rt.activeRunSpan, "gen_ai.mcp.error", {
1697
+ "server": ctx.name,
1698
+ "error.type": ctx.error.name,
1699
+ "error.message": ctx.error.message
1700
+ });
1701
+ }));
1702
+ }
1703
+ //#endregion
1704
+ //#region src/tracing-run-hooks.ts
1705
+ /** `invoke_agent` root span: `agent:start` / `agent:done` / `agent:abort`. */
1706
+ function installTracingAgentHooks(hooks, unregisters, rt) {
1707
+ const { legacy, conventions, runSpans, turnSpans, toolSpans, mcpSpans, spawnSpans, bootstrapSpans, turnTrack, safeStartSpan, safeSetAttrs, endAll } = rt;
1708
+ unregisters.push(hooks.hook("agent:start", (ctx) => {
1709
+ rt.activeSystem = ctx.providerName;
1710
+ const displayName = ctx.agentName && ctx.agentName.length > 0 ? ctx.agentName : "agent";
1711
+ const span = safeStartSpan(`invoke_agent ${displayName}`, {
1712
+ [GEN_AI.operationName]: "invoke_agent",
1713
+ [GEN_AI.system]: rt.activeSystem,
1714
+ [GEN_AI.agentName]: ctx.agentName,
1715
+ [GEN_AI.agentRunId]: ctx.runId,
1716
+ [GEN_AI.agentParentRunId]: ctx.parentRunId,
1717
+ [GEN_AI.agentDepth]: ctx.depth,
1718
+ "sentry.op": "gen_ai.invoke_agent",
1719
+ ...legacy ? {
1720
+ runId: ctx.runId,
1721
+ parentRunId: ctx.parentRunId,
1722
+ agentName: ctx.agentName,
1723
+ depth: ctx.depth
1724
+ } : {}
1725
+ }, ctx.tracingContext);
1726
+ if (span) {
1727
+ runSpans.set(ctx.runId, span);
1728
+ rt.activeRunSpan = span;
1729
+ }
1730
+ }));
1731
+ unregisters.push(hooks.hook("agent:done", (stats) => {
1732
+ const usageAttrs = buildUsageAttrs({
1733
+ input: stats.totalIn,
1734
+ output: stats.totalOut,
1735
+ cacheRead: stats.totalCacheRead,
1736
+ cacheCreation: stats.totalCacheCreation,
1737
+ cost: stats.cost,
1738
+ timeToFirstTokenMs: stats.timeTillFirstTokenMs
1739
+ }, conventions);
1740
+ for (const [, span] of runSpans) safeSetAttrs(span, {
1741
+ ...usageAttrs,
1742
+ [GEN_AI.turn]: stats.turns,
1743
+ "gen_ai.agent.elapsed_ms": stats.elapsed,
1744
+ ...legacy ? {
1745
+ totalIn: stats.totalIn,
1746
+ totalOut: stats.totalOut,
1747
+ totalCacheRead: stats.totalCacheRead,
1748
+ totalCacheCreation: stats.totalCacheCreation,
1749
+ cost: stats.cost,
1750
+ turns: stats.turns,
1751
+ elapsed: stats.elapsed
1752
+ } : {}
1753
+ });
1754
+ endAll(runSpans);
1755
+ endAll(turnSpans);
1756
+ endAll(toolSpans);
1757
+ endAll(mcpSpans);
1758
+ endAll(spawnSpans);
1759
+ endAll(bootstrapSpans);
1760
+ rt.activeRunSpan = void 0;
1761
+ rt.activeSystem = void 0;
1762
+ turnTrack.clear();
1763
+ }));
1764
+ unregisters.push(hooks.hook("agent:abort", () => {
1765
+ for (const [, span] of runSpans) safeSetAttrs(span, { "gen_ai.agent.status": "aborted" });
1766
+ }));
1767
+ }
1768
+ /** `chat` turn span + stream events. */
1769
+ function installTracingTurnHooks(hooks, unregisters, rt) {
1770
+ const { legacy, conventions, wantSentry, captureContent, turnSpans, turnTrack, safeStartSpan, safeSetAttrs, safeEnd, safeAddEvent, redact } = rt;
1771
+ unregisters.push(hooks.hook("turn:before", (ctx) => {
1772
+ const requestedModel = ctx.options.model;
1773
+ const baseAttrs = {
1774
+ [GEN_AI.operationName]: "chat",
1775
+ [GEN_AI.system]: rt.activeSystem,
1776
+ [GEN_AI.requestModel]: requestedModel,
1777
+ [GEN_AI.turn]: ctx.turn,
1778
+ [GEN_AI.responseStreaming]: true,
1779
+ [GEN_AI.requestMaxTokens]: ctx.options.maxTokens,
1780
+ "sentry.op": "gen_ai.chat",
1781
+ "gen_ai.agent.turn_id": ctx.turnId,
1782
+ ...legacy ? {
1783
+ turnId: ctx.turnId,
1784
+ turn: ctx.turn
1785
+ } : {}
1786
+ };
1787
+ if (captureContent) {
1788
+ const systemText = ctx.options.system;
1789
+ if (systemText) baseAttrs[GEN_AI.systemInstructions] = redact("system", systemText, {
1790
+ turnId: ctx.turnId,
1791
+ turn: ctx.turn
1792
+ });
1793
+ const inputMsgs = stringifyMessages(ctx.options.messages);
1794
+ if (inputMsgs) baseAttrs[GEN_AI.inputMessages] = redact("prompt", inputMsgs, {
1795
+ turnId: ctx.turnId,
1796
+ turn: ctx.turn
1797
+ });
1798
+ const toolDefs = stringifyToolDefs(ctx.options.tools);
1799
+ if (toolDefs) baseAttrs[GEN_AI.toolDefinitions] = toolDefs;
1800
+ }
1801
+ const span = safeStartSpan(`chat${requestedModel ? ` ${requestedModel}` : ""}`, baseAttrs);
1802
+ if (span) {
1803
+ turnSpans.set(ctx.turnId, span);
1804
+ turnTrack.set(ctx.turnId, { startedAt: Date.now() });
1805
+ }
1806
+ }));
1807
+ unregisters.push(hooks.hook("stream:start", (ctx) => {
1808
+ safeAddEvent(turnSpans.get(ctx.turnId), "gen_ai.stream.start", { startedAt: ctx.startedAt });
1809
+ }));
1810
+ unregisters.push(hooks.hook("turn:after", (ctx) => {
1811
+ const span = turnSpans.get(ctx.turnId);
1812
+ const tracked = turnTrack.get(ctx.turnId);
1813
+ turnTrack.delete(ctx.turnId);
1814
+ let tokensPerSecond;
1815
+ if (tracked && ctx.usage.output > 0) {
1816
+ const elapsedMs = Date.now() - tracked.startedAt;
1817
+ if (elapsedMs > 0) tokensPerSecond = ctx.usage.output / elapsedMs * 1e3;
1818
+ }
1819
+ const usageAttrs = buildUsageAttrs(ctx.usage, conventions);
1820
+ const cumInputTokens = wantSentry ? ctx.cumulativeUsage.input + ctx.cumulativeUsage.cacheRead + ctx.cumulativeUsage.cacheCreation : ctx.cumulativeUsage.input;
1821
+ const attrs = {
1822
+ ...usageAttrs,
1823
+ [GEN_AI.responseTokensPerSecond]: tokensPerSecond,
1824
+ "gen_ai.agent.cumulative.input_tokens": cumInputTokens,
1825
+ "gen_ai.agent.cumulative.output_tokens": ctx.cumulativeUsage.output,
1826
+ "gen_ai.agent.cumulative.total_tokens": cumInputTokens + ctx.cumulativeUsage.output,
1827
+ "gen_ai.agent.cumulative.cache_read_input_tokens": ctx.cumulativeUsage.cacheRead,
1828
+ "gen_ai.agent.cumulative.cache_creation_input_tokens": ctx.cumulativeUsage.cacheCreation,
1829
+ "gen_ai.agent.cumulative.cost_usd": ctx.cumulativeUsage.cost,
1830
+ "gen_ai.agent.cumulative.turns": ctx.cumulativeUsage.turns,
1831
+ ...legacy ? {
1832
+ inputTokens: ctx.usage.input,
1833
+ outputTokens: ctx.usage.output,
1834
+ finishReason: ctx.usage.finishReason,
1835
+ modelId: ctx.usage.modelId
1836
+ } : {}
1837
+ };
1838
+ if (captureContent && ctx.message && ctx.message.role !== "system" && ctx.message.role !== "command") {
1839
+ const outputMsgs = stringifyMessages([{
1840
+ role: ctx.message.role,
1841
+ content: ctx.message.content
1842
+ }]);
1843
+ if (outputMsgs) attrs[GEN_AI.outputMessages] = redact("stream-text", outputMsgs, {
1844
+ turnId: ctx.turnId,
1845
+ turn: ctx.turn
1846
+ });
1847
+ }
1848
+ safeSetAttrs(span, attrs);
1849
+ safeEnd(turnSpans, ctx.turnId);
1850
+ }));
1851
+ unregisters.push(hooks.hook("stream:error", (ctx) => {
1852
+ const span = turnSpans.get(ctx.turnId);
1853
+ const message = ctx.err instanceof Error ? ctx.err.message : String(ctx.err);
1854
+ safeSetAttrs(span, {
1855
+ "error.type": ctx.err instanceof Error ? ctx.err.name : "unknown",
1856
+ "error.message": message,
1857
+ "http.response.status_code": ctx.statusCode,
1858
+ "gen_ai.request.id": ctx.requestId
1859
+ });
1860
+ safeAddEvent(span, "gen_ai.stream.error", {
1861
+ "error.type": ctx.err instanceof Error ? ctx.err.name : "unknown",
1862
+ "error.message": message,
1863
+ "http.response.status_code": ctx.statusCode,
1864
+ "gen_ai.request.id": ctx.requestId
1865
+ });
1866
+ }));
1867
+ }
1868
+ //#endregion
1869
+ //#region src/tracing-runtime.ts
1870
+ /** Build a fresh runtime — called once per `install()`. */
1871
+ function createTracingRuntime(options, config) {
1872
+ const { namespace, legacy, conventions, wantSentry, captureContent, onError } = config;
1873
+ function safeStartSpan(name, attrs, parentContext) {
1874
+ try {
1875
+ return options.startSpan(prefixed(namespace, name), compact(attrs), parentContext);
1876
+ } catch (err) {
1877
+ try {
1878
+ onError("startSpan", err);
1879
+ } catch {}
1880
+ return;
1881
+ }
1882
+ }
1883
+ function safeSetAttrs(span, attrs) {
1884
+ if (!span?.setAttributes) return;
1885
+ try {
1886
+ span.setAttributes(compact(attrs));
1887
+ } catch (err) {
1888
+ try {
1889
+ onError("setAttributes", err);
1890
+ } catch {}
1891
+ }
1892
+ }
1893
+ function safeEnd(map, key) {
1894
+ const span = map.get(key);
1895
+ if (!span) return;
1896
+ try {
1897
+ span.end();
1898
+ } catch (err) {
1899
+ try {
1900
+ onError("end", err);
1901
+ } catch {}
1902
+ }
1903
+ map.delete(key);
1904
+ }
1905
+ function endAll(map) {
1906
+ for (const [, span] of map) try {
1907
+ span.end();
1908
+ } catch (err) {
1909
+ try {
1910
+ onError("end", err);
1911
+ } catch {}
1912
+ }
1913
+ map.clear();
1914
+ }
1915
+ function safeAddEvent(span, name, attrs) {
1916
+ if (!span) return;
1917
+ if (typeof span.addEvent === "function") {
1918
+ try {
1919
+ span.addEvent(name, compact(attrs));
1920
+ } catch (err) {
1921
+ try {
1922
+ onError("addEvent", err);
1923
+ } catch {}
1924
+ }
1925
+ return;
1926
+ }
1927
+ safeSetAttrs(span, Object.fromEntries(Object.entries(compact(attrs)).map(([k, v]) => [`event.${name}.${k}`, v])));
1928
+ }
1929
+ function redact(kind, value, meta) {
1930
+ if (typeof options.redact !== "function") return value;
1931
+ try {
1932
+ return options.redact(kind, value, meta);
1933
+ } catch (err) {
1934
+ try {
1935
+ onError("redact", err);
1936
+ } catch {}
1937
+ return value;
1938
+ }
1939
+ }
1940
+ return {
1941
+ options,
1942
+ legacy,
1943
+ conventions,
1944
+ wantSentry,
1945
+ captureContent,
1946
+ onError,
1947
+ runSpans: /* @__PURE__ */ new Map(),
1948
+ turnSpans: /* @__PURE__ */ new Map(),
1949
+ toolSpans: /* @__PURE__ */ new Map(),
1950
+ mcpSpans: /* @__PURE__ */ new Map(),
1951
+ spawnSpans: /* @__PURE__ */ new Map(),
1952
+ bootstrapSpans: /* @__PURE__ */ new Map(),
1953
+ activeSystem: void 0,
1954
+ turnTrack: /* @__PURE__ */ new Map(),
1955
+ activeRunSpan: void 0,
1956
+ safeStartSpan,
1957
+ safeSetAttrs,
1958
+ safeEnd,
1959
+ endAll,
1960
+ safeAddEvent,
1961
+ redact
1962
+ };
1963
+ }
1964
+ //#endregion
1965
+ //#region src/tracing-spawn-hooks.ts
1966
+ /** `handoff` spawn span + child trace-context injection. */
1967
+ function installTracingSpawnHooks(hooks, unregisters, rt) {
1968
+ const { options, conventions, onError, spawnSpans, safeStartSpan, safeSetAttrs, safeEnd } = rt;
1969
+ unregisters.push(hooks.hook("spawn:before", (ctx) => {
1970
+ const toAgent = ctx.task.length > 60 ? `${ctx.task.slice(0, 57)}…` : ctx.task;
1971
+ const span = safeStartSpan(`handoff to ${toAgent}`, {
1972
+ [GEN_AI.operationName]: "handoff",
1973
+ [GEN_AI.system]: rt.activeSystem,
1974
+ "sentry.op": "gen_ai.handoff",
1975
+ "gen_ai.agent.spawn.id": ctx.id,
1976
+ "gen_ai.agent.spawn.task": ctx.task,
1977
+ "gen_ai.agent.depth": ctx.depth
1978
+ });
1979
+ if (span) spawnSpans.set(ctx.id, span);
1980
+ if (typeof options.getActiveTraceContext === "function" && ctx.tracingContext) {
1981
+ let carrier;
1982
+ try {
1983
+ carrier = options.getActiveTraceContext();
1984
+ } catch (err) {
1985
+ try {
1986
+ onError("getActiveTraceContext", err);
1987
+ } catch {}
1988
+ }
1989
+ if (carrier) for (const [k, v] of Object.entries(carrier)) ctx.tracingContext[k] = v;
1990
+ }
1991
+ }));
1992
+ unregisters.push(hooks.hook("spawn:complete", (ctx) => {
1993
+ const span = spawnSpans.get(ctx.id);
1994
+ const childUsage = buildUsageAttrs({
1995
+ input: ctx.stats.totalIn,
1996
+ output: ctx.stats.totalOut,
1997
+ cacheRead: ctx.stats.totalCacheRead,
1998
+ cacheCreation: ctx.stats.totalCacheCreation,
1999
+ cost: ctx.stats.cost
2000
+ }, conventions);
2001
+ safeSetAttrs(span, {
2002
+ "gen_ai.agent.spawn.status": ctx.status ?? "completed",
2003
+ "gen_ai.agent.spawn.depth": ctx.depth,
2004
+ ...childUsage
2005
+ });
2006
+ safeEnd(spawnSpans, ctx.id);
2007
+ }));
2008
+ unregisters.push(hooks.hook("spawn:error", (ctx) => {
2009
+ safeSetAttrs(spawnSpans.get(ctx.id), {
2010
+ "error.type": ctx.error.name,
2011
+ "error.message": ctx.error.message
2012
+ });
2013
+ safeEnd(spawnSpans, ctx.id);
2014
+ }));
2015
+ }
2016
+ //#endregion
2017
+ //#region src/tracing-tool-hooks.ts
2018
+ /** Native `execute_tool` span. */
2019
+ function installTracingToolHooks(hooks, unregisters, rt) {
2020
+ const { legacy, conventions, wantSentry, captureContent, toolSpans, safeStartSpan, safeSetAttrs, safeEnd, redact } = rt;
2021
+ unregisters.push(hooks.hook("tool:before", (ctx) => {
2022
+ const span = safeStartSpan(`execute_tool ${ctx.displayName}`, {
2023
+ [GEN_AI.operationName]: "execute_tool",
2024
+ [GEN_AI.system]: rt.activeSystem,
2025
+ [GEN_AI.toolName]: ctx.name,
2026
+ [GEN_AI.toolType]: "function",
2027
+ [GEN_AI.toolCallId]: ctx.callId,
2028
+ "sentry.op": "gen_ai.execute_tool",
2029
+ "gen_ai.tool.display_name": ctx.displayName,
2030
+ "gen_ai.agent.turn_id": ctx.turnId,
2031
+ "gen_ai.agent.depth": ctx.depth,
2032
+ "gen_ai.agent.run.id": ctx.runId,
2033
+ "gen_ai.agent.parent_run.id": ctx.parentRunId,
2034
+ ...legacy ? {
2035
+ toolName: ctx.name,
2036
+ displayName: ctx.displayName,
2037
+ turnId: ctx.turnId,
2038
+ callId: ctx.callId
2039
+ } : {}
2040
+ });
2041
+ if (span) {
2042
+ toolSpans.set(ctx.callId, span);
2043
+ if (captureContent) try {
2044
+ const serialized = JSON.stringify(ctx.input);
2045
+ const redacted = redact("tool-input", serialized, {
2046
+ toolName: ctx.name,
2047
+ displayName: ctx.displayName,
2048
+ callId: ctx.callId,
2049
+ turnId: ctx.turnId
2050
+ });
2051
+ const attrs = {};
2052
+ if (wantSentry) attrs[GEN_AI.toolCallArguments] = redacted;
2053
+ if (conventions === "otel" || conventions === "both") attrs[GEN_AI.toolInputDeprecated] = redacted;
2054
+ safeSetAttrs(span, attrs);
2055
+ } catch {}
2056
+ }
2057
+ }));
2058
+ unregisters.push(hooks.hook("tool:after", (ctx) => {
2059
+ const span = toolSpans.get(ctx.callId);
2060
+ safeSetAttrs(span, {
2061
+ "gen_ai.tool.output_bytes": ctx.outputBytes,
2062
+ "gen_ai.tool.coercions": ctx.coercions?.length ?? 0
2063
+ });
2064
+ if (captureContent && typeof ctx.result === "string") {
2065
+ const redacted = redact("tool-result", ctx.result, {
2066
+ toolName: ctx.name,
2067
+ callId: ctx.callId
2068
+ });
2069
+ const attrs = {};
2070
+ if (wantSentry) attrs[GEN_AI.toolCallResult] = redacted;
2071
+ if (conventions === "otel" || conventions === "both") attrs[GEN_AI.toolOutputDeprecated] = redacted;
2072
+ safeSetAttrs(span, attrs);
2073
+ }
2074
+ safeEnd(toolSpans, ctx.callId);
2075
+ }));
2076
+ unregisters.push(hooks.hook("tool:error", (ctx) => {
2077
+ safeSetAttrs(toolSpans.get(ctx.callId), {
2078
+ "error.type": ctx.error.name,
2079
+ "error.message": ctx.error.message
2080
+ });
2081
+ safeEnd(toolSpans, ctx.callId);
2082
+ }));
2083
+ unregisters.push(hooks.hook("tool:cancelled", (ctx) => {
2084
+ safeSetAttrs(toolSpans.get(ctx.callId), {
2085
+ "gen_ai.tool.status": "cancelled",
2086
+ "gen_ai.tool.cancel_reason": ctx.reason
2087
+ });
2088
+ safeEnd(toolSpans, ctx.callId);
2089
+ }));
2090
+ }
2091
+ /** Gate / validation / budget / pairing / OAuth events on the run span. */
2092
+ function installTracingPolicyEventHooks(hooks, unregisters, rt) {
2093
+ const { safeAddEvent } = rt;
2094
+ unregisters.push(hooks.hook("tool:dispatched", (ctx) => {
2095
+ if (ctx.outcome === "gate-block") safeAddEvent(rt.activeRunSpan, "gen_ai.gate.block", {
2096
+ [GEN_AI.toolName]: ctx.name,
2097
+ [GEN_AI.toolCallId]: ctx.callId,
2098
+ reason: ctx.reason
2099
+ });
2100
+ else if (ctx.outcome === "gate-substitute") safeAddEvent(rt.activeRunSpan, "gen_ai.gate.substitute", {
2101
+ [GEN_AI.toolName]: ctx.name,
2102
+ [GEN_AI.toolCallId]: ctx.callId
2103
+ });
2104
+ else if (ctx.outcome === "unknown") safeAddEvent(rt.activeRunSpan, "gen_ai.tool.unknown", {
2105
+ [GEN_AI.toolName]: ctx.name,
2106
+ [GEN_AI.toolCallId]: ctx.callId
2107
+ });
2108
+ else if (ctx.outcome === "invalid-input") safeAddEvent(rt.activeRunSpan, "gen_ai.tool.invalid_input", {
2109
+ [GEN_AI.toolName]: ctx.name,
2110
+ [GEN_AI.toolCallId]: ctx.callId
2111
+ });
2112
+ }));
2113
+ unregisters.push(hooks.hook("validation:reject", (ctx) => {
2114
+ safeAddEvent(rt.activeRunSpan, "gen_ai.validation.reject", {
2115
+ [GEN_AI.toolName]: ctx.name,
2116
+ [GEN_AI.toolCallId]: ctx.callId,
2117
+ reason: ctx.reason
2118
+ });
2119
+ }));
2120
+ unregisters.push(hooks.hook("validation:coerce", (ctx) => {
2121
+ safeAddEvent(rt.activeRunSpan, "gen_ai.validation.coerce", {
2122
+ [GEN_AI.toolName]: ctx.name,
2123
+ [GEN_AI.toolCallId]: ctx.callId,
2124
+ coercions: ctx.coercions
2125
+ });
2126
+ }));
2127
+ unregisters.push(hooks.hook("budget:exceeded", (ctx) => {
2128
+ safeAddEvent(rt.activeRunSpan, "gen_ai.budget.exceeded", {
2129
+ turnId: ctx.turnId,
2130
+ bytes: ctx.bytes,
2131
+ budget: ctx.budget
2132
+ });
2133
+ }));
2134
+ unregisters.push(hooks.hook("tool-budget:exceeded", (ctx) => {
2135
+ safeAddEvent(rt.activeRunSpan, "gen_ai.tool_budget.exceeded", {
2136
+ [GEN_AI.toolName]: ctx.tool,
2137
+ turnId: ctx.turnId,
2138
+ count: ctx.count,
2139
+ max: ctx.max,
2140
+ mode: ctx.mode
2141
+ });
2142
+ }));
2143
+ unregisters.push(hooks.hook("pairing:repair", (ctx) => {
2144
+ safeAddEvent(rt.activeRunSpan, "gen_ai.pairing.repair", {
2145
+ mode: ctx.mode,
2146
+ callId: ctx.callId,
2147
+ turnId: ctx.turnId
2148
+ });
2149
+ }));
2150
+ unregisters.push(hooks.hook("oauth:refresh", (ctx) => {
2151
+ safeAddEvent(rt.activeRunSpan, "gen_ai.oauth.refresh", {
2152
+ provider: ctx.provider,
2153
+ providerId: ctx.providerId,
2154
+ source: ctx.source
2155
+ });
2156
+ }));
2157
+ }
2158
+ //#endregion
2159
+ //#region src/tracing.ts
1897
2160
  /**
1898
2161
  * Build a set of tracing hook handlers that can be installed on an agent.
1899
2162
  *
@@ -1933,504 +2196,23 @@ function createTracingHooks(options) {
1933
2196
  const captureContent = options.captureMessageContent !== false;
1934
2197
  const onError = options.onError ?? (() => {});
1935
2198
  return { install(hooks) {
1936
- const runSpans = /* @__PURE__ */ new Map();
1937
- const turnSpans = /* @__PURE__ */ new Map();
1938
- const toolSpans = /* @__PURE__ */ new Map();
1939
- const mcpSpans = /* @__PURE__ */ new Map();
1940
- const spawnSpans = /* @__PURE__ */ new Map();
1941
- const bootstrapSpans = /* @__PURE__ */ new Map();
1942
- let activeSystem;
1943
- const turnTrack = /* @__PURE__ */ new Map();
1944
- let activeRunSpan;
1945
- function safeStartSpan(name, attrs, parentContext) {
1946
- try {
1947
- return options.startSpan(prefixed(namespace, name), compact(attrs), parentContext);
1948
- } catch (err) {
1949
- try {
1950
- onError("startSpan", err);
1951
- } catch {}
1952
- return;
1953
- }
1954
- }
1955
- function safeSetAttrs(span, attrs) {
1956
- if (!span?.setAttributes) return;
1957
- try {
1958
- span.setAttributes(compact(attrs));
1959
- } catch (err) {
1960
- try {
1961
- onError("setAttributes", err);
1962
- } catch {}
1963
- }
1964
- }
1965
- function safeEnd(map, key) {
1966
- const span = map.get(key);
1967
- if (!span) return;
1968
- try {
1969
- span.end();
1970
- } catch (err) {
1971
- try {
1972
- onError("end", err);
1973
- } catch {}
1974
- }
1975
- map.delete(key);
1976
- }
1977
- function endAll(map) {
1978
- for (const [, span] of map) try {
1979
- span.end();
1980
- } catch (err) {
1981
- try {
1982
- onError("end", err);
1983
- } catch {}
1984
- }
1985
- map.clear();
1986
- }
1987
- function safeAddEvent(span, name, attrs) {
1988
- if (!span) return;
1989
- if (typeof span.addEvent === "function") {
1990
- try {
1991
- span.addEvent(name, compact(attrs));
1992
- } catch (err) {
1993
- try {
1994
- onError("addEvent", err);
1995
- } catch {}
1996
- }
1997
- return;
1998
- }
1999
- safeSetAttrs(span, Object.fromEntries(Object.entries(compact(attrs)).map(([k, v]) => [`event.${name}.${k}`, v])));
2000
- }
2001
- function redact(kind, value, meta) {
2002
- if (typeof options.redact !== "function") return value;
2003
- try {
2004
- return options.redact(kind, value, meta);
2005
- } catch (err) {
2006
- try {
2007
- onError("redact", err);
2008
- } catch {}
2009
- return value;
2010
- }
2011
- }
2199
+ const rt = createTracingRuntime(options, {
2200
+ namespace,
2201
+ legacy,
2202
+ conventions,
2203
+ wantSentry,
2204
+ captureContent,
2205
+ onError
2206
+ });
2207
+ const { runSpans, turnSpans, toolSpans, mcpSpans, spawnSpans, bootstrapSpans, endAll } = rt;
2012
2208
  const unregisters = [];
2013
- unregisters.push(hooks.hook("agent:start", (ctx) => {
2014
- activeSystem = ctx.providerName;
2015
- const span = safeStartSpan(`invoke_agent ${ctx.agentName && ctx.agentName.length > 0 ? ctx.agentName : "agent"}`, {
2016
- [GEN_AI.operationName]: "invoke_agent",
2017
- [GEN_AI.system]: activeSystem,
2018
- [GEN_AI.agentName]: ctx.agentName,
2019
- [GEN_AI.agentRunId]: ctx.runId,
2020
- [GEN_AI.agentParentRunId]: ctx.parentRunId,
2021
- [GEN_AI.agentDepth]: ctx.depth,
2022
- "sentry.op": "gen_ai.invoke_agent",
2023
- ...legacy ? {
2024
- runId: ctx.runId,
2025
- parentRunId: ctx.parentRunId,
2026
- agentName: ctx.agentName,
2027
- depth: ctx.depth
2028
- } : {}
2029
- }, ctx.tracingContext);
2030
- if (span) {
2031
- runSpans.set(ctx.runId, span);
2032
- activeRunSpan = span;
2033
- }
2034
- }));
2035
- unregisters.push(hooks.hook("agent:done", (stats) => {
2036
- const usageAttrs = buildUsageAttrs({
2037
- input: stats.totalIn,
2038
- output: stats.totalOut,
2039
- cacheRead: stats.totalCacheRead,
2040
- cacheCreation: stats.totalCacheCreation,
2041
- cost: stats.cost,
2042
- timeToFirstTokenMs: stats.timeTillFirstTokenMs
2043
- }, conventions);
2044
- for (const [, span] of runSpans) safeSetAttrs(span, {
2045
- ...usageAttrs,
2046
- [GEN_AI.turn]: stats.turns,
2047
- "gen_ai.agent.elapsed_ms": stats.elapsed,
2048
- ...legacy ? {
2049
- totalIn: stats.totalIn,
2050
- totalOut: stats.totalOut,
2051
- totalCacheRead: stats.totalCacheRead,
2052
- totalCacheCreation: stats.totalCacheCreation,
2053
- cost: stats.cost,
2054
- turns: stats.turns,
2055
- elapsed: stats.elapsed
2056
- } : {}
2057
- });
2058
- endAll(runSpans);
2059
- endAll(turnSpans);
2060
- endAll(toolSpans);
2061
- endAll(mcpSpans);
2062
- endAll(spawnSpans);
2063
- endAll(bootstrapSpans);
2064
- activeRunSpan = void 0;
2065
- activeSystem = void 0;
2066
- turnTrack.clear();
2067
- }));
2068
- unregisters.push(hooks.hook("agent:abort", () => {
2069
- for (const [, span] of runSpans) safeSetAttrs(span, { "gen_ai.agent.status": "aborted" });
2070
- }));
2071
- unregisters.push(hooks.hook("turn:before", (ctx) => {
2072
- const requestedModel = ctx.options.model;
2073
- const baseAttrs = {
2074
- [GEN_AI.operationName]: "chat",
2075
- [GEN_AI.system]: activeSystem,
2076
- [GEN_AI.requestModel]: requestedModel,
2077
- [GEN_AI.turn]: ctx.turn,
2078
- [GEN_AI.responseStreaming]: true,
2079
- [GEN_AI.requestMaxTokens]: ctx.options.maxTokens,
2080
- "sentry.op": "gen_ai.chat",
2081
- "gen_ai.agent.turn_id": ctx.turnId,
2082
- ...legacy ? {
2083
- turnId: ctx.turnId,
2084
- turn: ctx.turn
2085
- } : {}
2086
- };
2087
- if (captureContent) {
2088
- const systemText = ctx.options.system;
2089
- if (systemText) baseAttrs[GEN_AI.systemInstructions] = redact("system", systemText, {
2090
- turnId: ctx.turnId,
2091
- turn: ctx.turn
2092
- });
2093
- const inputMsgs = stringifyMessages(ctx.options.messages);
2094
- if (inputMsgs) baseAttrs[GEN_AI.inputMessages] = redact("prompt", inputMsgs, {
2095
- turnId: ctx.turnId,
2096
- turn: ctx.turn
2097
- });
2098
- const toolDefs = stringifyToolDefs(ctx.options.tools);
2099
- if (toolDefs) baseAttrs[GEN_AI.toolDefinitions] = toolDefs;
2100
- }
2101
- const span = safeStartSpan(`chat${requestedModel ? ` ${requestedModel}` : ""}`, baseAttrs);
2102
- if (span) {
2103
- turnSpans.set(ctx.turnId, span);
2104
- turnTrack.set(ctx.turnId, { startedAt: Date.now() });
2105
- }
2106
- }));
2107
- unregisters.push(hooks.hook("stream:start", (ctx) => {
2108
- safeAddEvent(turnSpans.get(ctx.turnId), "gen_ai.stream.start", { startedAt: ctx.startedAt });
2109
- }));
2110
- unregisters.push(hooks.hook("turn:after", (ctx) => {
2111
- const span = turnSpans.get(ctx.turnId);
2112
- const tracked = turnTrack.get(ctx.turnId);
2113
- turnTrack.delete(ctx.turnId);
2114
- let tokensPerSecond;
2115
- if (tracked && ctx.usage.output > 0) {
2116
- const elapsedMs = Date.now() - tracked.startedAt;
2117
- if (elapsedMs > 0) tokensPerSecond = ctx.usage.output / elapsedMs * 1e3;
2118
- }
2119
- const usageAttrs = buildUsageAttrs(ctx.usage, conventions);
2120
- const cumInputTokens = wantSentry ? ctx.cumulativeUsage.input + ctx.cumulativeUsage.cacheRead + ctx.cumulativeUsage.cacheCreation : ctx.cumulativeUsage.input;
2121
- const attrs = {
2122
- ...usageAttrs,
2123
- [GEN_AI.responseTokensPerSecond]: tokensPerSecond,
2124
- "gen_ai.agent.cumulative.input_tokens": cumInputTokens,
2125
- "gen_ai.agent.cumulative.output_tokens": ctx.cumulativeUsage.output,
2126
- "gen_ai.agent.cumulative.total_tokens": cumInputTokens + ctx.cumulativeUsage.output,
2127
- "gen_ai.agent.cumulative.cache_read_input_tokens": ctx.cumulativeUsage.cacheRead,
2128
- "gen_ai.agent.cumulative.cache_creation_input_tokens": ctx.cumulativeUsage.cacheCreation,
2129
- "gen_ai.agent.cumulative.cost_usd": ctx.cumulativeUsage.cost,
2130
- "gen_ai.agent.cumulative.turns": ctx.cumulativeUsage.turns,
2131
- ...legacy ? {
2132
- inputTokens: ctx.usage.input,
2133
- outputTokens: ctx.usage.output,
2134
- finishReason: ctx.usage.finishReason,
2135
- modelId: ctx.usage.modelId
2136
- } : {}
2137
- };
2138
- if (captureContent && ctx.message && ctx.message.role !== "system" && ctx.message.role !== "command") {
2139
- const outputMsgs = stringifyMessages([{
2140
- role: ctx.message.role,
2141
- content: ctx.message.content
2142
- }]);
2143
- if (outputMsgs) attrs[GEN_AI.outputMessages] = redact("stream-text", outputMsgs, {
2144
- turnId: ctx.turnId,
2145
- turn: ctx.turn
2146
- });
2147
- }
2148
- safeSetAttrs(span, attrs);
2149
- safeEnd(turnSpans, ctx.turnId);
2150
- }));
2151
- unregisters.push(hooks.hook("stream:error", (ctx) => {
2152
- const span = turnSpans.get(ctx.turnId);
2153
- const message = ctx.err instanceof Error ? ctx.err.message : String(ctx.err);
2154
- safeSetAttrs(span, {
2155
- "error.type": ctx.err instanceof Error ? ctx.err.name : "unknown",
2156
- "error.message": message,
2157
- "http.response.status_code": ctx.statusCode,
2158
- "gen_ai.request.id": ctx.requestId
2159
- });
2160
- safeAddEvent(span, "gen_ai.stream.error", {
2161
- "error.type": ctx.err instanceof Error ? ctx.err.name : "unknown",
2162
- "error.message": message,
2163
- "http.response.status_code": ctx.statusCode,
2164
- "gen_ai.request.id": ctx.requestId
2165
- });
2166
- }));
2167
- unregisters.push(hooks.hook("tool:before", (ctx) => {
2168
- const span = safeStartSpan(`execute_tool ${ctx.displayName}`, {
2169
- [GEN_AI.operationName]: "execute_tool",
2170
- [GEN_AI.system]: activeSystem,
2171
- [GEN_AI.toolName]: ctx.name,
2172
- [GEN_AI.toolType]: "function",
2173
- [GEN_AI.toolCallId]: ctx.callId,
2174
- "sentry.op": "gen_ai.execute_tool",
2175
- "gen_ai.tool.display_name": ctx.displayName,
2176
- "gen_ai.agent.turn_id": ctx.turnId,
2177
- "gen_ai.agent.depth": ctx.depth,
2178
- "gen_ai.agent.run.id": ctx.runId,
2179
- "gen_ai.agent.parent_run.id": ctx.parentRunId,
2180
- ...legacy ? {
2181
- toolName: ctx.name,
2182
- displayName: ctx.displayName,
2183
- turnId: ctx.turnId,
2184
- callId: ctx.callId
2185
- } : {}
2186
- });
2187
- if (span) {
2188
- toolSpans.set(ctx.callId, span);
2189
- if (captureContent) try {
2190
- const redacted = redact("tool-input", JSON.stringify(ctx.input), {
2191
- toolName: ctx.name,
2192
- displayName: ctx.displayName,
2193
- callId: ctx.callId,
2194
- turnId: ctx.turnId
2195
- });
2196
- const attrs = {};
2197
- if (wantSentry) attrs[GEN_AI.toolCallArguments] = redacted;
2198
- if (conventions === "otel" || conventions === "both") attrs[GEN_AI.toolInputDeprecated] = redacted;
2199
- safeSetAttrs(span, attrs);
2200
- } catch {}
2201
- }
2202
- }));
2203
- unregisters.push(hooks.hook("tool:after", (ctx) => {
2204
- const span = toolSpans.get(ctx.callId);
2205
- safeSetAttrs(span, {
2206
- "gen_ai.tool.output_bytes": ctx.outputBytes,
2207
- "gen_ai.tool.coercions": ctx.coercions?.length ?? 0
2208
- });
2209
- if (captureContent && typeof ctx.result === "string") {
2210
- const redacted = redact("tool-result", ctx.result, {
2211
- toolName: ctx.name,
2212
- callId: ctx.callId
2213
- });
2214
- const attrs = {};
2215
- if (wantSentry) attrs[GEN_AI.toolCallResult] = redacted;
2216
- if (conventions === "otel" || conventions === "both") attrs[GEN_AI.toolOutputDeprecated] = redacted;
2217
- safeSetAttrs(span, attrs);
2218
- }
2219
- safeEnd(toolSpans, ctx.callId);
2220
- }));
2221
- unregisters.push(hooks.hook("tool:error", (ctx) => {
2222
- safeSetAttrs(toolSpans.get(ctx.callId), {
2223
- "error.type": ctx.error.name,
2224
- "error.message": ctx.error.message
2225
- });
2226
- safeEnd(toolSpans, ctx.callId);
2227
- }));
2228
- unregisters.push(hooks.hook("tool:dispatched", (ctx) => {
2229
- if (ctx.outcome === "gate-block") safeAddEvent(activeRunSpan, "gen_ai.gate.block", {
2230
- [GEN_AI.toolName]: ctx.name,
2231
- [GEN_AI.toolCallId]: ctx.callId,
2232
- reason: ctx.reason
2233
- });
2234
- else if (ctx.outcome === "gate-substitute") safeAddEvent(activeRunSpan, "gen_ai.gate.substitute", {
2235
- [GEN_AI.toolName]: ctx.name,
2236
- [GEN_AI.toolCallId]: ctx.callId
2237
- });
2238
- else if (ctx.outcome === "unknown") safeAddEvent(activeRunSpan, "gen_ai.tool.unknown", {
2239
- [GEN_AI.toolName]: ctx.name,
2240
- [GEN_AI.toolCallId]: ctx.callId
2241
- });
2242
- else if (ctx.outcome === "invalid-input") safeAddEvent(activeRunSpan, "gen_ai.tool.invalid_input", {
2243
- [GEN_AI.toolName]: ctx.name,
2244
- [GEN_AI.toolCallId]: ctx.callId
2245
- });
2246
- }));
2247
- unregisters.push(hooks.hook("validation:reject", (ctx) => {
2248
- safeAddEvent(activeRunSpan, "gen_ai.validation.reject", {
2249
- [GEN_AI.toolName]: ctx.name,
2250
- [GEN_AI.toolCallId]: ctx.callId,
2251
- reason: ctx.reason
2252
- });
2253
- }));
2254
- unregisters.push(hooks.hook("validation:coerce", (ctx) => {
2255
- safeAddEvent(activeRunSpan, "gen_ai.validation.coerce", {
2256
- [GEN_AI.toolName]: ctx.name,
2257
- [GEN_AI.toolCallId]: ctx.callId,
2258
- coercions: ctx.coercions
2259
- });
2260
- }));
2261
- unregisters.push(hooks.hook("budget:exceeded", (ctx) => {
2262
- safeAddEvent(activeRunSpan, "gen_ai.budget.exceeded", {
2263
- turnId: ctx.turnId,
2264
- bytes: ctx.bytes,
2265
- budget: ctx.budget
2266
- });
2267
- }));
2268
- unregisters.push(hooks.hook("tool-budget:exceeded", (ctx) => {
2269
- safeAddEvent(activeRunSpan, "gen_ai.tool_budget.exceeded", {
2270
- [GEN_AI.toolName]: ctx.tool,
2271
- turnId: ctx.turnId,
2272
- count: ctx.count,
2273
- max: ctx.max,
2274
- mode: ctx.mode
2275
- });
2276
- }));
2277
- unregisters.push(hooks.hook("pairing:repair", (ctx) => {
2278
- safeAddEvent(activeRunSpan, "gen_ai.pairing.repair", {
2279
- mode: ctx.mode,
2280
- callId: ctx.callId,
2281
- turnId: ctx.turnId
2282
- });
2283
- }));
2284
- unregisters.push(hooks.hook("oauth:refresh", (ctx) => {
2285
- safeAddEvent(activeRunSpan, "gen_ai.oauth.refresh", {
2286
- provider: ctx.provider,
2287
- providerId: ctx.providerId,
2288
- source: ctx.source
2289
- });
2290
- }));
2291
- unregisters.push(hooks.hook("mcp:tool:before", (ctx) => {
2292
- const span = safeStartSpan(`execute_tool ${ctx.server}.${ctx.tool}`, {
2293
- [GEN_AI.operationName]: "execute_tool",
2294
- [GEN_AI.system]: activeSystem,
2295
- [GEN_AI.toolName]: ctx.displayName,
2296
- [GEN_AI.toolType]: "extension",
2297
- [GEN_AI.toolCallId]: ctx.callId,
2298
- [GEN_AI.mcpServer]: ctx.server,
2299
- "sentry.op": "gen_ai.execute_tool",
2300
- "gen_ai.mcp.tool": ctx.tool,
2301
- "gen_ai.agent.turn_id": ctx.turnId,
2302
- "gen_ai.agent.run.id": ctx.runId,
2303
- ...legacy ? {
2304
- server: ctx.server,
2305
- tool: ctx.tool,
2306
- displayName: ctx.displayName,
2307
- turnId: ctx.turnId,
2308
- callId: ctx.callId
2309
- } : {}
2310
- });
2311
- if (span) {
2312
- mcpSpans.set(ctx.callId, span);
2313
- if (captureContent) try {
2314
- const redacted = redact("mcp-tool-input", JSON.stringify(ctx.input), {
2315
- server: ctx.server,
2316
- tool: ctx.tool,
2317
- callId: ctx.callId
2318
- });
2319
- const attrs = {};
2320
- if (wantSentry) attrs[GEN_AI.toolCallArguments] = redacted;
2321
- if (conventions === "otel" || conventions === "both") attrs[GEN_AI.toolInputDeprecated] = redacted;
2322
- safeSetAttrs(span, attrs);
2323
- } catch {}
2324
- }
2325
- }));
2326
- unregisters.push(hooks.hook("mcp:tool:after", (ctx) => {
2327
- const span = mcpSpans.get(ctx.callId);
2328
- safeSetAttrs(span, { "gen_ai.tool.output_bytes": ctx.outputBytes });
2329
- if (captureContent && typeof ctx.result === "string") {
2330
- const redacted = redact("mcp-tool-result", ctx.result, {
2331
- server: ctx.server,
2332
- tool: ctx.tool,
2333
- callId: ctx.callId
2334
- });
2335
- const attrs = {};
2336
- if (wantSentry) attrs[GEN_AI.toolCallResult] = redacted;
2337
- if (conventions === "otel" || conventions === "both") attrs[GEN_AI.toolOutputDeprecated] = redacted;
2338
- safeSetAttrs(span, attrs);
2339
- }
2340
- safeEnd(mcpSpans, ctx.callId);
2341
- }));
2342
- unregisters.push(hooks.hook("mcp:tool:error", (ctx) => {
2343
- safeSetAttrs(mcpSpans.get(ctx.callId), {
2344
- "error.type": ctx.error.name,
2345
- "error.message": ctx.error.message
2346
- });
2347
- safeEnd(mcpSpans, ctx.callId);
2348
- }));
2349
- unregisters.push(hooks.hook("mcp:bootstrap:start", (ctx) => {
2350
- const span = safeStartSpan(`mcp.bootstrap ${ctx.name}`, {
2351
- [GEN_AI.operationName]: "mcp.bootstrap",
2352
- [GEN_AI.system]: activeSystem,
2353
- [GEN_AI.mcpServer]: ctx.name,
2354
- "gen_ai.mcp.transport": ctx.transport
2355
- });
2356
- if (span) bootstrapSpans.set(ctx.name, span);
2357
- }));
2358
- unregisters.push(hooks.hook("mcp:bootstrap:end", (ctx) => {
2359
- const span = bootstrapSpans.get(ctx.name);
2360
- const ok = ctx.ok;
2361
- safeSetAttrs(span, {
2362
- "gen_ai.mcp.bootstrap.duration_ms": ctx.durationMs,
2363
- "gen_ai.mcp.bootstrap.ok": ok,
2364
- ...ok ? {
2365
- [GEN_AI.mcpToolCount]: ctx.toolCount,
2366
- "gen_ai.mcp.lazy": ctx.lazy,
2367
- "gen_ai.mcp.cached": ctx.cached
2368
- } : {
2369
- "error.type": ctx.error.name,
2370
- "error.message": ctx.error.message
2371
- }
2372
- });
2373
- safeEnd(bootstrapSpans, ctx.name);
2374
- }));
2375
- unregisters.push(hooks.hook("mcp:auth:required", (ctx) => {
2376
- safeAddEvent(bootstrapSpans.get(ctx.name) ?? activeRunSpan, "gen_ai.mcp.auth.required", {
2377
- server: ctx.name,
2378
- transport: ctx.transport,
2379
- reason: ctx.reason
2380
- });
2381
- }));
2382
- unregisters.push(hooks.hook("mcp:error", (ctx) => {
2383
- safeAddEvent(activeRunSpan, "gen_ai.mcp.error", {
2384
- "server": ctx.name,
2385
- "error.type": ctx.error.name,
2386
- "error.message": ctx.error.message
2387
- });
2388
- }));
2389
- unregisters.push(hooks.hook("spawn:before", (ctx) => {
2390
- const span = safeStartSpan(`handoff to ${ctx.task.length > 60 ? `${ctx.task.slice(0, 57)}…` : ctx.task}`, {
2391
- [GEN_AI.operationName]: "handoff",
2392
- [GEN_AI.system]: activeSystem,
2393
- "sentry.op": "gen_ai.handoff",
2394
- "gen_ai.agent.spawn.id": ctx.id,
2395
- "gen_ai.agent.spawn.task": ctx.task,
2396
- "gen_ai.agent.depth": ctx.depth
2397
- });
2398
- if (span) spawnSpans.set(ctx.id, span);
2399
- if (typeof options.getActiveTraceContext === "function" && ctx.tracingContext) {
2400
- let carrier;
2401
- try {
2402
- carrier = options.getActiveTraceContext();
2403
- } catch (err) {
2404
- try {
2405
- onError("getActiveTraceContext", err);
2406
- } catch {}
2407
- }
2408
- if (carrier) for (const [k, v] of Object.entries(carrier)) ctx.tracingContext[k] = v;
2409
- }
2410
- }));
2411
- unregisters.push(hooks.hook("spawn:complete", (ctx) => {
2412
- const span = spawnSpans.get(ctx.id);
2413
- const childUsage = buildUsageAttrs({
2414
- input: ctx.stats.totalIn,
2415
- output: ctx.stats.totalOut,
2416
- cacheRead: ctx.stats.totalCacheRead,
2417
- cacheCreation: ctx.stats.totalCacheCreation,
2418
- cost: ctx.stats.cost
2419
- }, conventions);
2420
- safeSetAttrs(span, {
2421
- "gen_ai.agent.spawn.status": ctx.status ?? "completed",
2422
- "gen_ai.agent.spawn.depth": ctx.depth,
2423
- ...childUsage
2424
- });
2425
- safeEnd(spawnSpans, ctx.id);
2426
- }));
2427
- unregisters.push(hooks.hook("spawn:error", (ctx) => {
2428
- safeSetAttrs(spawnSpans.get(ctx.id), {
2429
- "error.type": ctx.error.name,
2430
- "error.message": ctx.error.message
2431
- });
2432
- safeEnd(spawnSpans, ctx.id);
2433
- }));
2209
+ installTracingAgentHooks(hooks, unregisters, rt);
2210
+ installTracingTurnHooks(hooks, unregisters, rt);
2211
+ installTracingToolHooks(hooks, unregisters, rt);
2212
+ installTracingPolicyEventHooks(hooks, unregisters, rt);
2213
+ installTracingMcpToolHooks(hooks, unregisters, rt);
2214
+ installTracingMcpServerHooks(hooks, unregisters, rt);
2215
+ installTracingSpawnHooks(hooks, unregisters, rt);
2434
2216
  let disposed = false;
2435
2217
  return function uninstall() {
2436
2218
  if (disposed) return;
@@ -2444,7 +2226,7 @@ function createTracingHooks(options) {
2444
2226
  endAll(mcpSpans);
2445
2227
  endAll(spawnSpans);
2446
2228
  endAll(bootstrapSpans);
2447
- activeRunSpan = void 0;
2229
+ rt.activeRunSpan = void 0;
2448
2230
  };
2449
2231
  } };
2450
2232
  }
@@ -2456,6 +2238,6 @@ function createTracingHooks(options) {
2456
2238
  */
2457
2239
  const GEN_AI_ATTRIBUTES = GEN_AI;
2458
2240
  //#endregion
2459
- export { zodToJsonSchema as A, tokenEndingAtCursor as C, shouldAutoGenerateTitle as D, generateSessionTitle as E, parseCommandInvocation as F, localReliabilityBehavior as I, commandBlocksToContent as M, commandSteps as N, isStandardSchema as O, executeCommand as P, resolveInlineSuggestion as S, cleanTitle as T, resolveExtensionDocsDir as _, loginMcpServer as a, createPathAutocompleteProvider as b, SKILL_EDIT_METADATA_KEY as c, buildZidaneExtensionSkill as d, buildZidaneSkillEditSkill as f, readSkillEditMarker as g, extensionScaffold as h, createMetricsHooks as i, commandBlockToEvent as j, resolveSchemaInput as k, ZIDANE_EXTENSION_SKILL_NAME as l, extensionDirForCwd as m, createTracingHooks as n, startOAuthCallback as o, editSessionMetadata as p, createMutationValidationHooks as r, EXTENSION_EDIT_METADATA_KEY as s, GEN_AI_ATTRIBUTES as t, ZIDANE_SKILL_EDIT_SKILL_NAME as u, withZidaneExtensionSkill as v, generateStructuredData as w, patchInlineGhost as x, withZidaneSkillEditSkill as y };
2241
+ export { parseCommandInvocation as C, mergeCommands as S, localReliabilityBehavior as T, commandBlockToEvent as _, loginMcpServer as a, createCommandRunRecord as b, resolveInlineSuggestion as c, cleanTitle as d, generateSessionTitle as f, zodToJsonSchema as g, resolveSchemaInput as h, createMetricsHooks as i, tokenEndingAtCursor as l, isStandardSchema as m, createTracingHooks as n, startOAuthCallback as o, shouldAutoGenerateTitle as p, createMutationValidationHooks as r, createPathAutocompleteProvider as s, GEN_AI_ATTRIBUTES as t, generateStructuredData as u, commandBlocksToContent as v, routesToDaemon as w, executeCommand as x, commandSteps as y };
2460
2242
 
2461
- //# sourceMappingURL=src-CkNQKFKr.js.map
2243
+ //# sourceMappingURL=src-BRMYRJib.js.map