@probelabs/visor 0.1.183-ee → 0.1.184-ee

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 (241) hide show
  1. package/dist/agent-protocol/task-live-update-slack.d.ts +24 -0
  2. package/dist/agent-protocol/task-live-update-slack.d.ts.map +1 -0
  3. package/dist/agent-protocol/task-live-update-teams.d.ts +25 -0
  4. package/dist/agent-protocol/task-live-update-teams.d.ts.map +1 -0
  5. package/dist/agent-protocol/task-live-update-telegram.d.ts +25 -0
  6. package/dist/agent-protocol/task-live-update-telegram.d.ts.map +1 -0
  7. package/dist/agent-protocol/task-live-updates.d.ts +102 -0
  8. package/dist/agent-protocol/task-live-updates.d.ts.map +1 -0
  9. package/dist/agent-protocol/task-progress-tool.d.ts.map +1 -1
  10. package/dist/agent-protocol/task-trace-resolution.d.ts +11 -0
  11. package/dist/agent-protocol/task-trace-resolution.d.ts.map +1 -0
  12. package/dist/agent-protocol/trace-serializer.d.ts.map +1 -1
  13. package/dist/agent-protocol/track-execution.d.ts +8 -0
  14. package/dist/agent-protocol/track-execution.d.ts.map +1 -1
  15. package/dist/cli-main.d.ts.map +1 -1
  16. package/dist/cli.d.ts.map +1 -1
  17. package/dist/config.d.ts.map +1 -1
  18. package/dist/frontends/slack-frontend.d.ts +2 -0
  19. package/dist/frontends/slack-frontend.d.ts.map +1 -1
  20. package/dist/frontends/teams-frontend.d.ts.map +1 -1
  21. package/dist/frontends/telegram-frontend.d.ts.map +1 -1
  22. package/dist/generated/config-schema.d.ts +110 -6
  23. package/dist/generated/config-schema.d.ts.map +1 -1
  24. package/dist/index.js +2239 -261
  25. package/dist/logger.d.ts +4 -1
  26. package/dist/logger.d.ts.map +1 -1
  27. package/dist/mcp-job-manager.d.ts +70 -0
  28. package/dist/mcp-job-manager.d.ts.map +1 -0
  29. package/dist/mcp-server.d.ts +6 -0
  30. package/dist/mcp-server.d.ts.map +1 -1
  31. package/dist/runners/mcp-server-runner.d.ts +4 -0
  32. package/dist/runners/mcp-server-runner.d.ts.map +1 -1
  33. package/dist/runners/runner-factory.d.ts.map +1 -1
  34. package/dist/sdk/{a2a-frontend-5YDHFQXD.mjs → a2a-frontend-OI4OVSKC.mjs} +4 -4
  35. package/dist/sdk/check-provider-registry-RITJW67U.mjs +32 -0
  36. package/dist/sdk/check-provider-registry-ZZ6N4GDP.mjs +32 -0
  37. package/dist/sdk/{chunk-4BN2XI4X.mjs → chunk-4HIWZA6M.mjs} +2 -2
  38. package/dist/sdk/{chunk-RI4ONH5X.mjs → chunk-4MHHELVZ.mjs} +2 -2
  39. package/dist/sdk/{chunk-J27D43HS.mjs → chunk-4ZLYHSN4.mjs} +2 -2
  40. package/dist/sdk/{chunk-ZPYODGYA.mjs → chunk-6E625R3C.mjs} +19 -4
  41. package/dist/sdk/chunk-6E625R3C.mjs.map +1 -0
  42. package/dist/sdk/{chunk-GA2TYKSR.mjs → chunk-7XKHFRPN.mjs} +4 -4
  43. package/dist/sdk/{chunk-6C3R6E42.mjs → chunk-IY5PQ5EN.mjs} +30 -6
  44. package/dist/sdk/chunk-IY5PQ5EN.mjs.map +1 -0
  45. package/dist/sdk/{chunk-MFXPJUUE.mjs → chunk-PUHU6UY6.mjs} +4 -3
  46. package/dist/sdk/chunk-PUHU6UY6.mjs.map +1 -0
  47. package/dist/sdk/{chunk-XOAEKFKB.mjs → chunk-QLT42TX7.mjs} +2 -2
  48. package/dist/sdk/chunk-SRU5TFNY.mjs +620 -0
  49. package/dist/sdk/chunk-SRU5TFNY.mjs.map +1 -0
  50. package/dist/sdk/{chunk-P2K4VOMU.mjs → chunk-TSX3YS3F.mjs} +3 -3
  51. package/dist/sdk/{chunk-WKLJ57WF.mjs → chunk-UM7LGO2P.mjs} +6 -6
  52. package/dist/sdk/{chunk-7VTZDC2X.mjs → chunk-VPPBOKBQ.mjs} +2 -2
  53. package/dist/sdk/chunk-WZQMTD7W.mjs +33 -0
  54. package/dist/sdk/chunk-WZQMTD7W.mjs.map +1 -0
  55. package/dist/sdk/{chunk-ZOF5QT6U.mjs → chunk-YBXNG75V.mjs} +118 -10
  56. package/dist/sdk/chunk-YBXNG75V.mjs.map +1 -0
  57. package/dist/sdk/{chunk-UXB4XWEE.mjs → chunk-YYFSAAD6.mjs} +53 -51
  58. package/dist/sdk/chunk-YYFSAAD6.mjs.map +1 -0
  59. package/dist/sdk/{chunk-RHKPFJLG.mjs → chunk-ZNKL6ESZ.mjs} +2 -2
  60. package/dist/sdk/{chunk-IDL3AA3G.mjs → chunk-ZYDRR6PZ.mjs} +1150 -403
  61. package/dist/sdk/chunk-ZYDRR6PZ.mjs.map +1 -0
  62. package/dist/sdk/{command-executor-YNJOS77A.mjs → command-executor-LHUW77GR.mjs} +3 -3
  63. package/dist/sdk/{config-PCP6O6Y6.mjs → config-TVU5RWR5.mjs} +3 -3
  64. package/dist/sdk/{dist-3UGGEZB3.mjs → dist-PN5UHL6A.mjs} +429 -429
  65. package/dist/sdk/dist-PN5UHL6A.mjs.map +1 -0
  66. package/dist/sdk/{email-frontend-WSNADJPI.mjs → email-frontend-ECHQCFTR.mjs} +2 -2
  67. package/dist/sdk/{failure-condition-evaluator-IRFKTYZD.mjs → failure-condition-evaluator-USY3ISVA.mjs} +6 -6
  68. package/dist/sdk/{github-auth-BJQBLK2V.mjs → github-auth-UO4DMNCC.mjs} +2 -2
  69. package/dist/sdk/{github-frontend-DECYOBRN.mjs → github-frontend-2T5PWYD5.mjs} +6 -6
  70. package/dist/sdk/{host-CFM2ASDI.mjs → host-OJSMCLKK.mjs} +6 -6
  71. package/dist/sdk/{host-T4LNVU2H.mjs → host-RM6UJEPP.mjs} +7 -7
  72. package/dist/sdk/{knex-store-OEWSZEBY.mjs → knex-store-KCMFAMH5.mjs} +2 -2
  73. package/dist/sdk/{liquid-extensions-E3AKRX7P.mjs → liquid-extensions-KZIRR4OY.mjs} +4 -4
  74. package/dist/sdk/{loader-WRGI244P.mjs → loader-35YWX5UQ.mjs} +4 -4
  75. package/dist/sdk/{memory-store-OHUIXCWJ.mjs → memory-store-3JONK7AF.mjs} +3 -3
  76. package/dist/sdk/{opa-policy-engine-IVMCGVNA.mjs → opa-policy-engine-FY5D45YS.mjs} +2 -2
  77. package/dist/sdk/{prompt-state-LN57DQF3.mjs → prompt-state-VVJMONT3.mjs} +3 -3
  78. package/dist/sdk/{renderer-schema-BT2IXMLW.mjs → renderer-schema-JZRRU5CW.mjs} +2 -2
  79. package/dist/sdk/{routing-H2PQ57OA.mjs → routing-NNQQSLWA.mjs} +8 -8
  80. package/dist/sdk/{schedule-tool-2DPNSU63.mjs → schedule-tool-ADZ2ON4I.mjs} +15 -14
  81. package/dist/sdk/schedule-tool-EMNF3FPQ.mjs +38 -0
  82. package/dist/sdk/{schedule-tool-handler-NBEO46RV.mjs → schedule-tool-handler-3R3IC6VA.mjs} +15 -14
  83. package/dist/sdk/{schedule-tool-handler-KLHE2SOW.mjs → schedule-tool-handler-F76ZD2WU.mjs} +17 -16
  84. package/dist/sdk/sdk.d.mts +40 -0
  85. package/dist/sdk/sdk.d.ts +40 -0
  86. package/dist/sdk/sdk.js +1154 -176
  87. package/dist/sdk/sdk.js.map +1 -1
  88. package/dist/sdk/sdk.mjs +14 -13
  89. package/dist/sdk/sdk.mjs.map +1 -1
  90. package/dist/sdk/{slack-frontend-DF5VL4OF.mjs → slack-frontend-K3TPGERM.mjs} +65 -9
  91. package/dist/sdk/slack-frontend-K3TPGERM.mjs.map +1 -0
  92. package/dist/sdk/{task-evaluator-OVMG7S56.mjs → task-evaluator-H3BXC7SE.mjs} +3 -3
  93. package/dist/sdk/{teams-frontend-DNW5GZP3.mjs → teams-frontend-6RRW533K.mjs} +54 -1
  94. package/dist/sdk/teams-frontend-6RRW533K.mjs.map +1 -0
  95. package/dist/sdk/{telegram-frontend-GA7OLADB.mjs → telegram-frontend-5UA77YAT.mjs} +48 -1
  96. package/dist/sdk/telegram-frontend-5UA77YAT.mjs.map +1 -0
  97. package/dist/sdk/{trace-helpers-26ZCAE2V.mjs → trace-helpers-OMF4C24T.mjs} +3 -3
  98. package/dist/sdk/{trace-serializer-KKBJHM7J.mjs → trace-serializer-EBHTHZYT.mjs} +3 -3
  99. package/dist/sdk/track-execution-3CHMGEPH.mjs +249 -0
  100. package/dist/sdk/track-execution-3CHMGEPH.mjs.map +1 -0
  101. package/dist/sdk/{utcp-check-provider-WI3QZ3W6.mjs → utcp-check-provider-Q4PD5EP2.mjs} +5 -5
  102. package/dist/sdk/workflow-check-provider-TC2G33WF.mjs +32 -0
  103. package/dist/sdk/workflow-check-provider-U4UXZ5YS.mjs +32 -0
  104. package/dist/sdk/{workflow-registry-YCZ3FCJC.mjs → workflow-registry-K56UTX36.mjs} +3 -3
  105. package/dist/slack/client.d.ts +14 -0
  106. package/dist/slack/client.d.ts.map +1 -1
  107. package/dist/slack/socket-runner.d.ts.map +1 -1
  108. package/dist/teams/client.d.ts +16 -0
  109. package/dist/teams/client.d.ts.map +1 -1
  110. package/dist/teams/webhook-runner.d.ts.map +1 -1
  111. package/dist/telegram/client.d.ts +17 -0
  112. package/dist/telegram/client.d.ts.map +1 -1
  113. package/dist/telegram/polling-runner.d.ts.map +1 -1
  114. package/dist/types/cli.d.ts +2 -0
  115. package/dist/types/cli.d.ts.map +1 -1
  116. package/dist/types/config.d.ts +40 -0
  117. package/dist/types/config.d.ts.map +1 -1
  118. package/package.json +4 -3
  119. package/dist/generated/config-schema.json +0 -4027
  120. package/dist/sdk/a2a-frontend-6LWBIPMS.mjs +0 -1734
  121. package/dist/sdk/a2a-frontend-6LWBIPMS.mjs.map +0 -1
  122. package/dist/sdk/check-provider-registry-WSEVHJEV.mjs +0 -31
  123. package/dist/sdk/check-provider-registry-YRADEEQY.mjs +0 -31
  124. package/dist/sdk/chunk-34QX63WK.mjs +0 -244
  125. package/dist/sdk/chunk-34QX63WK.mjs.map +0 -1
  126. package/dist/sdk/chunk-54KOAC4W.mjs +0 -665
  127. package/dist/sdk/chunk-6C3R6E42.mjs.map +0 -1
  128. package/dist/sdk/chunk-7W5QCO4Y.mjs +0 -5943
  129. package/dist/sdk/chunk-7W5QCO4Y.mjs.map +0 -1
  130. package/dist/sdk/chunk-7XRSCOKE.mjs +0 -825
  131. package/dist/sdk/chunk-FT3I25QV.mjs +0 -251
  132. package/dist/sdk/chunk-FT3I25QV.mjs.map +0 -1
  133. package/dist/sdk/chunk-G7GSN3SK.mjs +0 -390
  134. package/dist/sdk/chunk-G7GSN3SK.mjs.map +0 -1
  135. package/dist/sdk/chunk-IDL3AA3G.mjs.map +0 -1
  136. package/dist/sdk/chunk-J27D43HS.mjs.map +0 -1
  137. package/dist/sdk/chunk-MEB2TTIE.mjs +0 -157
  138. package/dist/sdk/chunk-MEB2TTIE.mjs.map +0 -1
  139. package/dist/sdk/chunk-MFXPJUUE.mjs.map +0 -1
  140. package/dist/sdk/chunk-NPSLGKXB.mjs +0 -1502
  141. package/dist/sdk/chunk-P2K4VOMU.mjs.map +0 -1
  142. package/dist/sdk/chunk-PQWZ6NFL.mjs +0 -459
  143. package/dist/sdk/chunk-PQWZ6NFL.mjs.map +0 -1
  144. package/dist/sdk/chunk-S5FSRHMY.mjs +0 -139
  145. package/dist/sdk/chunk-S5FSRHMY.mjs.map +0 -1
  146. package/dist/sdk/chunk-TFUQ2D5L.mjs +0 -307
  147. package/dist/sdk/chunk-TFUQ2D5L.mjs.map +0 -1
  148. package/dist/sdk/chunk-UCMJJ3IM.mjs +0 -227
  149. package/dist/sdk/chunk-UCMJJ3IM.mjs.map +0 -1
  150. package/dist/sdk/chunk-UFHOIB3R.mjs +0 -482
  151. package/dist/sdk/chunk-UFHOIB3R.mjs.map +0 -1
  152. package/dist/sdk/chunk-UXB4XWEE.mjs.map +0 -1
  153. package/dist/sdk/chunk-V45TITKX.mjs +0 -739
  154. package/dist/sdk/chunk-V45TITKX.mjs.map +0 -1
  155. package/dist/sdk/chunk-WKLJ57WF.mjs.map +0 -1
  156. package/dist/sdk/chunk-ZOF5QT6U.mjs.map +0 -1
  157. package/dist/sdk/chunk-ZPYODGYA.mjs.map +0 -1
  158. package/dist/sdk/command-executor-3AHGIYQG.mjs +0 -14
  159. package/dist/sdk/config-JE4HKTWW.mjs +0 -16
  160. package/dist/sdk/dist-3UGGEZB3.mjs.map +0 -1
  161. package/dist/sdk/failure-condition-evaluator-H3PBFBYT.mjs +0 -18
  162. package/dist/sdk/github-auth-27SZGPEC.mjs +0 -196
  163. package/dist/sdk/github-auth-BJQBLK2V.mjs.map +0 -1
  164. package/dist/sdk/github-frontend-TZRBOQCN.mjs +0 -1394
  165. package/dist/sdk/github-frontend-TZRBOQCN.mjs.map +0 -1
  166. package/dist/sdk/lazy-otel-5NH4ZJJM.mjs +0 -24
  167. package/dist/sdk/liquid-extensions-P6KDYILF.mjs +0 -25
  168. package/dist/sdk/memory-store-K5N7MC7U.mjs +0 -12
  169. package/dist/sdk/metrics-JTOG2HNO.mjs +0 -41
  170. package/dist/sdk/prompt-state-YPICX7PI.mjs +0 -16
  171. package/dist/sdk/renderer-schema-KOIH75RZ.mjs +0 -51
  172. package/dist/sdk/renderer-schema-KOIH75RZ.mjs.map +0 -1
  173. package/dist/sdk/routing-JMZ7HDCC.mjs +0 -26
  174. package/dist/sdk/schedule-tool-4M45RK3E.mjs +0 -37
  175. package/dist/sdk/schedule-tool-4M45RK3E.mjs.map +0 -1
  176. package/dist/sdk/schedule-tool-handler-KLHE2SOW.mjs.map +0 -1
  177. package/dist/sdk/schedule-tool-handler-NBEO46RV.mjs.map +0 -1
  178. package/dist/sdk/slack-frontend-BPWXNIHE.mjs +0 -929
  179. package/dist/sdk/slack-frontend-BPWXNIHE.mjs.map +0 -1
  180. package/dist/sdk/slack-frontend-DF5VL4OF.mjs.map +0 -1
  181. package/dist/sdk/task-evaluator-GQYDOSGT.mjs +0 -1392
  182. package/dist/sdk/task-evaluator-GQYDOSGT.mjs.map +0 -1
  183. package/dist/sdk/teams-frontend-DNW5GZP3.mjs.map +0 -1
  184. package/dist/sdk/telegram-frontend-GA7OLADB.mjs.map +0 -1
  185. package/dist/sdk/trace-helpers-26ZCAE2V.mjs.map +0 -1
  186. package/dist/sdk/trace-helpers-XV5GAX5L.mjs +0 -29
  187. package/dist/sdk/trace-helpers-XV5GAX5L.mjs.map +0 -1
  188. package/dist/sdk/trace-serializer-KKBJHM7J.mjs.map +0 -1
  189. package/dist/sdk/track-execution-3EC24C2X.mjs +0 -163
  190. package/dist/sdk/track-execution-3EC24C2X.mjs.map +0 -1
  191. package/dist/sdk/track-execution-66RLL6QT.mjs +0 -143
  192. package/dist/sdk/track-execution-66RLL6QT.mjs.map +0 -1
  193. package/dist/sdk/utcp-check-provider-JLIYF5HH.mjs +0 -16
  194. package/dist/sdk/utcp-check-provider-JLIYF5HH.mjs.map +0 -1
  195. package/dist/sdk/utcp-check-provider-WI3QZ3W6.mjs.map +0 -1
  196. package/dist/sdk/workflow-check-provider-X2UREEH7.mjs +0 -31
  197. package/dist/sdk/workflow-check-provider-X2UREEH7.mjs.map +0 -1
  198. package/dist/sdk/workflow-check-provider-YXALZNAQ.mjs +0 -31
  199. package/dist/sdk/workflow-check-provider-YXALZNAQ.mjs.map +0 -1
  200. package/dist/sdk/workflow-registry-X2IPY35M.mjs +0 -12
  201. package/dist/sdk/workflow-registry-X2IPY35M.mjs.map +0 -1
  202. package/dist/sdk/workflow-registry-YCZ3FCJC.mjs.map +0 -1
  203. /package/dist/sdk/{a2a-frontend-5YDHFQXD.mjs.map → a2a-frontend-OI4OVSKC.mjs.map} +0 -0
  204. /package/dist/sdk/{check-provider-registry-WSEVHJEV.mjs.map → check-provider-registry-RITJW67U.mjs.map} +0 -0
  205. /package/dist/sdk/{check-provider-registry-YRADEEQY.mjs.map → check-provider-registry-ZZ6N4GDP.mjs.map} +0 -0
  206. /package/dist/sdk/{chunk-4BN2XI4X.mjs.map → chunk-4HIWZA6M.mjs.map} +0 -0
  207. /package/dist/sdk/{chunk-RI4ONH5X.mjs.map → chunk-4MHHELVZ.mjs.map} +0 -0
  208. /package/dist/sdk/{chunk-54KOAC4W.mjs.map → chunk-4ZLYHSN4.mjs.map} +0 -0
  209. /package/dist/sdk/{chunk-GA2TYKSR.mjs.map → chunk-7XKHFRPN.mjs.map} +0 -0
  210. /package/dist/sdk/{chunk-XOAEKFKB.mjs.map → chunk-QLT42TX7.mjs.map} +0 -0
  211. /package/dist/sdk/{chunk-7XRSCOKE.mjs.map → chunk-TSX3YS3F.mjs.map} +0 -0
  212. /package/dist/sdk/{chunk-NPSLGKXB.mjs.map → chunk-UM7LGO2P.mjs.map} +0 -0
  213. /package/dist/sdk/{chunk-7VTZDC2X.mjs.map → chunk-VPPBOKBQ.mjs.map} +0 -0
  214. /package/dist/sdk/{chunk-RHKPFJLG.mjs.map → chunk-ZNKL6ESZ.mjs.map} +0 -0
  215. /package/dist/sdk/{command-executor-3AHGIYQG.mjs.map → command-executor-LHUW77GR.mjs.map} +0 -0
  216. /package/dist/sdk/{command-executor-YNJOS77A.mjs.map → config-TVU5RWR5.mjs.map} +0 -0
  217. /package/dist/sdk/{email-frontend-WSNADJPI.mjs.map → email-frontend-ECHQCFTR.mjs.map} +0 -0
  218. /package/dist/sdk/{config-JE4HKTWW.mjs.map → failure-condition-evaluator-USY3ISVA.mjs.map} +0 -0
  219. /package/dist/sdk/{github-auth-27SZGPEC.mjs.map → github-auth-UO4DMNCC.mjs.map} +0 -0
  220. /package/dist/sdk/{github-frontend-DECYOBRN.mjs.map → github-frontend-2T5PWYD5.mjs.map} +0 -0
  221. /package/dist/sdk/{host-CFM2ASDI.mjs.map → host-OJSMCLKK.mjs.map} +0 -0
  222. /package/dist/sdk/{host-T4LNVU2H.mjs.map → host-RM6UJEPP.mjs.map} +0 -0
  223. /package/dist/sdk/{knex-store-OEWSZEBY.mjs.map → knex-store-KCMFAMH5.mjs.map} +0 -0
  224. /package/dist/sdk/{config-PCP6O6Y6.mjs.map → liquid-extensions-KZIRR4OY.mjs.map} +0 -0
  225. /package/dist/sdk/{loader-WRGI244P.mjs.map → loader-35YWX5UQ.mjs.map} +0 -0
  226. /package/dist/sdk/{failure-condition-evaluator-H3PBFBYT.mjs.map → memory-store-3JONK7AF.mjs.map} +0 -0
  227. /package/dist/sdk/{opa-policy-engine-IVMCGVNA.mjs.map → opa-policy-engine-FY5D45YS.mjs.map} +0 -0
  228. /package/dist/sdk/{failure-condition-evaluator-IRFKTYZD.mjs.map → prompt-state-VVJMONT3.mjs.map} +0 -0
  229. /package/dist/sdk/{renderer-schema-BT2IXMLW.mjs.map → renderer-schema-JZRRU5CW.mjs.map} +0 -0
  230. /package/dist/sdk/{lazy-otel-5NH4ZJJM.mjs.map → routing-NNQQSLWA.mjs.map} +0 -0
  231. /package/dist/sdk/{liquid-extensions-E3AKRX7P.mjs.map → schedule-tool-ADZ2ON4I.mjs.map} +0 -0
  232. /package/dist/sdk/{liquid-extensions-P6KDYILF.mjs.map → schedule-tool-EMNF3FPQ.mjs.map} +0 -0
  233. /package/dist/sdk/{memory-store-K5N7MC7U.mjs.map → schedule-tool-handler-3R3IC6VA.mjs.map} +0 -0
  234. /package/dist/sdk/{memory-store-OHUIXCWJ.mjs.map → schedule-tool-handler-F76ZD2WU.mjs.map} +0 -0
  235. /package/dist/sdk/{task-evaluator-OVMG7S56.mjs.map → task-evaluator-H3BXC7SE.mjs.map} +0 -0
  236. /package/dist/sdk/{metrics-JTOG2HNO.mjs.map → trace-helpers-OMF4C24T.mjs.map} +0 -0
  237. /package/dist/sdk/{prompt-state-LN57DQF3.mjs.map → trace-serializer-EBHTHZYT.mjs.map} +0 -0
  238. /package/dist/sdk/{prompt-state-YPICX7PI.mjs.map → utcp-check-provider-Q4PD5EP2.mjs.map} +0 -0
  239. /package/dist/sdk/{routing-H2PQ57OA.mjs.map → workflow-check-provider-TC2G33WF.mjs.map} +0 -0
  240. /package/dist/sdk/{routing-JMZ7HDCC.mjs.map → workflow-check-provider-U4UXZ5YS.mjs.map} +0 -0
  241. /package/dist/sdk/{schedule-tool-2DPNSU63.mjs.map → workflow-registry-K56UTX36.mjs.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/agent-protocol/trace-serializer.ts","../../src/agent-protocol/task-evaluator.ts"],"sourcesContent":["/**\n * Trace serializer for LLM evaluation prompts and CLI display.\n *\n * Supports multiple trace backends:\n * 1. Grafana Tempo (via Grafana datasource proxy or direct Tempo API)\n * 2. Jaeger (via Jaeger HTTP API)\n * 3. Local NDJSON files (Visor's file-span-exporter OTEL format)\n *\n * Auto-detects the backend from environment variables:\n * - OTEL_EXPORTER_OTLP_ENDPOINT + VISOR_TELEMETRY_SINK=otlp → probe Grafana/Jaeger\n * - VISOR_TRACE_BACKEND=grafana|jaeger|file (explicit override)\n * - GRAFANA_URL, GRAFANA_TEMPO_DATASOURCE_ID → Grafana Tempo\n * - JAEGER_URL → Jaeger\n * - Falls back to local file scan\n */\n\nimport * as fs from 'fs';\nimport * as readline from 'readline';\nimport * as path from 'path';\nimport { logger } from '../logger';\n\n// ---------------------------------------------------------------------------\n// Trace backend configuration\n// ---------------------------------------------------------------------------\n\nexport interface TraceBackendConfig {\n type: 'grafana' | 'jaeger' | 'file' | 'auto';\n /** Grafana base URL, e.g. http://localhost:3000 */\n grafanaUrl?: string;\n /** Grafana Tempo datasource ID (default: auto-detect) */\n grafanaDatasourceId?: string | number;\n /** Jaeger base URL, e.g. http://localhost:16686 */\n jaegerUrl?: string;\n /** Local trace directory (default: output/traces) */\n traceDir?: string;\n /** Auth token for remote APIs */\n authToken?: string;\n}\n\nfunction resolveBackendConfig(overrides?: Partial<TraceBackendConfig>): TraceBackendConfig {\n const explicit = process.env.VISOR_TRACE_BACKEND as TraceBackendConfig['type'] | undefined;\n\n return {\n type: overrides?.type || explicit || 'auto',\n grafanaUrl: overrides?.grafanaUrl || process.env.GRAFANA_URL,\n grafanaDatasourceId: overrides?.grafanaDatasourceId || process.env.GRAFANA_TEMPO_DATASOURCE_ID,\n jaegerUrl: overrides?.jaegerUrl || process.env.JAEGER_URL,\n traceDir: overrides?.traceDir || process.env.VISOR_TRACE_DIR || 'output/traces',\n authToken: overrides?.authToken || process.env.GRAFANA_TOKEN,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Unified span type (normalized from all backends)\n// ---------------------------------------------------------------------------\n\ninterface NormalizedSpan {\n traceId: string;\n spanId: string;\n parentSpanId?: string;\n name: string;\n startTimeMs: number;\n endTimeMs: number;\n durationMs: number;\n attributes: Record<string, string | number | boolean>;\n events: Array<{ name: string; attributes: Record<string, string | number | boolean> }>;\n status: 'ok' | 'error';\n}\n\ninterface SpanTree {\n span: NormalizedSpan;\n children: SpanTree[];\n}\n\n// ---------------------------------------------------------------------------\n// OTLP response parsing (shared by Grafana Tempo and Jaeger)\n// ---------------------------------------------------------------------------\n\n/**\n * Parse OTLP JSON trace response (Tempo/Jaeger format) into normalized spans.\n * Format: { batches: [{ scopeSpans: [{ spans: [...] }] }] }\n * Jaeger variant: { data: [{ spans: [...] }] }\n */\nfunction parseOTLPResponse(data: any): NormalizedSpan[] {\n const spans: NormalizedSpan[] = [];\n\n // Grafana Tempo OTLP format\n if (data.batches) {\n for (const batch of data.batches) {\n for (const ss of batch.scopeSpans || []) {\n for (const s of ss.spans || []) {\n spans.push(normalizeOTLPSpan(s));\n }\n }\n }\n return spans;\n }\n\n // Jaeger native format\n if (data.data && Array.isArray(data.data)) {\n for (const trace of data.data) {\n for (const s of trace.spans || []) {\n spans.push(normalizeJaegerSpan(s, trace.traceID));\n }\n }\n return spans;\n }\n\n return spans;\n}\n\nfunction normalizeOTLPSpan(s: any): NormalizedSpan {\n const startNs = parseInt(s.startTimeUnixNano || '0', 10);\n const endNs = parseInt(s.endTimeUnixNano || '0', 10);\n\n // Decode base64 span/trace IDs if needed, or use hex strings\n const traceId = decodeOTLPId(s.traceId);\n const spanId = decodeOTLPId(s.spanId);\n const parentSpanId = s.parentSpanId ? decodeOTLPId(s.parentSpanId) : undefined;\n\n const attributes: Record<string, string | number | boolean> = {};\n for (const attr of s.attributes || []) {\n const val = attr.value;\n if (val.stringValue !== undefined) attributes[attr.key] = val.stringValue;\n else if (val.intValue !== undefined) attributes[attr.key] = parseInt(val.intValue, 10);\n else if (val.boolValue !== undefined) attributes[attr.key] = val.boolValue;\n else if (val.doubleValue !== undefined) attributes[attr.key] = val.doubleValue;\n }\n\n const events: NormalizedSpan['events'] = [];\n for (const evt of s.events || []) {\n const evtAttrs: Record<string, string | number | boolean> = {};\n for (const a of evt.attributes || []) {\n const v = a.value;\n if (v.stringValue !== undefined) evtAttrs[a.key] = v.stringValue;\n else if (v.intValue !== undefined) evtAttrs[a.key] = parseInt(v.intValue, 10);\n }\n events.push({ name: evt.name, attributes: evtAttrs });\n }\n\n return {\n traceId,\n spanId,\n parentSpanId,\n name: s.name || 'unknown',\n startTimeMs: startNs / 1e6,\n endTimeMs: endNs / 1e6,\n durationMs: (endNs - startNs) / 1e6,\n attributes,\n events,\n status: s.status?.code === 2 ? 'error' : 'ok',\n };\n}\n\nfunction normalizeJaegerSpan(s: any, traceId: string): NormalizedSpan {\n const attributes: Record<string, string | number | boolean> = {};\n for (const tag of s.tags || []) {\n attributes[tag.key] = tag.value;\n }\n\n const events: NormalizedSpan['events'] = [];\n for (const log of s.logs || []) {\n const evtAttrs: Record<string, string | number | boolean> = {};\n for (const f of log.fields || []) evtAttrs[f.key] = f.value;\n events.push({ name: (evtAttrs['event'] as string) || 'log', attributes: evtAttrs });\n }\n\n // Jaeger uses microseconds\n const startUs = s.startTime || 0;\n const durationUs = s.duration || 0;\n\n return {\n traceId,\n spanId: s.spanID,\n parentSpanId: s.references?.find((r: any) => r.refType === 'CHILD_OF')?.spanID,\n name: s.operationName || 'unknown',\n startTimeMs: startUs / 1000,\n endTimeMs: (startUs + durationUs) / 1000,\n durationMs: durationUs / 1000,\n attributes,\n events,\n status:\n attributes['otel.status_code'] === 'ERROR' || attributes['error'] === true ? 'error' : 'ok',\n };\n}\n\n/**\n * OTLP trace/span IDs may be base64-encoded. Decode to hex string.\n */\nfunction decodeOTLPId(id: string): string {\n if (!id) return '';\n // Already hex? (only hex chars)\n if (/^[0-9a-f]+$/i.test(id)) return id.toLowerCase();\n // Base64 → hex\n try {\n return Buffer.from(id, 'base64').toString('hex');\n } catch {\n return id;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Local NDJSON file parsing\n// ---------------------------------------------------------------------------\n\nfunction parseLocalNDJSONSpans(spans: any[]): NormalizedSpan[] {\n return spans.map(s => {\n const startMs = timeValueToMs(s.startTime || [0, 0]);\n const endMs = timeValueToMs(s.endTime || s.startTime || [0, 0]);\n const events: NormalizedSpan['events'] = (s.events || []).map((e: any) => ({\n name: e.name,\n attributes: e.attributes || {},\n }));\n\n return {\n traceId: s.traceId || '',\n spanId: s.spanId || '',\n parentSpanId: s.parentSpanId || undefined,\n name: s.name || 'unknown',\n startTimeMs: startMs,\n endTimeMs: endMs,\n durationMs: endMs - startMs,\n attributes: s.attributes || {},\n events,\n status: s.status?.code === 2 ? 'error' : 'ok',\n };\n });\n}\n\nfunction timeValueToMs(tv: [number, number]): number {\n return tv[0] * 1000 + tv[1] / 1e6;\n}\n\n// ---------------------------------------------------------------------------\n// Trace fetching — multi-backend\n// ---------------------------------------------------------------------------\n\n/**\n * Fetch trace spans by trace ID. Tries backends in order:\n * 1. Explicit backend (config.type)\n * 2. Grafana Tempo (auto-detect)\n * 3. Jaeger (auto-detect)\n * 4. Local NDJSON files\n */\nexport async function fetchTraceSpans(\n traceId: string,\n config?: Partial<TraceBackendConfig>\n): Promise<NormalizedSpan[]> {\n const cfg = resolveBackendConfig(config);\n\n const tryGrafana = cfg.type === 'grafana' || cfg.type === 'auto';\n const tryJaeger = cfg.type === 'jaeger' || cfg.type === 'auto';\n const tryFile = cfg.type === 'file' || cfg.type === 'auto';\n\n // 1. Grafana Tempo\n if (tryGrafana) {\n const spans = await fetchFromGrafanaTempo(traceId, cfg);\n if (spans && spans.length > 0) return spans;\n }\n\n // 2. Jaeger\n if (tryJaeger) {\n const spans = await fetchFromJaeger(traceId, cfg);\n if (spans && spans.length > 0) return spans;\n }\n\n // 3. Local files\n if (tryFile) {\n const spans = await fetchFromLocalFiles(traceId, cfg);\n if (spans && spans.length > 0) return spans;\n }\n\n return [];\n}\n\nasync function fetchFromGrafanaTempo(\n traceId: string,\n cfg: TraceBackendConfig\n): Promise<NormalizedSpan[] | null> {\n // Auto-detect Grafana URL from OTLP endpoint\n let grafanaUrl = cfg.grafanaUrl;\n if (!grafanaUrl) {\n const otlpEndpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;\n if (otlpEndpoint) {\n // Common pattern: OTLP on 4318, Grafana on 3000 or mapped port\n // Try common Grafana ports on same host\n const url = new URL(otlpEndpoint);\n const host = url.hostname;\n for (const port of ['3000', '8001', '80']) {\n try {\n const testUrl = `http://${host}:${port}/api/health`;\n const resp = await httpGet(testUrl, cfg.authToken, 2000);\n if (resp && resp.includes('\"database\"')) {\n grafanaUrl = `http://${host}:${port}`;\n break;\n }\n } catch {}\n }\n }\n }\n\n if (!grafanaUrl) return null;\n\n try {\n // Auto-detect Tempo datasource ID\n let dsId = cfg.grafanaDatasourceId;\n if (!dsId) {\n const dsResp = await httpGet(`${grafanaUrl}/api/datasources`, cfg.authToken);\n if (dsResp) {\n const datasources = JSON.parse(dsResp);\n const tempo = datasources.find((d: any) => d.type === 'tempo');\n if (tempo) dsId = tempo.id;\n }\n }\n if (!dsId) return null;\n\n const traceUrl = `${grafanaUrl}/api/datasources/proxy/${dsId}/api/traces/${traceId}`;\n const resp = await httpGet(traceUrl, cfg.authToken);\n if (!resp) return null;\n\n const data = JSON.parse(resp);\n return parseOTLPResponse(data);\n } catch (err) {\n logger.debug(`[TraceSerializer] Grafana Tempo fetch failed: ${err}`);\n return null;\n }\n}\n\nasync function fetchFromJaeger(\n traceId: string,\n cfg: TraceBackendConfig\n): Promise<NormalizedSpan[] | null> {\n let jaegerUrl = cfg.jaegerUrl;\n if (!jaegerUrl) {\n // Auto-detect: try common Jaeger ports on localhost\n const otlpEndpoint = process.env.OTEL_EXPORTER_OTLP_ENDPOINT;\n const host = otlpEndpoint ? new URL(otlpEndpoint).hostname : 'localhost';\n for (const port of ['16686']) {\n try {\n const testUrl = `http://${host}:${port}/api/services`;\n const resp = await httpGet(testUrl, undefined, 2000);\n if (resp && resp.includes('\"data\"')) {\n jaegerUrl = `http://${host}:${port}`;\n break;\n }\n } catch {}\n }\n }\n if (!jaegerUrl) return null;\n\n try {\n const traceUrl = `${jaegerUrl}/api/traces/${traceId}`;\n const resp = await httpGet(traceUrl, cfg.authToken);\n if (!resp) return null;\n\n const data = JSON.parse(resp);\n return parseOTLPResponse(data);\n } catch (err) {\n logger.debug(`[TraceSerializer] Jaeger fetch failed: ${err}`);\n return null;\n }\n}\n\nasync function fetchFromLocalFiles(\n traceId: string,\n cfg: TraceBackendConfig\n): Promise<NormalizedSpan[] | null> {\n const traceFile = await findTraceFile(traceId, cfg.traceDir);\n if (!traceFile) return null;\n\n try {\n const { parseNDJSONTrace } = await import('../debug-visualizer/trace-reader');\n const trace = await parseNDJSONTrace(traceFile);\n return parseLocalNDJSONSpans(trace.spans as any[]);\n } catch (err) {\n logger.debug(`[TraceSerializer] Local file parse failed: ${err}`);\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// HTTP helper\n// ---------------------------------------------------------------------------\n\nasync function httpGet(\n url: string,\n authToken?: string,\n timeoutMs?: number\n): Promise<string | null> {\n try {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), timeoutMs || 10000);\n\n const headers: Record<string, string> = {};\n if (authToken) headers['Authorization'] = `Bearer ${authToken}`;\n\n const resp = await fetch(url, {\n signal: controller.signal,\n headers,\n });\n clearTimeout(timeout);\n if (!resp.ok) return null;\n return await resp.text();\n } catch {\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Trace file discovery (local NDJSON files)\n// ---------------------------------------------------------------------------\n\n/**\n * Find the NDJSON trace file matching a given trace ID.\n * Scans the first line of each `.ndjson` file in the trace directory.\n */\nexport async function findTraceFile(traceId: string, traceDir?: string): Promise<string | null> {\n const dir = traceDir || process.env.VISOR_TRACE_DIR || 'output/traces';\n if (!fs.existsSync(dir)) return null;\n\n const files = fs.readdirSync(dir).filter(f => f.endsWith('.ndjson'));\n\n for (const file of files) {\n const filePath = path.join(dir, file);\n try {\n const firstLine = await readFirstLine(filePath);\n if (!firstLine) continue;\n const parsed = JSON.parse(firstLine);\n if (parsed.traceId === traceId) return filePath;\n } catch {\n // skip malformed files\n }\n }\n\n return null;\n}\n\nasync function readFirstLine(filePath: string): Promise<string | null> {\n return new Promise((resolve, reject) => {\n const stream = fs.createReadStream(filePath, { encoding: 'utf-8' });\n const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });\n let resolved = false;\n rl.on('line', (line: string) => {\n if (!resolved) {\n resolved = true;\n rl.close();\n stream.destroy();\n resolve(line.trim() || null);\n }\n });\n rl.on('close', () => {\n if (!resolved) resolve(null);\n });\n rl.on('error', reject);\n });\n}\n\n// ---------------------------------------------------------------------------\n// Noise filtering\n// ---------------------------------------------------------------------------\n\n/** Span names that are pure infrastructure noise and should be filtered out */\nconst NOISE_SPAN_NAMES = new Set([\n 'engine.state.init',\n 'engine.state.waveplanning',\n 'engine.state.planready',\n 'visor.sandbox.stopAll',\n]);\n\n/** Span names that are redundant wrappers — lift their children up */\nconst WRAPPER_SPAN_NAMES = new Set([\n 'engine.state.leveldispatch',\n 'visor.ai_check',\n 'probe.delegation',\n]);\n\nfunction isNoiseSpan(span: NormalizedSpan): boolean {\n return NOISE_SPAN_NAMES.has(span.name);\n}\n\nfunction isWrapperSpan(span: NormalizedSpan): boolean {\n return WRAPPER_SPAN_NAMES.has(span.name);\n}\n\n// ---------------------------------------------------------------------------\n// Build span tree from flat list (with noise filtering)\n// ---------------------------------------------------------------------------\n\nfunction buildSpanTree(spans: NormalizedSpan[]): SpanTree {\n // First filter out pure noise spans\n const filtered = spans.filter(s => !isNoiseSpan(s));\n\n const nodeMap = new Map<string, SpanTree>();\n\n // Create all nodes\n for (const span of filtered) {\n nodeMap.set(span.spanId, { span, children: [] });\n }\n\n // Build parent-child relationships\n let root: SpanTree | undefined;\n const orphans: SpanTree[] = [];\n for (const span of filtered) {\n const node = nodeMap.get(span.spanId)!;\n if (!span.parentSpanId) {\n root = node;\n } else {\n // Walk up to find nearest non-filtered ancestor\n let parentId: string | undefined = span.parentSpanId;\n while (parentId && !nodeMap.has(parentId)) {\n // Parent was filtered — find grandparent from original spans\n const parentSpan = spans.find(s => s.spanId === parentId);\n parentId = parentSpan?.parentSpanId;\n }\n if (parentId) {\n const parent = nodeMap.get(parentId);\n if (parent) parent.children.push(node);\n } else if (!root) {\n root = node;\n } else {\n // Orphaned span — parent not in this trace; attach to root later\n orphans.push(node);\n }\n }\n }\n\n // If no root found, pick the span with the longest duration\n if (!root) {\n const sorted = [...nodeMap.values()].sort((a, b) => b.span.durationMs - a.span.durationMs);\n root = sorted[0] || { span: filtered[0], children: [] };\n }\n\n // Attach orphaned spans to root so they appear in the tree\n if (orphans.length > 0) {\n root.children.push(...orphans);\n }\n\n // Sort children by start time\n const sortChildren = (node: SpanTree) => {\n node.children.sort((a, b) => a.span.startTimeMs - b.span.startTimeMs);\n node.children.forEach(sortChildren);\n };\n sortChildren(root);\n\n // Unwrap wrapper spans — lift children up and discard the wrapper\n const unwrap = (node: SpanTree): SpanTree => {\n // Recursively process children first\n node.children = node.children.map(unwrap);\n\n // Flatten: replace wrapper children with their children\n const newChildren: SpanTree[] = [];\n for (const child of node.children) {\n if (isWrapperSpan(child.span)) {\n // Lift grandchildren up\n newChildren.push(...child.children);\n } else {\n newChildren.push(child);\n }\n }\n node.children = newChildren;\n return node;\n };\n unwrap(root);\n\n // Remove redundant probe.event.tool.result spans that are siblings of\n // search.delegate spans — these are aggregate results echoed back to the\n // parent AI and duplicate info already shown inside the delegate subtree\n const removeDelegateEchos = (node: SpanTree): void => {\n const hasDelegateChild = node.children.some(c => c.span.name === 'search.delegate');\n if (hasDelegateChild) {\n node.children = node.children.filter(c => {\n if (c.span.name !== 'probe.event.tool.result') return true;\n const toolName = c.span.attributes['tool.name'];\n // Remove search echoes — their details are inside search.delegate\n return toolName !== 'search';\n });\n }\n node.children.forEach(removeDelegateEchos);\n };\n removeDelegateEchos(root);\n\n return root;\n}\n\n// ---------------------------------------------------------------------------\n// Compact tree rendering\n// ---------------------------------------------------------------------------\n\nexport interface RenderTreeOptions {\n maxDepth?: number;\n maxChars?: number;\n /** Fallback intent text for AI spans whose input is too truncated */\n fallbackIntent?: string;\n /** When true, don't truncate output/intent previews */\n fullOutput?: boolean;\n /** Final task response from the task store (full, not OTEL-truncated) */\n taskResponse?: string;\n}\n\n/**\n * Tracks displayed outputs and intents to avoid repeating the same text.\n * When a duplicate is detected, shows \"= <first-span-name>\" instead.\n */\ninterface DeduplicationContext {\n /** Map from normalized output prefix → span name that first displayed it */\n outputs: Map<string, string>;\n /** Map from normalized intent prefix → span name that first displayed it */\n intents: Map<string, string>;\n}\n\n/** Normalize text for dedup comparison: lowercase, collapse whitespace, take prefix */\nfunction dedupeKey(text: string): string {\n return text.replace(/\\s+/g, ' ').trim().slice(0, 100).toLowerCase();\n}\n\n/** Check if text was already displayed; if so return the reference name. Otherwise register it. */\nfunction dedupeOrRegister(\n ctx: DeduplicationContext,\n kind: 'outputs' | 'intents',\n text: string,\n spanName: string\n): string | null {\n if (!text || text.length < 20) return null;\n const key = dedupeKey(text);\n if (!key) return null;\n const map = ctx[kind];\n const existing = map.get(key);\n if (existing && existing !== spanName) {\n return existing;\n }\n // Cross-check: intents against outputs and vice versa\n const otherMap = kind === 'outputs' ? ctx.intents : ctx.outputs;\n const crossRef = otherMap.get(key);\n if (crossRef && crossRef !== spanName) {\n map.set(key, spanName);\n return crossRef;\n }\n map.set(key, spanName);\n return null;\n}\n\n/**\n * Serialize a trace (by ID) into a compact text tree for LLM prompts.\n * Auto-detects the backend (Grafana Tempo, Jaeger, local files).\n */\nexport async function serializeTraceForPrompt(\n traceIdOrPath: string,\n maxChars?: number,\n backendConfig?: Partial<TraceBackendConfig>,\n /** Final task response from the task store (not truncated by OTEL) */\n taskResponse?: string,\n /** Trace ID to try remote backends first (preferred over local file) */\n fallbackTraceId?: string\n): Promise<string> {\n let spans: NormalizedSpan[] = [];\n const isFilePath = traceIdOrPath.includes('/') || traceIdOrPath.endsWith('.ndjson');\n\n // Always try remote backends first (Grafana Tempo, Jaeger) — they have\n // full span structure with IDs, timestamps, and parent-child relationships.\n // The local NDJSON fallback file only has minimal event markers.\n const remoteTraceId = fallbackTraceId || (!isFilePath ? traceIdOrPath : undefined);\n if (remoteTraceId) {\n spans = await fetchTraceSpans(remoteTraceId, backendConfig);\n }\n\n // Fall back to local file only when remote returned nothing\n if (spans.length === 0 && isFilePath) {\n try {\n const { parseNDJSONTrace } = await import('../debug-visualizer/trace-reader');\n const trace = await parseNDJSONTrace(traceIdOrPath);\n spans = parseLocalNDJSONSpans(trace.spans as any[]);\n } catch {\n // file may not exist or be malformed\n }\n }\n\n // Last resort: if traceIdOrPath wasn't tried as a trace ID yet, try it\n if (spans.length === 0 && !remoteTraceId && !isFilePath) {\n spans = await fetchTraceSpans(traceIdOrPath, backendConfig);\n }\n\n if (spans.length === 0) {\n return '(no trace data available)';\n }\n\n const tree = buildSpanTree(spans);\n\n // Extract the route-intent topic as a global fallback for AI intent\n const routeIntentTopic = extractRouteIntentTopic(spans);\n\n // maxChars > 100k signals \"full\" mode (no truncation of previews)\n const fullOutput = (maxChars ?? 4000) > 100000;\n\n return renderSpanYaml(tree, spans, {\n maxChars: maxChars ?? 4000,\n fallbackIntent: routeIntentTopic,\n fullOutput,\n taskResponse,\n });\n}\n\n/**\n * Render a span tree as a compact ASCII tree with durations and details.\n */\nexport function renderSpanTree(tree: SpanTree, opts?: RenderTreeOptions): string {\n const maxChars = opts?.maxChars ?? 4000;\n const maxDepth = opts?.maxDepth ?? 20;\n const lines: string[] = [];\n\n const dedup: DeduplicationContext = { outputs: new Map(), intents: new Map() };\n renderNode(\n tree,\n '',\n true,\n 0,\n maxDepth,\n lines,\n undefined,\n opts?.fallbackIntent,\n opts?.fullOutput,\n dedup\n );\n\n let result = lines.join('\\n');\n if (result.length > maxChars) {\n result = result.slice(0, maxChars - 20) + '\\n... (truncated)';\n }\n return result;\n}\n\n// Keep backward compat — renderTraceTree delegates to renderSpanTree with adapter\nexport function renderTraceTree(\n tree: any, // ExecutionNode from trace-reader\n opts?: RenderTreeOptions\n): string {\n // Convert ExecutionNode tree to SpanTree\n const convert = (node: any): SpanTree => ({\n span: {\n traceId: node.span?.traceId || '',\n spanId: node.span?.spanId || '',\n parentSpanId: node.span?.parentSpanId,\n name: node.span?.name || node.checkId || 'unknown',\n startTimeMs: timeValueToMs(node.span?.startTime || [0, 0]),\n endTimeMs: timeValueToMs(node.span?.endTime || [0, 0]),\n durationMs: node.span?.duration || 0,\n attributes: node.span?.attributes || {},\n events: (node.span?.events || []).map((e: any) => ({\n name: e.name,\n attributes: e.attributes || {},\n })),\n status: node.status === 'error' ? 'error' : 'ok',\n },\n children: (node.children || []).map(convert),\n });\n return renderSpanTree(convert(tree), opts);\n}\n\n// ---------------------------------------------------------------------------\n// YAML-based renderer\n// ---------------------------------------------------------------------------\n\n/**\n * Render a span tree as YAML-like structured output.\n * More readable than ASCII tree for JSON inputs/outputs.\n */\nexport function renderSpanYaml(\n tree: SpanTree,\n allSpans: NormalizedSpan[],\n opts?: RenderTreeOptions\n): string {\n const fullOutput = opts?.fullOutput ?? false;\n const maxLen = fullOutput ? 100000 : 120;\n const dedup: DeduplicationContext = { outputs: new Map(), intents: new Map() };\n const lines: string[] = [];\n\n renderYamlNode(tree, 0, lines, dedup, opts?.fallbackIntent, fullOutput, maxLen);\n\n // Append the final task response from the task store (not OTEL-truncated)\n if (opts?.taskResponse) {\n // Remove any trailing dedup line like \"output: = generate-response\"\n while (lines.length > 0 && /^\\s*output:\\s*=\\s*\\S+/.test(lines[lines.length - 1])) {\n lines.pop();\n }\n const ml = fullOutput ? 100000 : 500;\n const text = opts.taskResponse.replace(/\\*\\*/g, '').replace(/`/g, '').trim();\n if (fullOutput) {\n lines.push(' response: |');\n for (const line of text.split('\\n')) {\n lines.push(` ${line}`);\n }\n } else {\n const truncated = truncate(text.replace(/\\n/g, ' '), ml);\n lines.push(` response: ${truncated}`);\n if (text.length > ml) {\n lines.push(' # use --full for complete response');\n }\n }\n }\n\n return lines.join('\\n');\n}\n\nfunction renderYamlNode(\n node: SpanTree,\n indent: number,\n lines: string[],\n dedup: DeduplicationContext,\n fallbackIntent?: string,\n fullOutput?: boolean,\n maxLen?: number,\n parentSpan?: NormalizedSpan\n): void {\n const pad = ' '.repeat(indent);\n const attrs = node.span.attributes;\n const duration = formatDurationMs(node.span.durationMs);\n const name = node.span.name;\n const ml = maxLen ?? 120;\n\n // Helper: get display name — for AI spans, use parent check name\n const parentCheckId = parentSpan?.attributes['visor.check.id'];\n const parentCheckName = parentCheckId\n ? String(parentCheckId).replace(/^visor\\.check\\./, '')\n : undefined;\n const displayName =\n name === 'ai.request' && parentCheckName\n ? parentCheckName\n : String(attrs['visor.check.id'] || name).replace(/^visor\\.check\\./, '');\n\n // --- Tool calls ---\n const toolName = attrs['tool.name'] || attrs['visor.tool.name'];\n if (toolName) {\n const toolInput = extractToolInput(String(toolName), attrs);\n const toolResultLen = attrs['tool.result.length'] || attrs['tool.result.count'];\n const tn = String(toolName);\n // Detect \"no results\" for search tools: probe header is ~350-450 chars,\n // so result.length < 500 for search means no actual matches\n const isSearchTool = tn === 'search' || tn === 'searchCode' || tn === 'search_code';\n const numLen = toolResultLen ? Number(toolResultLen) : -1;\n const noResults = isSearchTool && numLen >= 0 && numLen < 500;\n const resultSize = noResults\n ? ' → no results'\n : toolResultLen\n ? ` → ${formatSize(numLen)}`\n : '';\n const successMark = attrs['tool.success'] === false ? ' ✗' : '';\n lines.push(`${pad}- ${tn}(${toolInput})${resultSize}${successMark}`);\n return;\n }\n\n // --- Search delegate dedup decision ---\n if (name === 'search.delegate.dedup') {\n const query = attrs['dedup.query'] || '';\n const action = attrs['dedup.action'] || '?';\n const reason = attrs['dedup.reason'] || '';\n const rewritten = attrs['dedup.rewritten'] || '';\n const prevCount = attrs['dedup.previous_count'] || '0';\n let detail = `${action}`;\n if (rewritten) detail += ` → \"${truncate(String(rewritten), 60)}\"`;\n if (reason) detail += ` (${truncate(String(reason), 80)})`;\n lines.push(\n `${pad}dedup(\"${truncate(String(query), 60)}\") [${prevCount} prior]: ${detail} — ${duration}`\n );\n return;\n }\n\n // --- Search delegate ---\n if (name === 'search.delegate') {\n const query = attrs['search.query'] || '';\n const rewritten = attrs['search.query.rewritten'] || '';\n const output = attrs['search.delegate.output'] || '';\n const outputLen = attrs['search.delegate.output_length'] || '';\n\n let header = `search.delegate(\"${truncate(String(query), 80)}\")`;\n if (rewritten) header += ` → rewritten: \"${truncate(String(rewritten), 60)}\"`;\n header += ` — ${duration}`;\n lines.push(`${pad}${header}:`);\n\n // Parse structured output to show confidence, searches, and groups summary\n if (output) {\n try {\n const parsed = JSON.parse(String(output));\n if (parsed.confidence) {\n let confLine = `confidence: ${parsed.confidence}`;\n if (parsed.reason) confLine += ` — ${truncate(String(parsed.reason), 100)}`;\n lines.push(`${pad} ${confLine}`);\n }\n if (parsed.searches && Array.isArray(parsed.searches) && parsed.searches.length > 0) {\n lines.push(`${pad} searches (${parsed.searches.length}):`);\n for (const s of parsed.searches) {\n const outcome = s.had_results ? '✓' : '✗';\n lines.push(\n `${pad} ${outcome} \"${truncate(String(s.query || ''), 60)}\" in ${truncate(String(s.path || '.'), 40)}`\n );\n }\n }\n if (parsed.groups && Array.isArray(parsed.groups) && parsed.groups.length > 0) {\n lines.push(`${pad} groups (${parsed.groups.length}):`);\n for (const g of parsed.groups) {\n const fileCount = g.files?.length || 0;\n lines.push(`${pad} - ${truncate(String(g.reason || ''), 80)} (${fileCount} files)`);\n }\n }\n } catch {\n // Not JSON — show raw output length\n if (outputLen) lines.push(`${pad} output: ${outputLen} chars`);\n }\n }\n\n for (const child of node.children) {\n renderYamlNode(\n child,\n indent + 1,\n lines,\n dedup,\n fallbackIntent,\n fullOutput,\n maxLen,\n node.span\n );\n }\n return;\n }\n\n // --- AI request ---\n if (name === 'ai.request') {\n const model = attrs['ai.model'] || attrs['gen_ai.request.model'] || '?';\n const tokensIn = attrs['ai.input_length'] || attrs['gen_ai.usage.input_tokens'] || '';\n const tokensOut = attrs['gen_ai.usage.output_tokens'] || '';\n const tokenParts: string[] = [];\n if (tokensIn) tokenParts.push(`${tokensIn} in`);\n if (tokensOut) tokenParts.push(`${tokensOut} out`);\n const tokenStr = tokenParts.length > 0 ? ` — ${tokenParts.join(', ')}` : '';\n\n const hasChildren = node.children.length > 0;\n lines.push(`${pad}ai: ${model} — ${duration}${tokenStr}${hasChildren ? ':' : ''}`);\n\n // Intent\n const aiInput = String(attrs['ai.input'] || '');\n let intent = extractAIIntent(aiInput, ml);\n if (!intent && parentSpan) {\n const promptPreview = String(\n parentSpan.attributes['visor.provider.request.prompt.preview'] || ''\n );\n if (promptPreview) intent = extractAIIntent(promptPreview, ml);\n if (!intent) {\n const inputOutputs = String(parentSpan.attributes['visor.check.input.outputs'] || '');\n if (inputOutputs) {\n try {\n const o = JSON.parse(inputOutputs);\n const t = o['route-intent']?.topic;\n if (t) intent = truncate(String(t), ml);\n } catch {}\n }\n }\n }\n if (!intent && fallbackIntent && parentSpan?.name !== 'search.delegate') {\n intent = fallbackIntent;\n }\n if (intent) {\n const intentRef = dedupeOrRegister(dedup, 'intents', intent, displayName);\n if (intentRef) {\n lines.push(`${pad} intent: = ${intentRef}`);\n } else {\n lines.push(`${pad} intent: ${intent}`);\n }\n }\n\n // Children (tool calls etc.)\n for (const child of node.children) {\n renderYamlNode(\n child,\n indent + 1,\n lines,\n dedup,\n fallbackIntent,\n fullOutput,\n maxLen,\n node.span\n );\n }\n\n // Output from parent check span (AI provider stores output on the check span, not ai.request)\n if (parentSpan) {\n const checkOutput = String(parentSpan.attributes['visor.check.output'] || '');\n if (checkOutput) {\n renderYamlOutput(\n checkOutput,\n `${pad} `,\n 'output',\n displayName,\n dedup,\n lines,\n fullOutput,\n ml\n );\n }\n }\n return;\n }\n\n // --- visor.run ---\n if (name === 'visor.run') {\n const source = attrs['visor.run.source'] || '';\n const visorVersion = attrs['visor.version'] || '';\n const probeVersion = attrs['probe.version'] || '';\n const slackUser = attrs['slack.user_id'] || '';\n lines.push(`${pad}visor.run:`);\n lines.push(`${pad} trace_id: ${node.span.traceId}`);\n if (visorVersion) lines.push(`${pad} visor: ${visorVersion}`);\n if (probeVersion) lines.push(`${pad} probe: ${probeVersion}`);\n if (source) lines.push(`${pad} source: ${source}`);\n if (slackUser) lines.push(`${pad} slack_user: ${slackUser}`);\n lines.push(`${pad} duration: ${duration}`);\n for (const child of node.children) {\n renderYamlNode(\n child,\n indent + 1,\n lines,\n dedup,\n fallbackIntent,\n fullOutput,\n maxLen,\n node.span\n );\n }\n return;\n }\n\n // --- Visor check ---\n const checkId = attrs['visor.check.id'];\n const checkType = attrs['visor.check.type'];\n if (checkId || name.startsWith('visor.check.')) {\n const cleanName = String(checkId || name).replace(/^visor\\.check\\./, '');\n const errMark = node.span.status === 'error' ? ' ✗' : '';\n lines.push(`${pad}${cleanName}:${errMark}`);\n if (checkType) lines.push(`${pad} type: ${checkType}`);\n lines.push(`${pad} duration: ${duration}`);\n\n // Input — show the actual question/topic first, then dependency outputs\n const inputContext = String(attrs['visor.check.input.context'] || '');\n const inputOutputs = String(attrs['visor.check.input.outputs'] || '');\n const question = extractQuestionFromContext(inputContext, inputOutputs);\n if (question || (inputOutputs && inputOutputs !== '{}')) {\n renderYamlInput(inputOutputs, `${pad} `, lines, fullOutput, ml, question);\n }\n\n // Children\n for (const child of node.children) {\n renderYamlNode(\n child,\n indent + 1,\n lines,\n dedup,\n fallbackIntent,\n fullOutput,\n maxLen,\n node.span\n );\n }\n\n // Output (after children)\n // Skip if check has a direct AI child — it already rendered this check's output\n const hasDirectAiChild = node.children.some(c => c.span.name === 'ai.request');\n if (!hasDirectAiChild) {\n const output = String(attrs['visor.check.output'] || '');\n if (output) {\n renderYamlOutput(output, `${pad} `, 'output', cleanName, dedup, lines, fullOutput, ml);\n }\n }\n return;\n }\n\n // --- Generic span ---\n const errMark = node.span.status === 'error' ? ' ✗' : '';\n const hasChildren = node.children.length > 0;\n lines.push(`${pad}${name} — ${duration}${errMark}${hasChildren ? ':' : ''}`);\n for (const child of node.children) {\n renderYamlNode(child, indent + 1, lines, dedup, fallbackIntent, fullOutput, maxLen, node.span);\n }\n}\n\n/**\n * Render a JSON output as YAML key-value pairs under a given prefix.\n * Handles deduplication — if the output was already shown, prints \"output: = <name>\".\n */\nfunction renderYamlOutput(\n rawOutput: string,\n pad: string,\n label: string,\n spanName: string,\n dedup: DeduplicationContext,\n lines: string[],\n fullOutput?: boolean,\n maxLen?: number\n): void {\n const ml = maxLen ?? 120;\n\n // Try to parse as JSON for structured display\n let obj: any;\n try {\n obj = JSON.parse(rawOutput);\n } catch {\n // Truncated JSON — use tolerant parser to extract what we can\n obj = parseTruncatedJson(rawOutput);\n }\n if (obj === null || obj === undefined || typeof obj !== 'object') return;\n\n // Unwrap single-key wrapper objects: {answer: {text: \"...\"}} → {text: \"...\"}\n // and {text: \"...\"} → render text inline\n if (typeof obj === 'object' && !Array.isArray(obj)) {\n const keys = Object.keys(obj);\n if (keys.length === 1 && typeof obj[keys[0]] === 'object' && obj[keys[0]] !== null) {\n obj = obj[keys[0]]; // unwrap {answer: {...}} → {...}\n }\n // If single text key, render inline\n const objKeys = Object.keys(obj);\n if (objKeys.length === 1 && objKeys[0] === 'text' && typeof obj.text === 'string') {\n const text = obj.text.replace(/\\*\\*/g, '').replace(/`/g, '').trim();\n const flat = text.replace(/\\n/g, ' ');\n const preview2 = fullOutput ? flat : truncate(flat, ml);\n const ref2 = dedupeOrRegister(dedup, 'outputs', truncate(flat, 100), spanName);\n if (ref2) {\n lines.push(`${pad}${label}: = ${ref2}`);\n } else {\n lines.push(`${pad}${label}: ${preview2}`);\n }\n return;\n }\n }\n\n // Get a dedup key from the formatted preview\n const preview = formatJsonPreview(obj, 200);\n if (!preview) return;\n const ref = dedupeOrRegister(dedup, 'outputs', preview, spanName);\n if (ref) {\n lines.push(`${pad}${label}: = ${ref}`);\n return;\n }\n\n // Render as YAML structure\n renderYamlValue(obj, pad, label, lines, fullOutput, ml);\n}\n\n/**\n * Render a JSON value as YAML structure.\n */\nfunction renderYamlValue(\n val: any,\n pad: string,\n key: string,\n lines: string[],\n fullOutput?: boolean,\n maxLen?: number,\n depth?: number\n): void {\n const ml = maxLen ?? 120;\n const d = depth ?? 0;\n\n if (val === null || val === undefined) return;\n\n if (typeof val === 'boolean' || typeof val === 'number') {\n lines.push(`${pad}${key}: ${val}`);\n return;\n }\n\n if (typeof val === 'string') {\n // Skip stringified JSON\n if (val.startsWith('{') || val.startsWith('[')) return;\n const clean = val.replace(/\\*\\*/g, '').replace(/`/g, '').trim();\n if (fullOutput && clean.length > 100 && clean.includes('\\n')) {\n // Multiline YAML\n lines.push(`${pad}${key}: |`);\n for (const line of clean.split('\\n').slice(0, fullOutput ? 500 : 5)) {\n lines.push(`${pad} ${line}`);\n }\n } else {\n const flat = clean.replace(/\\n/g, ' ');\n const truncVal = fullOutput ? flat : truncate(flat, ml);\n lines.push(`${pad}${key}: ${truncVal}`);\n }\n return;\n }\n\n if (Array.isArray(val)) {\n if (val.length === 0) {\n lines.push(`${pad}${key}: []`);\n return;\n }\n // Short string arrays: render inline like [a, b, c]\n if (val.every((v: any) => typeof v === 'string') && val.join(', ').length < ml) {\n lines.push(`${pad}${key}: [${val.join(', ')}]`);\n return;\n }\n // Limit array depth\n const maxItems = fullOutput ? 20 : 3;\n lines.push(`${pad}${key}:`);\n for (let i = 0; i < Math.min(val.length, maxItems); i++) {\n const item = val[i];\n if (typeof item === 'object' && item !== null) {\n const entries = Object.entries(item).filter(([k]) => k !== 'raw' && k !== 'tags');\n if (entries.length > 0) {\n // Put first key on same line as dash\n const [firstKey, firstVal] = entries[0];\n if (firstVal === null || firstVal === undefined || typeof firstVal !== 'object') {\n const sv =\n typeof firstVal === 'string'\n ? fullOutput\n ? firstVal.split('\\n')[0]\n : truncate(firstVal.split('\\n')[0], ml)\n : String(firstVal ?? '');\n lines.push(`${pad} - ${firstKey}: ${sv}`);\n } else {\n // Complex first value — render key on dash line, value below\n lines.push(`${pad} - ${firstKey}:`);\n for (const [ck, cv] of Object.entries(firstVal)) {\n if (ck === 'raw' || ck === 'skills' || ck === 'tags') continue;\n renderYamlValue(cv, `${pad} `, ck, lines, fullOutput, ml, d + 2);\n }\n }\n for (let j = 1; j < entries.length; j++) {\n const [k, v] = entries[j];\n renderYamlValue(v, `${pad} `, k, lines, fullOutput, ml, d + 1);\n }\n }\n } else {\n lines.push(`${pad} - ${truncate(String(item), ml)}`);\n }\n }\n if (val.length > maxItems) {\n lines.push(`${pad} # ... ${val.length - maxItems} more`);\n }\n return;\n }\n\n if (typeof val === 'object') {\n // Limit nesting depth\n if (d > 3) {\n const keys = Object.keys(val);\n lines.push(`${pad}${key}: {${keys.slice(0, 4).join(', ')}${keys.length > 4 ? ', ...' : ''}}`);\n return;\n }\n lines.push(`${pad}${key}:`);\n for (const [k, v] of Object.entries(val)) {\n if (k === 'raw' || k === 'tags') continue;\n renderYamlValue(v, `${pad} `, k, lines, fullOutput, ml, d + 1);\n }\n }\n}\n\n/**\n * Extract the actual user question/topic from the check's input context.\n * The context contains the full execution context including outputs from\n * dependency checks. We look for the route-intent topic, args.topic, or\n * other indicators of the user's question.\n */\nfunction extractQuestionFromContext(\n contextStr: string,\n inputOutputsStr: string\n): string | undefined {\n if (!contextStr) return undefined;\n\n try {\n const ctx = JSON.parse(contextStr);\n\n // 1. Check outputs.route-intent.topic (most common)\n const outputs = ctx.outputs || {};\n const routeIntent = outputs['route-intent'];\n if (routeIntent) {\n const topic = routeIntent.topic || routeIntent.intent || routeIntent.question;\n if (topic && typeof topic === 'string') return topic;\n // route-intent might be a string itself\n if (typeof routeIntent === 'string') return routeIntent;\n }\n\n // 2. Check args.topic or args.question\n const args = ctx.args || {};\n if (args.topic && typeof args.topic === 'string') return args.topic;\n if (args.question && typeof args.question === 'string') return args.question;\n if (args.intent && typeof args.intent === 'string') return args.intent;\n\n // 3. Check any output with a topic field not already in inputOutputs\n for (const key of Object.keys(outputs)) {\n const val = outputs[key];\n if (typeof val === 'object' && val !== null) {\n if (val.topic && typeof val.topic === 'string') {\n // Skip if this output is already shown in inputOutputs\n try {\n const depOutputs = JSON.parse(inputOutputsStr);\n if (depOutputs[key]) continue;\n } catch {}\n return val.topic;\n }\n }\n }\n } catch {\n // Truncated JSON — try regex extraction\n const topicMatch = contextStr.match(/\"topic\"\\s*:\\s*\"([^\"]+)\"/);\n if (topicMatch) return topicMatch[1];\n }\n\n return undefined;\n}\n\n/**\n * Render input dependencies as YAML.\n */\nfunction renderYamlInput(\n inputOutputsStr: string,\n pad: string,\n lines: string[],\n fullOutput?: boolean,\n maxLen?: number,\n question?: string\n): void {\n const ml = maxLen ?? 120;\n\n // Show the question/topic prominently first\n if (question) {\n lines.push(`${pad}input: ${truncate(question, fullOutput ? 100000 : ml)}`);\n }\n\n try {\n const inputs = JSON.parse(inputOutputsStr);\n if (typeof inputs !== 'object' || inputs === null) return;\n const keys = Object.keys(inputs);\n if (keys.length === 0) return;\n\n if (!question) lines.push(`${pad}input:`);\n for (const key of keys) {\n const val = inputs[key];\n if (typeof val === 'object' && val !== null) {\n renderYamlValue(val, `${pad} `, key, lines, fullOutput, ml, 0);\n } else {\n lines.push(`${pad} ${key}: ${truncate(String(val), ml)}`);\n }\n }\n } catch {\n // Can't parse — skip\n }\n}\n\n// ---------------------------------------------------------------------------\n// ASCII tree renderer (kept for backward compat / tests)\n// ---------------------------------------------------------------------------\n\nfunction renderNode(\n node: SpanTree,\n prefix: string,\n isLast: boolean,\n depth: number,\n maxDepth: number,\n lines: string[],\n parentSpan?: NormalizedSpan,\n fallbackIntent?: string,\n fullOutput?: boolean,\n dedup?: DeduplicationContext\n): void {\n if (depth > maxDepth) return;\n\n const hasChildren = node.children.length > 0;\n const connector = depth === 0 ? '' : isLast ? '└── ' : '├── ';\n const { line: formatted, output: deferredOutput } = formatSpanLine(\n node.span,\n parentSpan,\n fallbackIntent,\n fullOutput,\n dedup,\n hasChildren\n );\n\n // Skip if formatSpanLine returns empty (filtered)\n if (formatted) {\n lines.push(`${prefix}${connector}${formatted}`);\n }\n\n const childPrefix = depth === 0 ? '' : formatted ? prefix + (isLast ? ' ' : '│ ') : prefix; // no indent increase if this node was skipped\n\n for (let i = 0; i < node.children.length; i++) {\n const isChildLast = i === node.children.length - 1 && !deferredOutput;\n renderNode(\n node.children[i],\n childPrefix,\n isChildLast,\n depth + (formatted ? 1 : 0),\n maxDepth,\n lines,\n node.span,\n fallbackIntent,\n fullOutput,\n dedup\n );\n }\n\n // Show deferred output at the bottom, after all children\n if (deferredOutput) {\n lines.push(`${childPrefix}└─→ ${deferredOutput}`);\n }\n}\n\ninterface FormatResult {\n line: string;\n /** Output to show after children (deferred to bottom) */\n output?: string;\n}\n\nfunction formatSpanLine(\n span: NormalizedSpan,\n parentSpan?: NormalizedSpan,\n fallbackIntent?: string,\n fullOutput?: boolean,\n dedup?: DeduplicationContext,\n hasChildren?: boolean\n): FormatResult {\n const duration = formatDurationMs(span.durationMs);\n const attrs = span.attributes;\n const name = span.name;\n const previewLimit = fullOutput ? 10000 : 120;\n\n // Helper: get a display name for this span (used in dedup references)\n const displayName = String(attrs['visor.check.id'] || name).replace(/^visor\\.check\\./, '');\n\n // Helper: deduplicate an output string — returns the display string (without → prefix)\n const dedupeOutputStr = (rawOutput: string, label: string): string => {\n if (!rawOutput) return '';\n if (!dedup) return rawOutput;\n const ref = dedupeOrRegister(dedup, 'outputs', rawOutput, label);\n if (ref) return `(= ${ref})`;\n return rawOutput;\n };\n\n // Helper: deduplicate an intent string — returns the display string\n const dedupeIntentStr = (rawIntent: string, label: string): string => {\n if (!rawIntent || !dedup) return rawIntent ? ` 💬 ${rawIntent}` : '';\n const ref = dedupeOrRegister(dedup, 'intents', rawIntent, label);\n if (ref) return ` 💬 (= ${ref})`;\n return ` 💬 ${rawIntent}`;\n };\n\n // Helper: format output as inline or deferred depending on whether node has children\n const makeResult = (line: string, outputPreview: string): FormatResult => {\n if (!outputPreview) return { line };\n if (hasChildren) {\n // Defer output to bottom — show after children\n return { line, output: outputPreview };\n }\n // Inline for leaf nodes\n return { line: `${line} → ${outputPreview}` };\n };\n\n // --- Tool calls: extract real inputs ---\n const toolName = attrs['tool.name'] || attrs['visor.tool.name'];\n if (toolName) {\n const toolInput = extractToolInput(String(toolName), attrs);\n const toolResultLen = attrs['tool.result.length'] || attrs['tool.result.count'];\n const toolSuccess = attrs['tool.success'];\n const tn = String(toolName);\n const isSearchTool = tn === 'search' || tn === 'searchCode' || tn === 'search_code';\n const numLen = toolResultLen ? Number(toolResultLen) : -1;\n const noResults = isSearchTool && numLen >= 0 && numLen < 500;\n const resultSize = noResults ? 'no results' : toolResultLen ? formatSize(numLen) : '';\n const durStr =\n Number(attrs['tool.duration_ms']) > 0\n ? ` (${formatDurationMs(Number(attrs['tool.duration_ms']))})`\n : '';\n\n // Bash: show exit code / signal instead of generic success mark\n let successMark = toolSuccess === false ? ' ✗' : '';\n if (tn === 'bash') {\n const toolResult = String(attrs['tool.result'] || '');\n const exitMatch = toolResult.match(/Exit Code: (\\S+)/);\n const sigMatch = toolResult.match(/Signal: (\\S+)/);\n if (sigMatch && sigMatch[1] !== 'null') {\n successMark = ` [${sigMatch[1]}]`;\n } else if (exitMatch && exitMatch[1] !== '0' && exitMatch[1] !== 'null') {\n successMark = ` [exit ${exitMatch[1]}]`;\n }\n }\n\n return {\n line: `${toolName}(${toolInput})${durStr}${resultSize ? ` → ${resultSize}` : ''}${successMark}`,\n };\n }\n\n // --- Search delegate dedup ---\n if (name === 'search.delegate.dedup') {\n const query = attrs['dedup.query'] || '';\n const action = attrs['dedup.action'] || '?';\n const reason = attrs['dedup.reason'] || '';\n const rewritten = attrs['dedup.rewritten'] || '';\n let detail = `${action}`;\n if (rewritten) detail += ` → \"${truncate(String(rewritten), 50)}\"`;\n if (reason) detail += ` — ${truncate(String(reason), 60)}`;\n return { line: `dedup(\"${truncate(String(query), 50)}\") ${detail} (${duration})` };\n }\n\n // --- Search delegate: show the search query + confidence ---\n if (name === 'search.delegate') {\n const query = attrs['search.query'] || '';\n const rewritten = attrs['search.query.rewritten'] || '';\n const output = attrs['search.delegate.output'] || '';\n let suffix = '';\n // Try to extract confidence and group/search counts from output\n try {\n const parsed = JSON.parse(String(output));\n const parts: string[] = [];\n if (parsed.confidence) parts.push(parsed.confidence);\n if (parsed.groups?.length) parts.push(`${parsed.groups.length} groups`);\n if (parsed.searches?.length) parts.push(`${parsed.searches.length} searches`);\n if (parts.length > 0) suffix = ` → ${parts.join(', ')}`;\n } catch {}\n const rewriteStr = rewritten ? ` → \"${truncate(String(rewritten), 40)}\"` : '';\n return {\n line: `search.delegate(\"${truncate(String(query), 60)}\"${rewriteStr}) (${duration})${suffix}`,\n };\n }\n\n // --- AI request: show model + input summary ---\n if (name === 'ai.request') {\n const model = attrs['ai.model'] || attrs['gen_ai.request.model'] || '?';\n const tokensIn = attrs['ai.input_length'] || attrs['gen_ai.usage.input_tokens'] || '';\n const tokensOut = attrs['gen_ai.usage.output_tokens'] || '';\n const tokenParts: string[] = [];\n if (tokensIn) tokenParts.push(`${tokensIn} in`);\n if (tokensOut) tokenParts.push(`${tokensOut} out`);\n const tokenStr = tokenParts.length > 0 ? ` [${tokenParts.join(', ')}]` : '';\n\n // Extract a short intent/question from ai.input — inline on same line\n const aiInput = String(attrs['ai.input'] || '');\n let intent = extractAIIntent(aiInput, previewLimit);\n\n // Fallback: if ai.input was truncated, try parent check's attributes\n if (!intent && parentSpan) {\n // Try prompt preview first\n const promptPreview = String(\n parentSpan.attributes['visor.provider.request.prompt.preview'] || ''\n );\n if (promptPreview) {\n intent = extractAIIntent(promptPreview, previewLimit);\n }\n // Try extracting topic from parent check's input context (route-intent output)\n if (!intent) {\n const inputOutputs = String(parentSpan.attributes['visor.check.input.outputs'] || '');\n if (inputOutputs) {\n try {\n const outputs = JSON.parse(inputOutputs);\n const topic = outputs['route-intent']?.topic;\n if (topic) intent = truncate(String(topic), 150);\n } catch {}\n }\n }\n }\n // Global fallback: use the route-intent topic — but only for top-level AI,\n // not for sub-delegates whose intent is the search.delegate query\n if (!intent && fallbackIntent && parentSpan?.name !== 'search.delegate') {\n intent = fallbackIntent;\n }\n const intentStr = intent ? dedupeIntentStr(intent, displayName) : '';\n\n // Get output preview from parent check's output\n let outputPreview = '';\n if (parentSpan) {\n const checkOutput = String(parentSpan.attributes['visor.check.output'] || '');\n if (checkOutput) {\n const preview = extractOutputPreview(checkOutput, previewLimit);\n if (preview) outputPreview = dedupeOutputStr(preview, displayName);\n }\n }\n\n const mainLine = `ai ${model} (${duration})${tokenStr}${intentStr}`;\n return makeResult(mainLine, outputPreview);\n }\n\n // --- Visor check: clean name, show type, show input/output preview ---\n const checkId = attrs['visor.check.id'];\n const checkType = attrs['visor.check.type'];\n if (checkId || name.startsWith('visor.check.')) {\n const cleanName = String(checkId || name).replace(/^visor\\.check\\./, '');\n const typeStr = checkType ? ` [${checkType}]` : '';\n\n // Show input dependencies\n const inputOutputs = String(attrs['visor.check.input.outputs'] || '');\n let inputStr = '';\n if (inputOutputs && inputOutputs !== '{}') {\n inputStr = ' ' + formatInputPreview(inputOutputs, previewLimit);\n }\n\n // Get output preview for checks that produce meaningful output\n const output = String(attrs['visor.check.output'] || '');\n let outputPreview = '';\n if (output) {\n const preview = extractOutputPreview(output, previewLimit);\n if (preview) outputPreview = dedupeOutputStr(preview, cleanName);\n }\n\n const mainLine = `${cleanName}${typeStr} (${duration})${inputStr}`;\n return makeResult(mainLine, outputPreview);\n }\n\n // --- visor.run: show source info ---\n if (name === 'visor.run') {\n const source = attrs['visor.run.source'] || '';\n const sourceStr = source ? ` (${source})` : '';\n return { line: `visor.run${sourceStr} (${duration})` };\n }\n\n // --- Negotiated timeout observer: show decision details ---\n if (\n name === 'probe.event.negotiated_timeout.observer' ||\n name === 'negotiated_timeout.observer'\n ) {\n // Decision data lives in span events emitted by Probe inside the observer span.\n // Look through span.events for observer_extended, observer_declined, observer_exhausted.\n let detail = '';\n\n // First try span attributes (future Probe versions may set these directly)\n const attrDecision = attrs['observer.decision'] || attrs['decision_reason'];\n if (attrDecision) {\n const reason = attrs['observer.reason'] || attrs['decision_reason'] || '';\n if (String(attrDecision) === 'extended' || attrs['granted_ms']) {\n const grantedMin =\n attrs['observer.granted_min'] ||\n attrs['granted_min'] ||\n (attrs['granted_ms'] ? Math.round(Number(attrs['granted_ms']) / 60000) : '?');\n detail = `extended +${grantedMin}min`;\n if (reason) detail += ` (${truncate(String(reason), 60)})`;\n const used = attrs['observer.extensions_used'] || attrs['extensions_used'];\n const max = attrs['observer.max_requests'] || attrs['max_requests'];\n if (used) detail += ` [${used}/${max || '?'} used]`;\n } else if (String(attrDecision) === 'exhausted') {\n detail = 'budget exhausted';\n } else {\n detail = `declined`;\n if (reason) detail += `: ${truncate(String(reason), 60)}`;\n }\n }\n\n // Then try span events (current Probe versions emit these)\n if (!detail && span.events.length > 0) {\n for (const evt of span.events) {\n const evtName = evt.name || '';\n const ea = evt.attributes;\n if (evtName.includes('observer_extended')) {\n const grantedMin =\n ea['granted_min'] ||\n (ea['granted_ms'] ? Math.round(Number(ea['granted_ms']) / 60000) : '?');\n detail = `extended +${grantedMin}min`;\n if (ea['decision_reason']) detail += ` (${truncate(String(ea['decision_reason']), 60)})`;\n if (ea['extensions_used'])\n detail += ` [${ea['extensions_used']}/${ea['max_requests'] || '?'} used]`;\n break;\n }\n if (evtName.includes('observer_declined')) {\n detail = 'declined';\n if (ea['decision_reason']) detail += `: ${truncate(String(ea['decision_reason']), 60)}`;\n break;\n }\n if (evtName.includes('observer_exhausted')) {\n const used = ea['extensions_used'] || '?';\n const max = ea['max_requests'] || '?';\n detail = `budget exhausted [${used}/${max} extensions]`;\n break;\n }\n if (evtName.includes('observer_invoked') && !detail) {\n // Show invocation context as fallback if no decision event follows\n const elapsed = ea['elapsed_min'] || '?';\n const tools = ea['active_tools_count'] || 0;\n detail = `${elapsed}min elapsed, ${tools} active tools`;\n // Don't break — keep looking for a decision event\n }\n }\n }\n\n // Final fallback: span attributes for elapsed/active tools\n if (!detail) {\n const elapsed = attrs['elapsed_min'];\n const activeTools = attrs['active_tools_count'] || attrs['active_tools'];\n if (elapsed) detail += `${elapsed}min elapsed`;\n if (activeTools)\n detail += detail ? `, ${activeTools} active tools` : `${activeTools} active tools`;\n }\n\n const label = detail ? `timeout.observer: ${detail}` : 'timeout.observer';\n return { line: `${label} (${duration})` };\n }\n\n // --- Negotiated timeout sub-events (promoted to individual spans) ---\n if (name.includes('negotiated_timeout.observer_')) {\n const suffix = name.replace(/.*negotiated_timeout\\.observer_/, '');\n const reason = attrs['decision_reason'] || '';\n if (suffix === 'extended') {\n const grantedMin =\n attrs['granted_min'] ||\n (attrs['granted_ms'] ? Math.round(Number(attrs['granted_ms']) / 60000) : '?');\n const used = attrs['extensions_used'] || '?';\n const max = attrs['max_requests'] || '?';\n const reasonStr = reason ? ` (${truncate(String(reason), 60)})` : '';\n return { line: `timeout.extended: +${grantedMin}min${reasonStr} [${used}/${max} used]` };\n }\n if (suffix === 'declined') {\n const reasonStr = reason ? `: ${truncate(String(reason), 60)}` : '';\n return { line: `timeout.declined${reasonStr}` };\n }\n if (suffix === 'exhausted') {\n const used = attrs['extensions_used'] || '?';\n const max = attrs['max_requests'] || '?';\n return { line: `timeout.exhausted [${used}/${max} extensions, budget depleted]` };\n }\n // observer_invoked, observer_response — less important, show compact\n if (suffix === 'invoked') {\n const elapsed = attrs['elapsed_min'] || '?';\n const tools = attrs['active_tools_count'] || 0;\n return { line: `timeout.observer invoked (${elapsed}min elapsed, ${tools} active tools)` };\n }\n return { line: `timeout.${suffix} (${duration})` };\n }\n\n // --- Negotiated timeout abort summary: show that final response was generated under timeout ---\n if (name.includes('negotiated_timeout.abort_summary')) {\n const summaryLen = attrs['summary_length'] || attrs['summary.length'];\n const lenStr = summaryLen ? ` → ${formatSize(Number(summaryLen))}` : '';\n return { line: `timeout.abort_summary (${duration})${lenStr}` };\n }\n\n // --- Graceful stop events ---\n if (name.includes('graceful_stop.initiated') || name.includes('graceful_stop.invoked')) {\n const reason = attrs['graceful_stop.reason'] || attrs['reason'] || '';\n const reasonStr = reason ? `: ${truncate(String(reason), 80)}` : '';\n return { line: `graceful_stop${reasonStr} (${duration})` };\n }\n\n // --- Generic span ---\n return { line: `${name} (${duration})${span.status === 'error' ? ' ✗' : ''}` };\n}\n\n/**\n * Extract a meaningful input description for a tool call.\n * Parse a workspace path like /tmp/visor-workspaces/<session>/<repo>/path/to/file\n * into { repo, filePath } components.\n */\nfunction parseWorkspacePath(fullPath: string): { repo: string; filePath?: string } | null {\n // Match /tmp/visor-workspaces/<session-id>/<repo>/...\n const wsMatch = fullPath.match(/\\/visor-workspaces\\/[^/]+\\/([^/]+)(?:\\/(.+))?/);\n if (wsMatch) {\n return { repo: wsMatch[1], filePath: wsMatch[2] };\n }\n // Match .visor/worktrees/worktrees/<worktree-id>/<path>\n const wtMatch = fullPath.match(/\\.visor\\/worktrees\\/worktrees\\/[^/]+\\/(.+)/);\n if (wtMatch) {\n const segs = wtMatch[1].split('/');\n return { repo: segs[0], filePath: segs.length > 1 ? segs.slice(1).join('/') : undefined };\n }\n return null;\n}\n\n/**\n * Parses the Pattern/Path from tool.result for search tools,\n * and file paths for extract tools.\n */\nfunction extractToolInput(\n toolName: string,\n attrs: Record<string, string | number | boolean>\n): string {\n const result = String(attrs['tool.result'] || '');\n const explicitInput = String(attrs['tool.input'] || '');\n\n if (explicitInput) return truncate(explicitInput, 80);\n\n switch (toolName) {\n case 'search': {\n // Parse \"Pattern: ...\" and \"Path: ...\" from Probe search output\n const patMatch = result.match(/Pattern: (.+)/);\n const pathMatch = result.match(/Path: (\\S+)/);\n const pattern = patMatch ? patMatch[1].trim() : '';\n const workspace = pathMatch ? parseWorkspacePath(pathMatch[1]) : null;\n const parts: string[] = [];\n if (pattern) parts.push(`\"${truncate(pattern, 50)}\"`);\n if (workspace?.repo) parts.push(workspace.repo);\n return parts.join(', ');\n }\n case 'extract': {\n // Parse file paths from \"Files to extract:\" block\n // Full path looks like: /tmp/visor-workspaces/<session>/<repo>/path/to/file (lines N-M)\n const fileMatch = result.match(/Files to extract:\\n\\s*(\\S+)/);\n if (fileMatch) {\n const fullPath = fileMatch[1];\n const workspace = parseWorkspacePath(fullPath);\n if (workspace) {\n const parts: string[] = [];\n parts.push(workspace.filePath || workspace.repo || fullPath.split('/').pop() || '');\n if (workspace.repo) parts.push(workspace.repo);\n return parts.join(', ');\n }\n // Fallback: show last 2 segments\n const segs = fullPath.split('/');\n return segs.length > 2 ? segs.slice(-2).join('/') : segs[segs.length - 1];\n }\n return '';\n }\n case 'bash': {\n // tool.result starts with \"Command: <cmd>\\nWorking directory: ...\"\n const cmdMatch = result.match(/^Command: (.+)/);\n if (cmdMatch) {\n let cmd = cmdMatch[1].trim();\n // Strip long pipes — show first command + pipe count\n const pipes = cmd.split(/\\s*\\|\\s*/);\n if (pipes.length > 2) {\n cmd = `${pipes[0]} | ... (${pipes.length} stages)`;\n }\n return truncate(cmd, 80);\n }\n // Blocked commands: \"Permission denied: Component \"<cmd>\" not allowed: ...\"\n const deniedMatch = result.match(/^Permission denied: Component \"([^\"]+)\"/);\n if (deniedMatch) {\n return truncate(deniedMatch[1], 60) + ' [denied]';\n }\n return '';\n }\n case 'listFiles': {\n const pathMatch = result.match(/^(\\S+):/);\n if (pathMatch) {\n const parts = pathMatch[1].split('/');\n return parts[parts.length - 1] || '';\n }\n return '';\n }\n default:\n return truncate(explicitInput, 60);\n }\n}\n\n/**\n * Extract a short intent/question from an AI prompt.\n * Looks for ## Current Request, <question>, or the user message.\n */\nfunction extractAIIntent(input: string, maxLen: number = 150): string {\n if (!input || input.length < 20) return '';\n\n // Try <question>...</question>\n const qMatch = input.match(/<question>([\\s\\S]*?)<\\/question>/);\n if (qMatch) return truncate(qMatch[1].trim(), maxLen);\n\n // Try \"## Current Request\" section\n const crMatch = input.match(/## Current Request\\s*\\n(?:User: )?(.+)/);\n if (crMatch) return truncate(crMatch[1].trim(), maxLen);\n\n // Try \"User:\" pattern\n const userMatch = input.match(/(?:^|\\n)User: (.+)/);\n if (userMatch) return truncate(userMatch[1].trim(), maxLen);\n\n // Try \"Primary message\" pattern\n const pmMatch = input.match(/Primary message[^:]*:\\s*\\n(.+)/);\n if (pmMatch) return truncate(pmMatch[1].trim(), maxLen);\n\n return '';\n}\n\n/**\n * Format a JSON output as a compact structural preview.\n * Shows key names + brief values, preserving the JSON nature of the data.\n */\nfunction formatJsonPreview(obj: any, maxLen: number): string {\n if (obj === null || obj === undefined) return '';\n if (typeof obj !== 'object') return truncate(String(obj), maxLen);\n\n if (Array.isArray(obj)) {\n if (obj.length === 0) return '[]';\n // Show array length + first item preview\n const first =\n typeof obj[0] === 'object' && obj[0] !== null\n ? obj[0].project_id || obj[0].id || obj[0].name || Object.keys(obj[0])[0] || '...'\n : String(obj[0]);\n return `[${obj.length}] ${truncate(String(first), 30)}${obj.length > 1 ? ', ...' : ''}`;\n }\n\n // Object — show key:value pairs compactly\n const parts: string[] = [];\n let len = 2; // for { }\n for (const [key, val] of Object.entries(obj)) {\n // Skip internal/verbose keys\n if (key === 'raw' || key === 'skills' || key === 'tags') continue;\n let valStr: string;\n if (val === null || val === undefined) continue;\n if (typeof val === 'boolean') valStr = String(val);\n else if (typeof val === 'number') valStr = String(val);\n else if (typeof val === 'string') {\n // Skip text fields that are stringified JSON (duplicate data)\n if (val.startsWith('{') || val.startsWith('[')) continue;\n // Clean markdown from text values\n const clean = val\n .replace(/\\*\\*/g, '')\n .replace(/^#+\\s*/gm, '')\n .replace(/`/g, '')\n .trim();\n valStr = `\"${truncate(clean.split('\\n')[0], Math.min(80, maxLen / 3))}\"`;\n } else if (Array.isArray(val)) valStr = `[${val.length}]`;\n else if (typeof val === 'object') valStr = `{${Object.keys(val).length} keys}`;\n else valStr = '...';\n\n const part = `${key}: ${valStr}`;\n if (len + part.length + 2 > maxLen) {\n parts.push('...');\n break;\n }\n parts.push(part);\n len += part.length + 2;\n }\n\n return `{${parts.join(', ')}}`;\n}\n\n/**\n * Extract a short preview from a check's output JSON.\n * Shows structural JSON preview preserving the data format.\n */\nfunction extractOutputPreview(output: string, maxLen: number = 120): string {\n try {\n const obj = JSON.parse(output);\n return formatJsonPreview(obj, maxLen);\n } catch {\n // JSON truncated by telemetry — extract top-level keys with regex\n return extractTruncatedJsonPreview(output, maxLen);\n }\n}\n\n/**\n * Extract a structured preview from truncated JSON (telemetry cuts at ~2048 chars).\n * Extracts top-level key:value pairs using regex.\n */\n/**\n * Tolerant JSON parser that extracts as much structure as possible from\n * truncated JSON (e.g., OTEL attribute values cut off at ~2048 chars).\n * Returns a partial JS object/array/string — whatever was parseable.\n */\nfunction parseTruncatedJson(input: string): any {\n let pos = 0;\n const len = input.length;\n\n function skipWhitespace(): void {\n while (pos < len && ' \\t\\n\\r'.includes(input[pos])) pos++;\n }\n\n function parseString(): string {\n if (input[pos] !== '\"') return '';\n pos++; // skip opening quote\n let result = '';\n while (pos < len) {\n const ch = input[pos];\n if (ch === '\\\\' && pos + 1 < len) {\n const next = input[pos + 1];\n if (next === 'n') {\n result += '\\n';\n pos += 2;\n continue;\n }\n if (next === 't') {\n result += '\\t';\n pos += 2;\n continue;\n }\n if (next === '\"') {\n result += '\"';\n pos += 2;\n continue;\n }\n if (next === '\\\\') {\n result += '\\\\';\n pos += 2;\n continue;\n }\n result += next;\n pos += 2;\n continue;\n }\n if (ch === '\"') {\n pos++;\n return result;\n }\n result += ch;\n pos++;\n }\n // Truncated — no closing quote\n return result;\n }\n\n function parseNumber(): number {\n const start = pos;\n if (input[pos] === '-') pos++;\n while (pos < len && input[pos] >= '0' && input[pos] <= '9') pos++;\n if (pos < len && input[pos] === '.') {\n pos++;\n while (pos < len && input[pos] >= '0' && input[pos] <= '9') pos++;\n }\n return Number(input.slice(start, pos));\n }\n\n function parseValue(): any {\n skipWhitespace();\n if (pos >= len) return undefined;\n const ch = input[pos];\n if (ch === '\"') return parseString();\n if (ch === '{') return parseObject();\n if (ch === '[') return parseArray();\n if (ch === 't' && input.slice(pos, pos + 4) === 'true') {\n pos += 4;\n return true;\n }\n if (ch === 'f' && input.slice(pos, pos + 5) === 'false') {\n pos += 5;\n return false;\n }\n if (ch === 'n' && input.slice(pos, pos + 4) === 'null') {\n pos += 4;\n return null;\n }\n if (ch === '-' || (ch >= '0' && ch <= '9')) return parseNumber();\n return undefined; // truncated\n }\n\n function parseObject(): Record<string, any> {\n const obj: Record<string, any> = {};\n pos++; // skip {\n skipWhitespace();\n while (pos < len && input[pos] !== '}') {\n skipWhitespace();\n if (pos >= len || input[pos] !== '\"') break; // truncated\n const key = parseString();\n skipWhitespace();\n if (pos >= len || input[pos] !== ':') {\n obj[key] = undefined;\n break;\n }\n pos++; // skip :\n const val = parseValue();\n if (val !== undefined) obj[key] = val;\n skipWhitespace();\n if (pos < len && input[pos] === ',') pos++;\n }\n if (pos < len && input[pos] === '}') pos++;\n return obj;\n }\n\n function parseArray(): any[] {\n const arr: any[] = [];\n pos++; // skip [\n skipWhitespace();\n while (pos < len && input[pos] !== ']') {\n const val = parseValue();\n if (val !== undefined) arr.push(val);\n else break; // truncated\n skipWhitespace();\n if (pos < len && input[pos] === ',') pos++;\n skipWhitespace();\n }\n if (pos < len && input[pos] === ']') pos++;\n return arr;\n }\n\n return parseValue();\n}\n\nfunction extractTruncatedJsonPreview(output: string, maxLen: number): string {\n if (!output.startsWith('{') && !output.startsWith('[')) return '';\n\n const parsed = parseTruncatedJson(output);\n if (!parsed || typeof parsed !== 'object') return '';\n\n return formatJsonPreview(parsed, maxLen);\n}\n\n/**\n * Format check inputs from visor.check.input.outputs into a compact summary.\n * Shows which checks provided data: ← {route-intent: {intent, topic}, build-config: {5 keys}}\n */\nfunction formatInputPreview(inputOutputsStr: string, maxLen: number): string {\n if (!inputOutputsStr) return '';\n try {\n const inputs = JSON.parse(inputOutputsStr);\n if (typeof inputs !== 'object' || inputs === null) return '';\n const keys = Object.keys(inputs);\n if (keys.length === 0) return '';\n\n const parts: string[] = [];\n let len = 2;\n for (const key of keys) {\n const val = inputs[key];\n let valStr: string;\n if (typeof val === 'object' && val !== null) {\n const vkeys = Object.keys(val);\n if (vkeys.length <= 3) {\n valStr = `{${vkeys.join(', ')}}`;\n } else {\n valStr = `{${vkeys.slice(0, 2).join(', ')}, ...${vkeys.length} keys}`;\n }\n } else {\n valStr = truncate(String(val), 30);\n }\n const part = `${key}: ${valStr}`;\n if (len + part.length + 2 > maxLen) {\n parts.push('...');\n break;\n }\n parts.push(part);\n len += part.length + 2;\n }\n return `← {${parts.join(', ')}}`;\n } catch {\n return '';\n }\n}\n\n/**\n * Extract the route-intent topic from the span list.\n * Looks for the route-intent check output or classify check output.\n */\nfunction extractRouteIntentTopic(spans: NormalizedSpan[]): string | undefined {\n // Try route-intent check output first\n const riSpan = spans.find(s => s.attributes['visor.check.id'] === 'route-intent');\n if (riSpan) {\n const output = String(riSpan.attributes['visor.check.output'] || '');\n if (output) {\n try {\n const obj = JSON.parse(output);\n if (obj.topic) return truncate(String(obj.topic), 150);\n } catch {}\n }\n }\n // Try classify check output\n const classifySpan = spans.find(s => s.attributes['visor.check.id'] === 'classify');\n if (classifySpan) {\n const output = String(classifySpan.attributes['visor.check.output'] || '');\n if (output) {\n try {\n const obj = JSON.parse(output);\n if (obj.topic) return truncate(String(obj.topic), 150);\n } catch {}\n }\n }\n return undefined;\n}\n\nfunction formatSize(chars: number): string {\n if (chars < 1000) return `${chars} chars`;\n return `${(chars / 1000).toFixed(1)}k chars`;\n}\n\nfunction formatDurationMs(ms: number): string {\n if (ms < 0) return '0ms';\n if (ms < 1000) return `${Math.round(ms)}ms`;\n if (ms < 60000) return `${(ms / 1000).toFixed(1)}s`;\n const mins = Math.floor(ms / 60000);\n const secs = Math.round((ms % 60000) / 1000);\n return `${mins}m ${secs}s`;\n}\n\nfunction truncate(str: string, max: number): string {\n if (typeof str !== 'string') return '';\n if (str.length <= max) return str;\n // Show first and last portions with truncation marker in the middle\n const tail = Math.min(100, Math.floor(max / 3));\n const head = max - tail - 19; // 19 for \" ...[truncated]... \"\n if (head < 10) return str.slice(0, max - 3) + '...';\n return str.slice(0, head) + ' ...[truncated]... ' + str.slice(-tail);\n}\n","/**\n * Task Response Evaluator with LLM Judge + Trace Analysis.\n *\n * Evaluates completed agent tasks on two axes:\n * 1. Response quality (relevance, completeness, actionability)\n * 2. Execution quality (tool call efficiency, unnecessary delegations)\n *\n * Uses ProbeAgent in single-shot mode (same pattern as llm-judge.ts).\n */\n\nimport crypto from 'crypto';\nimport { logger } from '../logger';\nimport type { SqliteTaskStore } from './task-store';\nimport { serializeTraceForPrompt } from './trace-serializer';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface ResponseQuality {\n rating: number; // 1-5\n category: 'excellent' | 'good' | 'adequate' | 'poor' | 'off-topic' | 'error';\n relevance: boolean;\n completeness: boolean;\n actionable: boolean;\n reasoning: string;\n}\n\nexport interface ExecutionQuality {\n rating: number; // 1-5\n category: 'efficient' | 'adequate' | 'wasteful' | 'error';\n unnecessary_tool_calls?: number;\n reasoning: string;\n}\n\nexport interface TaskEvaluationResult {\n response_quality: ResponseQuality;\n execution_quality?: ExecutionQuality;\n overall_rating: number; // 1-5\n summary: string;\n trace_available?: boolean; // false when evaluation was done without execution trace\n}\n\nexport interface TaskEvaluatorConfig {\n model?: string;\n provider?: string;\n apiKey?: string;\n prompt?: string; // Override default evaluation system prompt\n traceDir?: string; // Where to find trace files (default: output/traces)\n}\n\n// ---------------------------------------------------------------------------\n// Default prompt\n// ---------------------------------------------------------------------------\n\nexport const DEFAULT_EVALUATION_PROMPT = `You are a task response quality evaluator for an AI agent system called Visor.\n\nYou will receive the user's original request and an execution trace inside <execution_trace> tags. The trace is a YAML-formatted view of the entire agent execution, including the final response. When no trace is available, the agent response is provided directly.\n\n## How to Read the Execution Trace\n\nThe trace is a tree of spans representing the agent's execution pipeline:\n\n**Top-level: \\`visor.run\\`** — The root span with metadata:\n- \\`trace_id\\`: Unique execution identifier\n- \\`visor\\` / \\`probe\\`: Software versions\n- \\`source\\`: Where the request came from (e.g., \"slack\", \"cli\")\n- \\`duration\\`: Total wall-clock time\n\n**Checks** — Named processing steps (e.g., \\`route-intent\\`, \\`explore-code\\`, \\`generate-response\\`):\n- \\`type\\`: \"ai\" (LLM-powered), \"script\" (deterministic), or \"workflow\" (sub-pipeline)\n- \\`duration\\`: How long this step took\n- \\`input\\`: What was passed to this check — may include an \\`intent\\` (the user's question as understood by the router) and dependency outputs\n- \\`output\\`: The check's result — may be structured JSON or plain text\n\n**AI blocks** (\\`ai: model-name\\`) — Individual LLM calls within checks:\n- Shows model used, duration, and token counts (input/output)\n- \\`intent\\`: The question or instruction sent to the LLM\n\n**Tool calls** — Listed as \\`- toolName(input) → size\\`:\n- \\`search(\"query\" in repo)\\`: Code search. \"→ no results\" means nothing was found; otherwise shows result size\n- \\`extract(file/path)\\`: File content extraction with result size\n- \\`listFiles(dir)\\`: Directory listing\n- \\`bash()\\`: Shell command execution\n\n**Delegations** (\\`search.delegate(\"query\")\\`) — Sub-agent searches:\n- Contains their own AI blocks and tool calls\n- Used for complex multi-step code exploration\n\n**The \\`response\\` field** at the end of the trace is the final answer sent back to the user. This is the primary output to evaluate.\n\n**Symbols:**\n- \\`✗\\` marks failed/error spans\n- \\`= check-name\\` means output is identical to that check's output (deduplication)\n\n## Evaluation Criteria\n\n**Response Quality** (1-5):\n- **Relevance**: Does the response directly address what the user asked? A response about the wrong topic or that misunderstands the question scores low.\n- **Completeness**: Does it fully answer the question? Partial answers, missing key details, or surface-level responses score lower.\n- **Actionable**: Can the user act on this information? Vague or generic advice scores lower than specific, concrete answers with code references.\n- Rating: 5=excellent (thorough, specific, directly useful), 4=good (answers well but minor gaps), 3=adequate (addresses question but lacks depth), 2=poor (partially relevant or very incomplete), 1=off-topic or error\n\n**Execution Quality** (1-5, only when trace is provided):\n- **Efficiency**: Were tool calls necessary and well-targeted? Good search queries that find results on the first try score high.\n- **Redundancy**: Were there duplicate searches, unnecessary re-searches with slightly different queries, or tools called for information already available?\n- **Extract-then-search anti-pattern**: If a file was already extracted (e.g., \\`extract(docs/config.mdx) → 3.3k chars\\`), then a subsequent \\`search(\"term\" in config.mdx)\\` is redundant — the agent already has the file content and should parse it from context instead of making another tool call. Flag every instance of this pattern.\n- **Search-reformulation waste**: If a search returns \"no results\" and the agent immediately retries with a minor query variation (e.g., \\`\"audit store_type\"\\` → \\`\"audit \"store_type\"\"\\` → \\`\"store_type\"\\`), that's usually wasteful. A single well-crafted query should suffice; reformulating 3+ times for the same concept is a red flag.\n- **Delegation quality**: Were search delegations productive? Did they explore relevant code paths?\n- **Token usage**: Was input context kept reasonable, or did the agent load excessive amounts of code?\n- Rating: 5=efficient (minimal, targeted tool use), 4=adequate (minor redundancy), 3=some waste (noticeable unnecessary calls), 2=wasteful (many redundant searches or delegations), 1=error/broken execution\n\n**Overall Rating** (1-5): Weighted combination — response quality matters most, execution quality is secondary. A perfect response from a wasteful execution still scores 3-4 overall.\n\nYou MUST respond with valid JSON matching the provided schema. Be specific in your reasoning — reference actual check names, tool calls, or response content.`;\n\n// ---------------------------------------------------------------------------\n// JSON Schema\n// ---------------------------------------------------------------------------\n\nfunction buildEvaluationSchema(includeExecution: boolean): Record<string, unknown> {\n const schema: Record<string, unknown> = {\n type: 'object',\n required: ['response_quality', 'overall_rating', 'summary'],\n properties: {\n response_quality: {\n type: 'object',\n required: ['rating', 'category', 'relevance', 'completeness', 'actionable', 'reasoning'],\n properties: {\n rating: { type: 'integer', minimum: 1, maximum: 5 },\n category: {\n type: 'string',\n enum: ['excellent', 'good', 'adequate', 'poor', 'off-topic', 'error'],\n },\n relevance: { type: 'boolean' },\n completeness: { type: 'boolean' },\n actionable: { type: 'boolean' },\n reasoning: { type: 'string' },\n },\n },\n overall_rating: { type: 'integer', minimum: 1, maximum: 5 },\n summary: { type: 'string' },\n },\n };\n\n if (includeExecution) {\n (schema.required as string[]).push('execution_quality');\n (schema.properties as Record<string, unknown>).execution_quality = {\n type: 'object',\n required: ['rating', 'category', 'reasoning'],\n properties: {\n rating: { type: 'integer', minimum: 1, maximum: 5 },\n category: { type: 'string', enum: ['efficient', 'adequate', 'wasteful', 'error'] },\n unnecessary_tool_calls: { type: 'integer' },\n reasoning: { type: 'string' },\n },\n };\n }\n\n return schema;\n}\n\n// ---------------------------------------------------------------------------\n// Core evaluation\n// ---------------------------------------------------------------------------\n\n/**\n * Evaluate a completed task using an LLM judge.\n *\n * @param taskId - Task ID (full or prefix)\n * @param store - Initialized SqliteTaskStore\n * @param config - Optional evaluator configuration\n * @returns Evaluation result with ratings and reasoning\n */\nexport async function evaluateTask(\n taskId: string,\n store: SqliteTaskStore,\n config?: TaskEvaluatorConfig\n): Promise<TaskEvaluationResult> {\n // 1. Load task data\n const { rows } = store.listTasksRaw({ limit: 500 });\n const match = rows.find(r => r.id === taskId || r.id.startsWith(taskId));\n if (!match) {\n throw new Error(`Task not found: ${taskId}`);\n }\n\n const fullTask = store.getTask(match.id);\n if (!fullTask) {\n throw new Error(`Task data not found: ${match.id}`);\n }\n\n // 2. Extract request and response text\n const requestText = match.request_message || 'No request text available';\n\n let responseText = 'No response available';\n if (fullTask.status?.message) {\n const parts = fullTask.status.message.parts ?? [];\n const textPart = parts.find((p: any) => typeof p.text === 'string');\n if (textPart) {\n responseText = (textPart as any).text;\n }\n }\n\n // 3. Shortcut for failed tasks with no real response\n if (fullTask.status.state === 'failed' && responseText === 'No response available') {\n return {\n response_quality: {\n rating: 1,\n category: 'error',\n relevance: false,\n completeness: false,\n actionable: false,\n reasoning: 'Task failed without producing a response.',\n },\n overall_rating: 1,\n summary: 'Task failed without producing a response.',\n };\n }\n\n // 4. Try to find and serialize execution trace (full mode, with task response)\n // Supports Grafana Tempo, Jaeger, and local NDJSON files (auto-detected)\n let traceTree: string | undefined;\n const traceId = match.metadata?.trace_id as string | undefined;\n const traceFile = match.metadata?.trace_file as string | undefined;\n\n if (traceFile || traceId) {\n try {\n const traceRef = traceFile || traceId!;\n // Use full mode (1M chars) so trace is not truncated, include task response\n traceTree = await serializeTraceForPrompt(\n traceRef,\n 1_000_000,\n { traceDir: config?.traceDir },\n responseText !== 'No response available' ? responseText : undefined,\n traceId\n );\n if (traceTree === '(no trace data available)') {\n traceTree = undefined;\n }\n } catch (err) {\n logger.debug(\n `[TaskEvaluator] Failed to load trace: ${err instanceof Error ? err.message : err}`\n );\n }\n }\n\n // 5. Build prompts\n const systemPrompt = config?.prompt || process.env.VISOR_EVAL_PROMPT || DEFAULT_EVALUATION_PROMPT;\n const hasTrace = !!traceTree;\n\n let userPrompt: string;\n if (traceTree) {\n // Trace includes the full execution + response — no need to duplicate\n userPrompt = `<user_request>\\n${requestText}\\n</user_request>\\n\\n<execution_trace>\\n${traceTree}\\n</execution_trace>`;\n } else {\n // No trace available — provide request and response directly\n userPrompt = `<user_request>\\n${requestText}\\n</user_request>\\n\\n<agent_response>\\n${responseText}\\n</agent_response>`;\n }\n\n // 6. Call LLM via ProbeAgent\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const { ProbeAgent } = require('@probelabs/probe');\n\n const model =\n config?.model || process.env.VISOR_EVAL_MODEL || process.env.VISOR_JUDGE_MODEL || undefined;\n const provider = config?.provider || process.env.VISOR_EVAL_PROVIDER || undefined;\n\n const agentOptions: Record<string, unknown> = {\n sessionId: `visor-task-eval-${Date.now()}`,\n systemPrompt,\n maxIterations: 1,\n disableTools: true,\n };\n if (model) agentOptions.model = model;\n if (provider) agentOptions.provider = provider;\n if (config?.apiKey) {\n const envKey =\n provider === 'openai'\n ? 'OPENAI_API_KEY'\n : provider === 'anthropic'\n ? 'ANTHROPIC_API_KEY'\n : 'GOOGLE_API_KEY';\n process.env[envKey] = config.apiKey;\n }\n\n const agent = new ProbeAgent(agentOptions);\n if (typeof agent.initialize === 'function') {\n await agent.initialize();\n }\n\n const jsonSchema = buildEvaluationSchema(hasTrace);\n const schemaStr = JSON.stringify(jsonSchema);\n const response = await agent.answer(userPrompt, undefined, { schema: schemaStr });\n\n // 7. Parse JSON response (same pattern as llm-judge.ts:181-196)\n let result: TaskEvaluationResult;\n try {\n const cleaned = response\n .replace(/^```(?:json)?\\s*\\n?/m, '')\n .replace(/\\n?```\\s*$/m, '')\n .trim();\n result = JSON.parse(cleaned);\n } catch {\n const jsonMatch = response.match(/\\{[\\s\\S]*\\}/);\n if (jsonMatch) {\n result = JSON.parse(jsonMatch[0]);\n } else {\n throw new Error(`Failed to parse evaluation response as JSON: ${response.slice(0, 200)}`);\n }\n }\n\n // 8. When no trace was available, cap overall rating and flag the evaluation\n // as incomplete — response text alone can't verify execution quality.\n if (!hasTrace) {\n const MAX_RATING_WITHOUT_TRACE = 4;\n if (result.overall_rating > MAX_RATING_WITHOUT_TRACE) {\n result.overall_rating = MAX_RATING_WITHOUT_TRACE;\n }\n result.trace_available = false;\n result.summary = `[No trace available — execution quality not assessed, rating capped at ${MAX_RATING_WITHOUT_TRACE}/5] ${result.summary}`;\n } else {\n result.trace_available = true;\n }\n\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Store evaluation as artifact\n// ---------------------------------------------------------------------------\n\n/**\n * Run evaluation and store result as a task artifact.\n */\nexport async function evaluateAndStore(\n taskId: string,\n store: SqliteTaskStore,\n config?: TaskEvaluatorConfig\n): Promise<TaskEvaluationResult> {\n const result = await evaluateTask(taskId, store, config);\n\n // Resolve full task ID\n const { rows } = store.listTasksRaw({ limit: 500 });\n const match = rows.find(r => r.id === taskId || r.id.startsWith(taskId));\n if (match) {\n store.addArtifact(match.id, {\n artifact_id: crypto.randomUUID(),\n name: 'evaluation',\n parts: [{ text: JSON.stringify(result), media_type: 'application/json' }],\n });\n }\n\n return result;\n}\n"],"mappings":"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","names":["hasChildren","errMark"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/teams/markdown.ts","../../src/teams/client.ts","../../src/frontends/teams-frontend.ts"],"sourcesContent":["// Lightweight Markdown → Teams formatter.\n// Teams supports standard Markdown natively, so minimal conversion is needed.\n// Main job: ensure text stays within Teams message size limits (~28KB).\n//\n// Teams natively supports:\n// - **bold** / __bold__\n// - *italic* / _italic_\n// - ~~strikethrough~~\n// - `code` and ```code blocks```\n// - [links](url)\n// - > blockquotes\n// - Bullet and numbered lists\n// - # Headers (in Adaptive Cards; plain text uses bold)\n//\n// Teams bot text messages have a ~28KB size limit.\n\n/**\n * Convert Markdown text to Teams-compatible format.\n * Teams renders standard Markdown, so this is mostly a passthrough.\n * Strips any raw HTML tags that might leak from AI output.\n */\nexport function markdownToTeams(text: string): string {\n if (!text || typeof text !== 'string') return '';\n return text;\n}\n\n/**\n * Chunk text into segments no larger than limit, splitting at newlines.\n */\nexport function chunkText(text: string, limit: number = 28000): string[] {\n if (text.length <= limit) return [text];\n\n const chunks: string[] = [];\n const lines = text.split('\\n');\n let current = '';\n\n for (const line of lines) {\n const candidate = current ? current + '\\n' + line : line;\n if (candidate.length > limit) {\n if (current) {\n chunks.push(current);\n current = line;\n } else {\n // Single line exceeds limit — force split\n let remaining = line;\n while (remaining.length > limit) {\n chunks.push(remaining.slice(0, limit));\n remaining = remaining.slice(limit);\n }\n current = remaining;\n }\n } else {\n current = candidate;\n }\n }\n if (current) chunks.push(current);\n\n return chunks;\n}\n\n/**\n * Main entry point: convert Markdown to Teams format.\n */\nexport function formatTeamsText(text: string): string {\n return markdownToTeams(text);\n}\n","// Microsoft Teams Bot Framework API client.\n// Wraps the botbuilder SDK for sending messages via Bot Framework.\n\nimport {\n CloudAdapter,\n ConfigurationBotFrameworkAuthentication,\n TurnContext,\n MessageFactory,\n} from 'botbuilder';\nimport type { ConversationReference } from 'botbuilder';\nimport { chunkText } from './markdown';\n\nexport interface TeamsSendResult {\n ok: boolean;\n activityId?: string;\n error?: string;\n}\n\nexport interface TeamsClientOptions {\n appId: string;\n appPassword: string;\n tenantId?: string;\n}\n\nexport class TeamsClient {\n private appId: string;\n private appPassword: string;\n private tenantId?: string;\n private adapter: CloudAdapter;\n\n constructor(opts: TeamsClientOptions) {\n if (!opts.appId) throw new Error('TeamsClient: appId is required');\n if (!opts.appPassword) throw new Error('TeamsClient: appPassword is required');\n this.appId = opts.appId;\n this.appPassword = opts.appPassword;\n this.tenantId = opts.tenantId;\n\n const auth = new ConfigurationBotFrameworkAuthentication({\n MicrosoftAppId: this.appId,\n MicrosoftAppPassword: this.appPassword,\n MicrosoftAppTenantId: this.tenantId || '',\n });\n this.adapter = new CloudAdapter(auth);\n }\n\n /** Get the underlying CloudAdapter (used by webhook runner for processing inbound) */\n getAdapter(): CloudAdapter {\n return this.adapter;\n }\n\n /** Get the configured App ID */\n getAppId(): string {\n return this.appId;\n }\n\n /**\n * Send a text message using a stored conversation reference.\n * Auto-chunks at 28000 characters.\n */\n async sendMessage(opts: {\n conversationReference: ConversationReference;\n text: string;\n replyToActivityId?: string;\n }): Promise<TeamsSendResult> {\n const chunks = chunkText(opts.text, 28000);\n let lastActivityId: string | undefined;\n\n for (const chunk of chunks) {\n try {\n await this.adapter.continueConversationAsync(\n this.appId,\n opts.conversationReference,\n async (turnContext: TurnContext) => {\n const activity = MessageFactory.text(chunk);\n if (opts.replyToActivityId) {\n activity.replyToId = opts.replyToActivityId;\n }\n const response = await turnContext.sendActivity(activity);\n lastActivityId = response?.id;\n }\n );\n } catch (err) {\n return {\n ok: false,\n error: err instanceof Error ? err.message : String(err),\n };\n }\n }\n\n return { ok: true, activityId: lastActivityId };\n }\n}\n","/**\n * Microsoft Teams Frontend for Visor workflows.\n *\n * Mirrors the WhatsAppFrontend pattern:\n * - Sends AI replies as Teams text messages\n * - Uses standard Markdown (Teams renders it natively)\n * - No reaction equivalent (CheckScheduled is a no-op)\n */\nimport type { Frontend, FrontendContext } from './host';\nimport { TeamsClient } from '../teams/client';\nimport { formatTeamsText } from '../teams/markdown';\nimport type { ConversationReference } from 'botbuilder';\n\ntype TeamsFrontendConfig = {\n appId?: string;\n appPassword?: string;\n tenantId?: string;\n};\n\nexport class TeamsFrontend implements Frontend {\n public readonly name = 'teams';\n private subs: Array<{ unsubscribe(): void }> = [];\n private cfg: TeamsFrontendConfig;\n private errorNotified: boolean = false;\n\n constructor(config?: TeamsFrontendConfig) {\n this.cfg = config || {};\n }\n\n start(ctx: FrontendContext): void {\n const bus = ctx.eventBus;\n\n try {\n ctx.logger.info(`[teams-frontend] started`);\n } catch {}\n\n // CheckCompleted: post AI replies\n this.subs.push(\n bus.on('CheckCompleted', async (env: any) => {\n const ev = (env && env.payload) || env;\n await this.maybePostDirectReply(ctx, ev.checkId, ev.result).catch(() => {});\n })\n );\n\n // CheckErrored: post error notice\n this.subs.push(\n bus.on('CheckErrored', async (env: any) => {\n const ev = (env && env.payload) || env;\n const message = ev?.error?.message || 'Execution error';\n await this.maybePostError(ctx, 'Check failed', message, ev?.checkId).catch(() => {});\n })\n );\n\n // Shutdown: post error\n this.subs.push(\n bus.on('Shutdown', async (env: any) => {\n const ev = (env && env.payload) || env;\n const message = ev?.error?.message || 'Fatal error';\n await this.maybePostError(ctx, 'Run failed', message).catch(() => {});\n })\n );\n\n // CheckScheduled: no-op (Teams has no reaction equivalent for text messages)\n // StateTransition: no-op\n }\n\n stop(): void {\n for (const s of this.subs) s.unsubscribe();\n this.subs = [];\n }\n\n private getTeams(ctx: FrontendContext): TeamsClient | undefined {\n // Prefer injected client (for tests or shared runner context)\n const injected = (ctx as any).teams || (ctx as any).teamsClient;\n if (injected) return injected;\n // Lazy-create from env or frontend config\n try {\n const appId = this.cfg.appId || process.env.TEAMS_APP_ID;\n const appPassword = this.cfg.appPassword || process.env.TEAMS_APP_PASSWORD;\n if (\n typeof appId === 'string' &&\n appId.trim() &&\n typeof appPassword === 'string' &&\n appPassword.trim()\n ) {\n return new TeamsClient({\n appId: appId.trim(),\n appPassword: appPassword.trim(),\n tenantId: this.cfg.tenantId || process.env.TEAMS_TENANT_ID,\n });\n }\n } catch {}\n return undefined;\n }\n\n private getInboundTeamsPayload(ctx: FrontendContext): any | null {\n try {\n const endpoint = '/bots/teams/message';\n return (ctx as any).webhookContext?.webhookData?.get(endpoint) || null;\n } catch {\n return null;\n }\n }\n\n private async maybePostError(\n ctx: FrontendContext,\n title: string,\n message: string,\n _checkId?: string\n ): Promise<void> {\n if (this.errorNotified) return;\n const teams = this.getTeams(ctx);\n if (!teams) return;\n const payload = this.getInboundTeamsPayload(ctx);\n const conversationRef: ConversationReference | undefined =\n payload?.teams_conversation_reference;\n if (!conversationRef) return;\n const ev: any = payload?.event;\n\n let text = `${title}`;\n if (_checkId) text += `\\nCheck: ${_checkId}`;\n if (message) text += `\\n${message}`;\n\n await teams.sendMessage({\n conversationReference: conversationRef,\n text,\n replyToActivityId: ev?.activity_id,\n });\n this.errorNotified = true;\n }\n\n private async maybePostDirectReply(\n ctx: FrontendContext,\n checkId: string,\n result: { output?: any; content?: string }\n ): Promise<void> {\n try {\n const cfg: any = ctx.config || {};\n const checkCfg: any = cfg.checks?.[checkId];\n if (!checkCfg) return;\n\n const providerType = (checkCfg.type as string) || '';\n const isAi = providerType === 'ai';\n const isLogChat = providerType === 'log' && checkCfg.group === 'chat';\n const isWorkflow = providerType === 'workflow';\n if (!isAi && !isLogChat && !isWorkflow) return;\n if (checkCfg.criticality === 'internal') return;\n\n // For AI checks, only post simple schemas\n if (isAi) {\n const schema = checkCfg.schema;\n if (typeof schema === 'string') {\n const simpleSchemas = ['code-review', 'markdown', 'text', 'plain'];\n if (!simpleSchemas.includes(schema)) return;\n }\n }\n\n const teams = this.getTeams(ctx);\n if (!teams) return;\n\n const payload = this.getInboundTeamsPayload(ctx);\n const conversationRef: ConversationReference | undefined =\n payload?.teams_conversation_reference;\n if (!conversationRef) {\n ctx.logger.warn(\n `[teams-frontend] skip posting reply for ${checkId}: missing conversation reference`\n );\n return;\n }\n const ev: any = payload?.event;\n\n // Extract text (same logic as WhatsApp/Telegram/Email/Slack frontends)\n const out: any = (result as any)?.output;\n let text: string | undefined;\n if (out && typeof out.text === 'string' && out.text.trim().length > 0) {\n text = out.text.trim();\n } else if (isAi && typeof checkCfg.schema === 'string') {\n if (\n typeof (result as any)?.content === 'string' &&\n (result as any).content.trim().length > 0\n ) {\n text = (result as any).content.trim();\n }\n } else if (isLogChat && typeof (result as any)?.logOutput === 'string') {\n const raw = (result as any).logOutput;\n if (raw.trim().length > 0) text = raw.trim();\n }\n\n // Append raw output\n if (out && typeof out._rawOutput === 'string' && out._rawOutput.trim().length > 0) {\n text = (text || '') + '\\n\\n' + out._rawOutput.trim();\n }\n\n if (!text) {\n ctx.logger.info(`[teams-frontend] skip posting reply for ${checkId}: no renderable text`);\n return;\n }\n\n // Normalize literal \\n escape sequences\n text = text.replace(/\\\\n/g, '\\n');\n\n const formattedText = formatTeamsText(text);\n const postResult = await teams.sendMessage({\n conversationReference: conversationRef,\n text: formattedText,\n replyToActivityId: ev?.activity_id,\n });\n\n if (!postResult.ok) {\n ctx.logger.warn(\n `[teams-frontend] failed to post reply for ${checkId}: ${postResult.error}`\n );\n return;\n }\n ctx.logger.info(\n `[teams-frontend] posted reply for ${checkId} (activityId=${postResult.activityId})`\n );\n } catch (err) {\n try {\n ctx.logger.warn(\n `[teams-frontend] maybePostDirectReply failed for ${checkId}: ${\n err instanceof Error ? err.message : String(err)\n }`\n );\n } catch {}\n }\n }\n}\n"],"mappings":";;;;;AAqBO,SAAS,gBAAgB,MAAsB;AACpD,MAAI,CAAC,QAAQ,OAAO,SAAS,SAAU,QAAO;AAC9C,SAAO;AACT;AAKO,SAAS,UAAU,MAAc,QAAgB,MAAiB;AACvE,MAAI,KAAK,UAAU,MAAO,QAAO,CAAC,IAAI;AAEtC,QAAM,SAAmB,CAAC;AAC1B,QAAM,QAAQ,KAAK,MAAM,IAAI;AAC7B,MAAI,UAAU;AAEd,aAAW,QAAQ,OAAO;AACxB,UAAM,YAAY,UAAU,UAAU,OAAO,OAAO;AACpD,QAAI,UAAU,SAAS,OAAO;AAC5B,UAAI,SAAS;AACX,eAAO,KAAK,OAAO;AACnB,kBAAU;AAAA,MACZ,OAAO;AAEL,YAAI,YAAY;AAChB,eAAO,UAAU,SAAS,OAAO;AAC/B,iBAAO,KAAK,UAAU,MAAM,GAAG,KAAK,CAAC;AACrC,sBAAY,UAAU,MAAM,KAAK;AAAA,QACnC;AACA,kBAAU;AAAA,MACZ;AAAA,IACF,OAAO;AACL,gBAAU;AAAA,IACZ;AAAA,EACF;AACA,MAAI,QAAS,QAAO,KAAK,OAAO;AAEhC,SAAO;AACT;AAKO,SAAS,gBAAgB,MAAsB;AACpD,SAAO,gBAAgB,IAAI;AAC7B;AAjEA;AAAA;AAAA;AAAA;AAAA;;;ACGA;AAAA,EACE;AAAA,EACA;AAAA,EAEA;AAAA,OACK;AARP,IAwBa;AAxBb;AAAA;AAAA;AAUA;AAcO,IAAM,cAAN,MAAkB;AAAA,MACf;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MAER,YAAY,MAA0B;AACpC,YAAI,CAAC,KAAK,MAAO,OAAM,IAAI,MAAM,gCAAgC;AACjE,YAAI,CAAC,KAAK,YAAa,OAAM,IAAI,MAAM,sCAAsC;AAC7E,aAAK,QAAQ,KAAK;AAClB,aAAK,cAAc,KAAK;AACxB,aAAK,WAAW,KAAK;AAErB,cAAM,OAAO,IAAI,wCAAwC;AAAA,UACvD,gBAAgB,KAAK;AAAA,UACrB,sBAAsB,KAAK;AAAA,UAC3B,sBAAsB,KAAK,YAAY;AAAA,QACzC,CAAC;AACD,aAAK,UAAU,IAAI,aAAa,IAAI;AAAA,MACtC;AAAA;AAAA,MAGA,aAA2B;AACzB,eAAO,KAAK;AAAA,MACd;AAAA;AAAA,MAGA,WAAmB;AACjB,eAAO,KAAK;AAAA,MACd;AAAA;AAAA;AAAA;AAAA;AAAA,MAMA,MAAM,YAAY,MAIW;AAC3B,cAAM,SAAS,UAAU,KAAK,MAAM,IAAK;AACzC,YAAI;AAEJ,mBAAW,SAAS,QAAQ;AAC1B,cAAI;AACF,kBAAM,KAAK,QAAQ;AAAA,cACjB,KAAK;AAAA,cACL,KAAK;AAAA,cACL,OAAO,gBAA6B;AAClC,sBAAM,WAAW,eAAe,KAAK,KAAK;AAC1C,oBAAI,KAAK,mBAAmB;AAC1B,2BAAS,YAAY,KAAK;AAAA,gBAC5B;AACA,sBAAM,WAAW,MAAM,YAAY,aAAa,QAAQ;AACxD,iCAAiB,UAAU;AAAA,cAC7B;AAAA,YACF;AAAA,UACF,SAAS,KAAK;AACZ,mBAAO;AAAA,cACL,IAAI;AAAA,cACJ,OAAO,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,YACxD;AAAA,UACF;AAAA,QACF;AAEA,eAAO,EAAE,IAAI,MAAM,YAAY,eAAe;AAAA,MAChD;AAAA,IACF;AAAA;AAAA;;;AC3FA,IAmBa;AAnBb;AAAA;AASA;AACA;AASO,IAAM,gBAAN,MAAwC;AAAA,MAC7B,OAAO;AAAA,MACf,OAAuC,CAAC;AAAA,MACxC;AAAA,MACA,gBAAyB;AAAA,MAEjC,YAAY,QAA8B;AACxC,aAAK,MAAM,UAAU,CAAC;AAAA,MACxB;AAAA,MAEA,MAAM,KAA4B;AAChC,cAAM,MAAM,IAAI;AAEhB,YAAI;AACF,cAAI,OAAO,KAAK,0BAA0B;AAAA,QAC5C,QAAQ;AAAA,QAAC;AAGT,aAAK,KAAK;AAAA,UACR,IAAI,GAAG,kBAAkB,OAAO,QAAa;AAC3C,kBAAM,KAAM,OAAO,IAAI,WAAY;AACnC,kBAAM,KAAK,qBAAqB,KAAK,GAAG,SAAS,GAAG,MAAM,EAAE,MAAM,MAAM;AAAA,YAAC,CAAC;AAAA,UAC5E,CAAC;AAAA,QACH;AAGA,aAAK,KAAK;AAAA,UACR,IAAI,GAAG,gBAAgB,OAAO,QAAa;AACzC,kBAAM,KAAM,OAAO,IAAI,WAAY;AACnC,kBAAM,UAAU,IAAI,OAAO,WAAW;AACtC,kBAAM,KAAK,eAAe,KAAK,gBAAgB,SAAS,IAAI,OAAO,EAAE,MAAM,MAAM;AAAA,YAAC,CAAC;AAAA,UACrF,CAAC;AAAA,QACH;AAGA,aAAK,KAAK;AAAA,UACR,IAAI,GAAG,YAAY,OAAO,QAAa;AACrC,kBAAM,KAAM,OAAO,IAAI,WAAY;AACnC,kBAAM,UAAU,IAAI,OAAO,WAAW;AACtC,kBAAM,KAAK,eAAe,KAAK,cAAc,OAAO,EAAE,MAAM,MAAM;AAAA,YAAC,CAAC;AAAA,UACtE,CAAC;AAAA,QACH;AAAA,MAIF;AAAA,MAEA,OAAa;AACX,mBAAW,KAAK,KAAK,KAAM,GAAE,YAAY;AACzC,aAAK,OAAO,CAAC;AAAA,MACf;AAAA,MAEQ,SAAS,KAA+C;AAE9D,cAAM,WAAY,IAAY,SAAU,IAAY;AACpD,YAAI,SAAU,QAAO;AAErB,YAAI;AACF,gBAAM,QAAQ,KAAK,IAAI,SAAS,QAAQ,IAAI;AAC5C,gBAAM,cAAc,KAAK,IAAI,eAAe,QAAQ,IAAI;AACxD,cACE,OAAO,UAAU,YACjB,MAAM,KAAK,KACX,OAAO,gBAAgB,YACvB,YAAY,KAAK,GACjB;AACA,mBAAO,IAAI,YAAY;AAAA,cACrB,OAAO,MAAM,KAAK;AAAA,cAClB,aAAa,YAAY,KAAK;AAAA,cAC9B,UAAU,KAAK,IAAI,YAAY,QAAQ,IAAI;AAAA,YAC7C,CAAC;AAAA,UACH;AAAA,QACF,QAAQ;AAAA,QAAC;AACT,eAAO;AAAA,MACT;AAAA,MAEQ,uBAAuB,KAAkC;AAC/D,YAAI;AACF,gBAAM,WAAW;AACjB,iBAAQ,IAAY,gBAAgB,aAAa,IAAI,QAAQ,KAAK;AAAA,QACpE,QAAQ;AACN,iBAAO;AAAA,QACT;AAAA,MACF;AAAA,MAEA,MAAc,eACZ,KACA,OACA,SACA,UACe;AACf,YAAI,KAAK,cAAe;AACxB,cAAM,QAAQ,KAAK,SAAS,GAAG;AAC/B,YAAI,CAAC,MAAO;AACZ,cAAM,UAAU,KAAK,uBAAuB,GAAG;AAC/C,cAAM,kBACJ,SAAS;AACX,YAAI,CAAC,gBAAiB;AACtB,cAAM,KAAU,SAAS;AAEzB,YAAI,OAAO,GAAG,KAAK;AACnB,YAAI,SAAU,SAAQ;AAAA,SAAY,QAAQ;AAC1C,YAAI,QAAS,SAAQ;AAAA,EAAK,OAAO;AAEjC,cAAM,MAAM,YAAY;AAAA,UACtB,uBAAuB;AAAA,UACvB;AAAA,UACA,mBAAmB,IAAI;AAAA,QACzB,CAAC;AACD,aAAK,gBAAgB;AAAA,MACvB;AAAA,MAEA,MAAc,qBACZ,KACA,SACA,QACe;AACf,YAAI;AACF,gBAAM,MAAW,IAAI,UAAU,CAAC;AAChC,gBAAM,WAAgB,IAAI,SAAS,OAAO;AAC1C,cAAI,CAAC,SAAU;AAEf,gBAAM,eAAgB,SAAS,QAAmB;AAClD,gBAAM,OAAO,iBAAiB;AAC9B,gBAAM,YAAY,iBAAiB,SAAS,SAAS,UAAU;AAC/D,gBAAM,aAAa,iBAAiB;AACpC,cAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,WAAY;AACxC,cAAI,SAAS,gBAAgB,WAAY;AAGzC,cAAI,MAAM;AACR,kBAAM,SAAS,SAAS;AACxB,gBAAI,OAAO,WAAW,UAAU;AAC9B,oBAAM,gBAAgB,CAAC,eAAe,YAAY,QAAQ,OAAO;AACjE,kBAAI,CAAC,cAAc,SAAS,MAAM,EAAG;AAAA,YACvC;AAAA,UACF;AAEA,gBAAM,QAAQ,KAAK,SAAS,GAAG;AAC/B,cAAI,CAAC,MAAO;AAEZ,gBAAM,UAAU,KAAK,uBAAuB,GAAG;AAC/C,gBAAM,kBACJ,SAAS;AACX,cAAI,CAAC,iBAAiB;AACpB,gBAAI,OAAO;AAAA,cACT,2CAA2C,OAAO;AAAA,YACpD;AACA;AAAA,UACF;AACA,gBAAM,KAAU,SAAS;AAGzB,gBAAM,MAAY,QAAgB;AAClC,cAAI;AACJ,cAAI,OAAO,OAAO,IAAI,SAAS,YAAY,IAAI,KAAK,KAAK,EAAE,SAAS,GAAG;AACrE,mBAAO,IAAI,KAAK,KAAK;AAAA,UACvB,WAAW,QAAQ,OAAO,SAAS,WAAW,UAAU;AACtD,gBACE,OAAQ,QAAgB,YAAY,YACnC,OAAe,QAAQ,KAAK,EAAE,SAAS,GACxC;AACA,qBAAQ,OAAe,QAAQ,KAAK;AAAA,YACtC;AAAA,UACF,WAAW,aAAa,OAAQ,QAAgB,cAAc,UAAU;AACtE,kBAAM,MAAO,OAAe;AAC5B,gBAAI,IAAI,KAAK,EAAE,SAAS,EAAG,QAAO,IAAI,KAAK;AAAA,UAC7C;AAGA,cAAI,OAAO,OAAO,IAAI,eAAe,YAAY,IAAI,WAAW,KAAK,EAAE,SAAS,GAAG;AACjF,oBAAQ,QAAQ,MAAM,SAAS,IAAI,WAAW,KAAK;AAAA,UACrD;AAEA,cAAI,CAAC,MAAM;AACT,gBAAI,OAAO,KAAK,2CAA2C,OAAO,sBAAsB;AACxF;AAAA,UACF;AAGA,iBAAO,KAAK,QAAQ,QAAQ,IAAI;AAEhC,gBAAM,gBAAgB,gBAAgB,IAAI;AAC1C,gBAAM,aAAa,MAAM,MAAM,YAAY;AAAA,YACzC,uBAAuB;AAAA,YACvB,MAAM;AAAA,YACN,mBAAmB,IAAI;AAAA,UACzB,CAAC;AAED,cAAI,CAAC,WAAW,IAAI;AAClB,gBAAI,OAAO;AAAA,cACT,6CAA6C,OAAO,KAAK,WAAW,KAAK;AAAA,YAC3E;AACA;AAAA,UACF;AACA,cAAI,OAAO;AAAA,YACT,qCAAqC,OAAO,gBAAgB,WAAW,UAAU;AAAA,UACnF;AAAA,QACF,SAAS,KAAK;AACZ,cAAI;AACF,gBAAI,OAAO;AAAA,cACT,oDAAoD,OAAO,KACzD,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CACjD;AAAA,YACF;AAAA,UACF,QAAQ;AAAA,UAAC;AAAA,QACX;AAAA,MACF;AAAA,IACF;AAAA;AAAA;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../../src/telegram/markdown.ts","../../src/telegram/client.ts","../../src/frontends/telegram-frontend.ts"],"sourcesContent":["// Lightweight Markdown → Telegram HTML formatter.\n// Converts common Markdown output from AI steps to Telegram-compatible HTML.\n//\n// Supported conversions:\n// - # Header / ## Header → <b>Header</b>\n// - **bold** / __bold__ → <b>bold</b>\n// - *italic* → <i>italic</i>\n// - ~~strike~~ → <s>strike</s>\n// - `code` → <code>code</code>\n// - ```block``` → <pre>block</pre>\n// - [label](url) → <a href=\"url\">label</a>\n// - > blockquote → <blockquote>text</blockquote>\n// - HTML entities escaped: & < >\n//\n// Code blocks are passed through with entity escaping only (no other transforms).\n\n/** Escape HTML entities in text */\nexport function escapeHtml(text: string): string {\n return text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\n}\n\n/**\n * Convert Markdown text to Telegram-compatible HTML.\n * Processes line-by-line, respecting fenced code blocks.\n */\nexport function markdownToTelegramHtml(text: string): string {\n if (!text || typeof text !== 'string') return '';\n\n const lines = text.split(/\\r?\\n/);\n const result: string[] = [];\n let inCodeBlock = false;\n let codeBlockLang = '';\n let codeLines: string[] = [];\n let inBlockquote = false;\n let blockquoteLines: string[] = [];\n\n const flushBlockquote = () => {\n if (blockquoteLines.length > 0) {\n result.push(`<blockquote>${blockquoteLines.join('\\n')}</blockquote>`);\n blockquoteLines = [];\n inBlockquote = false;\n }\n };\n\n for (let i = 0; i < lines.length; i++) {\n const trimmed = lines[i].trimStart();\n\n // Track fenced code blocks\n if (/^```/.test(trimmed)) {\n if (!inCodeBlock) {\n flushBlockquote();\n inCodeBlock = true;\n codeBlockLang = trimmed.slice(3).trim();\n codeLines = [];\n } else {\n // Close code block\n const escaped = codeLines.map(l => escapeHtml(l)).join('\\n');\n if (codeBlockLang && codeBlockLang !== 'mermaid') {\n result.push(\n `<pre><code class=\"language-${escapeHtml(codeBlockLang)}\">${escaped}</code></pre>`\n );\n } else {\n result.push(`<pre>${escaped}</pre>`);\n }\n inCodeBlock = false;\n codeBlockLang = '';\n codeLines = [];\n }\n continue;\n }\n if (inCodeBlock) {\n codeLines.push(lines[i]);\n continue;\n }\n\n // Blockquotes: > text\n const bqMatch = /^>\\s?(.*)$/.exec(trimmed);\n if (bqMatch) {\n inBlockquote = true;\n blockquoteLines.push(convertInline(bqMatch[1]));\n continue;\n } else if (inBlockquote) {\n flushBlockquote();\n }\n\n const line = lines[i];\n\n // Headers: # Header → <b>Header</b>\n const headerMatch = /^(#{1,6})\\s+(.+)$/.exec(line.trimStart());\n if (headerMatch) {\n result.push(`<b>${convertInline(headerMatch[2].trim())}</b>`);\n continue;\n }\n\n // Horizontal rules\n if (/^[-*_]{3,}\\s*$/.test(trimmed)) {\n result.push('———');\n continue;\n }\n\n // Bullet lists: \"- item\" or \"* item\" → \"• item\"\n const bulletMatch = /^(\\s*)([-*])\\s+(.+)$/.exec(line);\n if (bulletMatch) {\n const indent = bulletMatch[1];\n result.push(`${indent}• ${convertInline(bulletMatch[3])}`);\n continue;\n }\n\n // Numbered lists: preserve as-is but convert inline\n const numMatch = /^(\\s*)(\\d+\\.)\\s+(.+)$/.exec(line);\n if (numMatch) {\n result.push(`${numMatch[1]}${numMatch[2]} ${convertInline(numMatch[3])}`);\n continue;\n }\n\n // Regular line: apply inline conversions\n result.push(convertInline(line));\n }\n\n // Close any unclosed code block\n if (inCodeBlock && codeLines.length > 0) {\n const escaped = codeLines.map(l => escapeHtml(l)).join('\\n');\n result.push(`<pre>${escaped}</pre>`);\n }\n flushBlockquote();\n\n return result.join('\\n');\n}\n\n/**\n * Apply inline Markdown conversions to a single line.\n * Order matters: escape HTML first, then apply formatting.\n */\nfunction convertInline(line: string): string {\n // First, identify and protect inline code spans\n const codeSpans: string[] = [];\n let processed = line.replace(/`([^`]+)`/g, (_m, code: string) => {\n const idx = codeSpans.length;\n codeSpans.push(`<code>${escapeHtml(code)}</code>`);\n return `\\x00CODE${idx}\\x00`;\n });\n\n // Escape HTML in non-code portions\n processed = escapeHtml(processed);\n\n // Images: ![alt](url) → (just show as link)\n processed = processed.replace(\n /!\\[([^\\]]*)\\]\\(([^)\\s]+)(?:\\s+&quot;[^&]*&quot;)?\\)/g,\n (_m, alt: string, url: string) => `<a href=\"${url}\">${alt || 'image'}</a>`\n );\n\n // Links: [label](url) → <a href=\"url\">label</a>\n processed = processed.replace(\n /\\[([^\\]]+)\\]\\(([^)\\s]+)(?:\\s+&quot;[^&]*&quot;)?\\)/g,\n (_m, label: string, url: string) => `<a href=\"${url}\">${label}</a>`\n );\n\n // Bold: **text** or __text__ → <b>text</b>\n processed = processed.replace(/\\*\\*([^*]+)\\*\\*/g, '<b>$1</b>');\n processed = processed.replace(/__([^_]+)__/g, '<b>$1</b>');\n\n // Italic: *text* → <i>text</i> (but not inside bold)\n processed = processed.replace(/(?<!\\*)\\*([^*]+)\\*(?!\\*)/g, '<i>$1</i>');\n\n // Strikethrough: ~~text~~ → <s>text</s>\n processed = processed.replace(/~~([^~]+)~~/g, '<s>$1</s>');\n\n // Restore code spans\n processed = processed.replace(\n /\\x00CODE(\\d+)\\x00/g,\n (_m, idx: string) => codeSpans[parseInt(idx)]\n );\n\n return processed;\n}\n\n/**\n * Chunk text into segments no larger than limit, splitting at newlines.\n * Respects code block boundaries where possible.\n */\nexport function chunkText(text: string, limit: number = 4096): string[] {\n if (text.length <= limit) return [text];\n\n const chunks: string[] = [];\n const lines = text.split('\\n');\n let current = '';\n\n for (const line of lines) {\n const candidate = current ? current + '\\n' + line : line;\n if (candidate.length > limit) {\n if (current) {\n chunks.push(current);\n current = line;\n } else {\n // Single line exceeds limit — force split\n let remaining = line;\n while (remaining.length > limit) {\n chunks.push(remaining.slice(0, limit));\n remaining = remaining.slice(limit);\n }\n current = remaining;\n }\n } else {\n current = candidate;\n }\n }\n if (current) chunks.push(current);\n\n return chunks;\n}\n\n/**\n * Main entry point: convert Markdown to Telegram HTML.\n */\nexport function formatTelegramText(text: string): string {\n return markdownToTelegramHtml(text);\n}\n","// Telegram Bot API wrapper built on grammy.\n// Exposes Visor-friendly methods matching the SlackClient pattern\n// while leveraging grammy for transport, rate limiting, and middleware.\n\nimport { Bot, type Api } from 'grammy';\nimport { chunkText } from './markdown';\n\nexport interface TelegramUser {\n id: number;\n is_bot: boolean;\n first_name: string;\n username?: string;\n}\n\nexport interface TelegramSendResult {\n ok: boolean;\n message_id?: number;\n error?: string;\n}\n\nexport class TelegramClient {\n private bot: Bot;\n private _botInfo: TelegramUser | null = null;\n\n constructor(botToken: string) {\n if (!botToken || typeof botToken !== 'string') {\n throw new Error('TelegramClient: botToken is required');\n }\n this.bot = new Bot(botToken);\n }\n\n /** Get the underlying grammy Bot instance (for polling runner) */\n getBot(): Bot {\n return this.bot;\n }\n\n /** Get the underlying grammy API instance */\n get api(): Api {\n return this.bot.api;\n }\n\n /** Initialize bot info (call before using) */\n async init(): Promise<TelegramUser> {\n const me = await this.bot.api.getMe();\n this._botInfo = {\n id: me.id,\n is_bot: me.is_bot,\n first_name: me.first_name,\n username: me.username,\n };\n return this._botInfo;\n }\n\n /** Get cached bot info */\n getBotInfo(): TelegramUser | null {\n return this._botInfo;\n }\n\n /**\n * Send a text message with optional HTML parse mode.\n * Auto-chunks messages exceeding 4096 characters.\n * Falls back to plain text if HTML parsing fails.\n */\n async sendMessage(opts: {\n chat_id: number | string;\n text: string;\n parse_mode?: 'HTML';\n reply_to_message_id?: number;\n message_thread_id?: number;\n }): Promise<TelegramSendResult> {\n try {\n const { chat_id, text, parse_mode, reply_to_message_id, message_thread_id } = opts;\n const chunks = chunkText(text, 4096);\n let firstMessageId: number | undefined;\n\n for (let i = 0; i < chunks.length; i++) {\n const params: Record<string, unknown> = {\n // disable_web_page_preview is deprecated, use link_preview_options\n link_preview_options: { is_disabled: true },\n };\n if (parse_mode) params.parse_mode = parse_mode;\n if (i === 0 && reply_to_message_id)\n params.reply_parameters = { message_id: reply_to_message_id };\n if (message_thread_id) params.message_thread_id = message_thread_id;\n\n try {\n const msg = await this.bot.api.sendMessage(chat_id, chunks[i], params as any);\n if (i === 0) firstMessageId = msg.message_id;\n } catch (err: any) {\n // If HTML parse fails, retry without parse_mode\n if (parse_mode === 'HTML' && err?.description?.includes(\"can't parse entities\")) {\n const plainParams = { ...params };\n delete plainParams.parse_mode;\n const msg = await this.bot.api.sendMessage(chat_id, chunks[i], plainParams as any);\n if (i === 0) firstMessageId = msg.message_id;\n } else {\n throw err;\n }\n }\n }\n\n return { ok: true, message_id: firstMessageId };\n } catch (err: any) {\n const errMsg = err?.description || err?.message || String(err);\n console.warn(`Telegram sendMessage failed (non-fatal): ${errMsg}`);\n return { ok: false, error: errMsg };\n }\n }\n\n /**\n * Send a document/file.\n */\n async sendDocument(opts: {\n chat_id: number | string;\n document: Buffer;\n filename: string;\n caption?: string;\n parse_mode?: 'HTML';\n reply_to_message_id?: number;\n message_thread_id?: number;\n }): Promise<TelegramSendResult> {\n try {\n const {\n chat_id,\n document,\n filename,\n caption,\n parse_mode,\n reply_to_message_id,\n message_thread_id,\n } = opts;\n const params: Record<string, unknown> = {};\n if (caption) params.caption = caption.slice(0, 1024); // Telegram caption limit\n if (parse_mode) params.parse_mode = parse_mode;\n if (reply_to_message_id) params.reply_parameters = { message_id: reply_to_message_id };\n if (message_thread_id) params.message_thread_id = message_thread_id;\n\n const file = new (await import('grammy')).InputFile(document, filename);\n const msg = await this.bot.api.sendDocument(chat_id, file, params as any);\n return { ok: true, message_id: msg.message_id };\n } catch (err: any) {\n const errMsg = err?.description || err?.message || String(err);\n console.warn(`Telegram sendDocument failed (non-fatal): ${errMsg}`);\n return { ok: false, error: errMsg };\n }\n }\n\n /**\n * Add an emoji reaction to a message.\n * Note: Bot must be admin in groups to set reactions.\n */\n async setMessageReaction(opts: {\n chat_id: number | string;\n message_id: number;\n emoji: string;\n }): Promise<boolean> {\n try {\n await this.bot.api.setMessageReaction(opts.chat_id, opts.message_id, [\n { type: 'emoji', emoji: opts.emoji as any },\n ]);\n return true;\n } catch (err: any) {\n // Non-fatal: reactions may fail if bot lacks permissions\n console.warn(\n `Telegram setMessageReaction failed (non-fatal): ${err?.description || err?.message || String(err)}`\n );\n return false;\n }\n }\n}\n","/**\n * Telegram Frontend for Visor workflows.\n *\n * Mirrors the SlackFrontend pattern:\n * - Posts AI replies to Telegram chats\n * - Converts Markdown to Telegram HTML format\n * - Manages emoji reactions for acknowledgement (👀 → 👍)\n */\nimport type { Frontend, FrontendContext } from './host';\nimport { TelegramClient } from '../telegram/client';\nimport { formatTelegramText } from '../telegram/markdown';\n\ntype TelegramFrontendConfig = {\n defaultChatId?: string | number;\n botToken?: string;\n};\n\nexport class TelegramFrontend implements Frontend {\n public readonly name = 'telegram';\n private subs: Array<{ unsubscribe(): void }> = [];\n private cfg: TelegramFrontendConfig;\n private acked: boolean = false;\n private ackRef: { chatId: number | string; messageId: number } | null = null;\n private errorNotified: boolean = false;\n\n constructor(config?: TelegramFrontendConfig) {\n this.cfg = config || {};\n }\n\n start(ctx: FrontendContext): void {\n const bus = ctx.eventBus;\n\n try {\n ctx.logger.info(`[telegram-frontend] started`);\n } catch {}\n\n // Log inbound event if triggered from Telegram\n try {\n const payload = this.getInboundTelegramPayload(ctx);\n if (payload) {\n const ev: any = payload.event || {};\n const chatId = String(ev.chat_id || '-');\n const msgId = String(ev.message_id || '-');\n ctx.logger.info(`[telegram-frontend] inbound event: chat_id=${chatId} message_id=${msgId}`);\n }\n } catch {}\n\n // CheckCompleted: post AI replies\n this.subs.push(\n bus.on('CheckCompleted', async (env: any) => {\n const ev = (env && env.payload) || env;\n await this.maybePostDirectReply(ctx, ev.checkId, ev.result).catch(() => {});\n })\n );\n\n // CheckErrored: post error notice\n this.subs.push(\n bus.on('CheckErrored', async (env: any) => {\n const ev = (env && env.payload) || env;\n const message = ev?.error?.message || 'Execution error';\n await this.maybePostError(ctx, 'Check failed', message, ev?.checkId).catch(() => {});\n })\n );\n\n // StateTransition: finalize reactions on terminal state\n this.subs.push(\n bus.on('StateTransition', async (env: any) => {\n const ev = (env && env.payload) || env;\n if (ev && (ev.to === 'Completed' || ev.to === 'Error')) {\n await this.finalizeReactions(ctx).catch(() => {});\n }\n })\n );\n\n // Shutdown: post error\n this.subs.push(\n bus.on('Shutdown', async (env: any) => {\n const ev = (env && env.payload) || env;\n const message = ev?.error?.message || 'Fatal error';\n await this.maybePostError(ctx, 'Run failed', message).catch(() => {});\n })\n );\n\n // CheckScheduled: add acknowledgement reaction\n this.subs.push(\n bus.on('CheckScheduled', async () => {\n await this.ensureAcknowledgement(ctx).catch(() => {});\n })\n );\n }\n\n stop(): void {\n for (const s of this.subs) s.unsubscribe();\n this.subs = [];\n }\n\n private getTelegram(ctx: FrontendContext): TelegramClient | undefined {\n // Prefer injected client (for tests or shared runner context)\n const injected = (ctx as any).telegram || (ctx as any).telegramClient;\n if (injected) return injected;\n // Lazy-create from env or frontend config\n try {\n const token = this.cfg.botToken || process.env.TELEGRAM_BOT_TOKEN;\n if (typeof token === 'string' && token.trim()) {\n return new TelegramClient(token.trim());\n }\n } catch {}\n return undefined;\n }\n\n private getInboundTelegramPayload(ctx: FrontendContext): any | null {\n try {\n const endpoint = '/bots/telegram/message';\n return (ctx as any).webhookContext?.webhookData?.get(endpoint) || null;\n } catch {\n return null;\n }\n }\n\n private getInboundTelegramEvent(\n ctx: FrontendContext\n ): { chatId: number | string; messageId: number } | null {\n try {\n const payload = this.getInboundTelegramPayload(ctx);\n const ev: any = payload?.event;\n const chatId = ev?.chat_id;\n const messageId = ev?.message_id;\n if (chatId !== undefined && messageId !== undefined) {\n return { chatId, messageId };\n }\n } catch {}\n return null;\n }\n\n private async ensureAcknowledgement(ctx: FrontendContext): Promise<void> {\n if (this.acked) return;\n const ref = this.getInboundTelegramEvent(ctx);\n if (!ref) return;\n const telegram = this.getTelegram(ctx);\n if (!telegram) return;\n\n // Skip ack for own bot messages\n try {\n const payload = this.getInboundTelegramPayload(ctx);\n const ev: any = payload?.event;\n const botInfo = telegram.getBotInfo();\n if (botInfo && ev?.from?.id === botInfo.id) return;\n } catch {}\n\n await telegram.setMessageReaction({\n chat_id: ref.chatId,\n message_id: ref.messageId,\n emoji: '👀',\n });\n try {\n ctx.logger.info(\n `[telegram-frontend] added ack reaction chat_id=${ref.chatId} message_id=${ref.messageId}`\n );\n } catch {}\n this.acked = true;\n this.ackRef = ref;\n }\n\n private async finalizeReactions(ctx: FrontendContext): Promise<void> {\n if (!this.acked || !this.ackRef) return;\n const telegram = this.getTelegram(ctx);\n if (!telegram) return;\n try {\n await telegram.setMessageReaction({\n chat_id: this.ackRef.chatId,\n message_id: this.ackRef.messageId,\n emoji: '👍',\n });\n try {\n ctx.logger.info(\n `[telegram-frontend] finalized reaction chat_id=${this.ackRef.chatId} message_id=${this.ackRef.messageId}`\n );\n } catch {}\n } finally {\n this.acked = false;\n this.ackRef = null;\n }\n }\n\n private async maybePostError(\n ctx: FrontendContext,\n title: string,\n message: string,\n checkId?: string\n ): Promise<void> {\n if (this.errorNotified) return;\n const telegram = this.getTelegram(ctx);\n if (!telegram) return;\n const payload = this.getInboundTelegramPayload(ctx);\n const ev: any = payload?.event;\n const chatId = ev?.chat_id;\n const messageId = ev?.message_id;\n if (chatId === undefined) return;\n\n let text = `❌ ${title}`;\n if (checkId) text += `\\nCheck: ${checkId}`;\n if (message) text += `\\n${message}`;\n\n await telegram.sendMessage({\n chat_id: chatId,\n text,\n reply_to_message_id: messageId,\n });\n this.errorNotified = true;\n }\n\n private async maybePostDirectReply(\n ctx: FrontendContext,\n checkId: string,\n result: { output?: any; content?: string }\n ): Promise<void> {\n try {\n const cfg: any = ctx.config || {};\n const checkCfg: any = cfg.checks?.[checkId];\n if (!checkCfg) return;\n\n const providerType = (checkCfg.type as string) || '';\n const isAi = providerType === 'ai';\n const isLogChat = providerType === 'log' && checkCfg.group === 'chat';\n const isWorkflow = providerType === 'workflow';\n if (!isAi && !isLogChat && !isWorkflow) return;\n if (checkCfg.criticality === 'internal') return;\n\n // For AI checks, only post simple schemas\n if (isAi) {\n const schema = checkCfg.schema;\n if (typeof schema === 'string') {\n const simpleSchemas = ['code-review', 'markdown', 'text', 'plain'];\n if (!simpleSchemas.includes(schema)) return;\n }\n }\n\n const telegram = this.getTelegram(ctx);\n if (!telegram) return;\n\n const payload = this.getInboundTelegramPayload(ctx);\n const ev: any = payload?.event;\n const chatId = ev?.chat_id;\n const messageId = ev?.message_id;\n if (chatId === undefined) {\n ctx.logger.warn(`[telegram-frontend] skip posting reply for ${checkId}: missing chat_id`);\n return;\n }\n\n // Extract text (same logic as SlackFrontend)\n const out: any = (result as any)?.output;\n let text: string | undefined;\n if (out && typeof out.text === 'string' && out.text.trim().length > 0) {\n text = out.text.trim();\n } else if (isAi && typeof checkCfg.schema === 'string') {\n if (\n typeof (result as any)?.content === 'string' &&\n (result as any).content.trim().length > 0\n ) {\n text = (result as any).content.trim();\n }\n } else if (isLogChat && typeof (result as any)?.logOutput === 'string') {\n const raw = (result as any).logOutput;\n if (raw.trim().length > 0) text = raw.trim();\n }\n\n // Append raw output\n if (out && typeof out._rawOutput === 'string' && out._rawOutput.trim().length > 0) {\n text = (text || '') + '\\n\\n' + out._rawOutput.trim();\n }\n\n if (!text) {\n ctx.logger.info(\n `[telegram-frontend] skip posting reply for ${checkId}: no renderable text`\n );\n return;\n }\n\n // Normalize literal \\n escape sequences\n text = text.replace(/\\\\n/g, '\\n');\n\n const formattedText = formatTelegramText(text);\n const postResult = await telegram.sendMessage({\n chat_id: chatId,\n text: formattedText,\n parse_mode: 'HTML',\n reply_to_message_id: messageId,\n message_thread_id: ev?.message_thread_id,\n });\n\n if (!postResult.ok) {\n ctx.logger.warn(\n `[telegram-frontend] failed to post reply for ${checkId}: ${postResult.error}`\n );\n return;\n }\n ctx.logger.info(\n `[telegram-frontend] posted reply for ${checkId} to chat_id=${chatId} message_id=${postResult.message_id}`\n );\n } catch (err) {\n try {\n ctx.logger.warn(\n `[telegram-frontend] maybePostDirectReply failed for ${checkId}: ${\n err instanceof Error ? err.message : String(err)\n }`\n );\n } catch {}\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,29 +0,0 @@
1
- import {
2
- __getOrCreateNdjsonPath,
3
- _appendRunMarker,
4
- addEvent,
5
- getTracer,
6
- getVisorRunAttributes,
7
- init_trace_helpers,
8
- setSpanAttributes,
9
- setSpanError,
10
- withActiveSpan,
11
- withVisorRun
12
- } from "./chunk-TFUQ2D5L.mjs";
13
- import "./chunk-MFXPJUUE.mjs";
14
- import "./chunk-34QX63WK.mjs";
15
- import "./chunk-UCMJJ3IM.mjs";
16
- import "./chunk-J7LXIPZS.mjs";
17
- init_trace_helpers();
18
- export {
19
- __getOrCreateNdjsonPath,
20
- _appendRunMarker,
21
- addEvent,
22
- getTracer,
23
- getVisorRunAttributes,
24
- setSpanAttributes,
25
- setSpanError,
26
- withActiveSpan,
27
- withVisorRun
28
- };
29
- //# sourceMappingURL=trace-helpers-XV5GAX5L.mjs.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}