langwatch 0.34.0 → 0.35.0

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 (774) hide show
  1. package/dist/{chunk-RIPASL56.mjs → chunk-2O4ILSP5.mjs} +2 -2
  2. package/dist/{chunk-2V5FBEY3.mjs → chunk-3QHURXIZ.mjs} +42 -5
  3. package/dist/chunk-3QHURXIZ.mjs.map +1 -0
  4. package/dist/{chunk-FSACIXYG.js → chunk-53AMPF5E.js} +16 -22
  5. package/dist/chunk-53AMPF5E.js.map +1 -0
  6. package/dist/{chunk-YKWXS2BM.js → chunk-EDWIKCYX.js} +130 -48
  7. package/dist/chunk-EDWIKCYX.js.map +1 -0
  8. package/dist/{chunk-QZRBNYW2.js → chunk-HBVGKWJK.js} +53 -16
  9. package/dist/chunk-HBVGKWJK.js.map +1 -0
  10. package/dist/{chunk-NTRV2ICJ.js → chunk-IUSLT65Z.js} +2 -2
  11. package/dist/{chunk-NTRV2ICJ.js.map → chunk-IUSLT65Z.js.map} +1 -1
  12. package/dist/{chunk-4ZA6WF6S.mjs → chunk-KH2GOLFO.mjs} +104 -22
  13. package/dist/chunk-KH2GOLFO.mjs.map +1 -0
  14. package/dist/{chunk-PONU4KJX.mjs → chunk-L5KBRKHS.mjs} +110 -5
  15. package/dist/chunk-L5KBRKHS.mjs.map +1 -0
  16. package/dist/chunk-TKSTXX3D.js +239 -0
  17. package/dist/chunk-TKSTXX3D.js.map +1 -0
  18. package/dist/{chunk-42EDFIG2.mjs → chunk-XMAFHMLS.mjs} +10 -16
  19. package/dist/{chunk-42EDFIG2.mjs.map → chunk-XMAFHMLS.mjs.map} +1 -1
  20. package/dist/cli/bundle.js +3768 -0
  21. package/dist/cli/index.js +10 -1335
  22. package/dist/{implementation-BIfcyP32.d.ts → implementation-CMWs8g5L.d.ts} +3 -3
  23. package/dist/{implementation-BBG46scL.d.mts → implementation-Cv1hPZBQ.d.mts} +3 -3
  24. package/dist/index.d.mts +125 -12
  25. package/dist/index.d.ts +125 -12
  26. package/dist/index.js +4840 -1410
  27. package/dist/index.js.map +1 -1
  28. package/dist/index.mjs +4788 -1358
  29. package/dist/index.mjs.map +1 -1
  30. package/dist/observability-sdk/index.d.mts +6 -6
  31. package/dist/observability-sdk/index.d.ts +6 -6
  32. package/dist/observability-sdk/index.js +5 -10
  33. package/dist/observability-sdk/index.js.map +1 -1
  34. package/dist/observability-sdk/index.mjs +5 -10
  35. package/dist/observability-sdk/instrumentation/langchain/index.d.mts +2 -2
  36. package/dist/observability-sdk/instrumentation/langchain/index.d.ts +2 -2
  37. package/dist/observability-sdk/instrumentation/langchain/index.js +18 -21
  38. package/dist/observability-sdk/instrumentation/langchain/index.js.map +1 -1
  39. package/dist/observability-sdk/instrumentation/langchain/index.mjs +3 -6
  40. package/dist/observability-sdk/instrumentation/langchain/index.mjs.map +1 -1
  41. package/dist/observability-sdk/setup/node/index.d.mts +2 -2
  42. package/dist/observability-sdk/setup/node/index.d.ts +2 -2
  43. package/dist/observability-sdk/setup/node/index.js +4 -8
  44. package/dist/observability-sdk/setup/node/index.js.map +1 -1
  45. package/dist/observability-sdk/setup/node/index.mjs +3 -7
  46. package/dist/{types-CYfKDbKj.d.ts → types-D-yAkWoC.d.ts} +71 -3
  47. package/dist/{types-Dmazk5Bk.d.mts → types-DLfhJb38.d.mts} +1 -1
  48. package/dist/{types-Dmazk5Bk.d.ts → types-DLfhJb38.d.ts} +1 -1
  49. package/dist/{types-BvCQH8F1.d.ts → types-VOZv9LYO.d.mts} +1 -1
  50. package/dist/{types-BvCQH8F1.d.mts → types-VOZv9LYO.d.ts} +1 -1
  51. package/dist/{types-fzTtg5sg.d.mts → types-bfBzGB7S.d.mts} +71 -3
  52. package/package.json +13 -6
  53. package/dist/add-TFE2BH4K.mjs +0 -148
  54. package/dist/add-TFE2BH4K.mjs.map +0 -1
  55. package/dist/add-URBA6FGV.js +0 -148
  56. package/dist/add-URBA6FGV.js.map +0 -1
  57. package/dist/archive-CL6XUEYU.mjs +0 -41
  58. package/dist/archive-CL6XUEYU.mjs.map +0 -1
  59. package/dist/archive-K4SSNBML.js +0 -41
  60. package/dist/archive-K4SSNBML.js.map +0 -1
  61. package/dist/assign-4PVKU4WO.mjs +0 -54
  62. package/dist/assign-4PVKU4WO.mjs.map +0 -1
  63. package/dist/assign-RFENMUXO.js +0 -54
  64. package/dist/assign-RFENMUXO.js.map +0 -1
  65. package/dist/chunk-2MITUTNI.js +0 -205
  66. package/dist/chunk-2MITUTNI.js.map +0 -1
  67. package/dist/chunk-2V5FBEY3.mjs.map +0 -1
  68. package/dist/chunk-2VVANTLB.js +0 -68
  69. package/dist/chunk-2VVANTLB.js.map +0 -1
  70. package/dist/chunk-377U47MY.js +0 -42
  71. package/dist/chunk-377U47MY.js.map +0 -1
  72. package/dist/chunk-3K6C35HN.mjs +0 -80
  73. package/dist/chunk-3K6C35HN.mjs.map +0 -1
  74. package/dist/chunk-3PZ5VO5T.mjs +0 -205
  75. package/dist/chunk-3PZ5VO5T.mjs.map +0 -1
  76. package/dist/chunk-4Q4HSAKZ.js +0 -894
  77. package/dist/chunk-4Q4HSAKZ.js.map +0 -1
  78. package/dist/chunk-4ZA6WF6S.mjs.map +0 -1
  79. package/dist/chunk-535JT5M3.mjs +0 -42
  80. package/dist/chunk-535JT5M3.mjs.map +0 -1
  81. package/dist/chunk-5M6GLAIG.js +0 -410
  82. package/dist/chunk-5M6GLAIG.js.map +0 -1
  83. package/dist/chunk-5PF32BLZ.mjs +0 -76
  84. package/dist/chunk-5PF32BLZ.mjs.map +0 -1
  85. package/dist/chunk-5W4B44MH.mjs +0 -103
  86. package/dist/chunk-5W4B44MH.mjs.map +0 -1
  87. package/dist/chunk-5Z3A3Z5M.mjs +0 -96
  88. package/dist/chunk-5Z3A3Z5M.mjs.map +0 -1
  89. package/dist/chunk-64H4FLDB.mjs +0 -51
  90. package/dist/chunk-64H4FLDB.mjs.map +0 -1
  91. package/dist/chunk-67PP4GB4.mjs +0 -40
  92. package/dist/chunk-67PP4GB4.mjs.map +0 -1
  93. package/dist/chunk-6KMX34ZH.js +0 -257
  94. package/dist/chunk-6KMX34ZH.js.map +0 -1
  95. package/dist/chunk-6RSHYGUB.js +0 -85
  96. package/dist/chunk-6RSHYGUB.js.map +0 -1
  97. package/dist/chunk-7HFW67OR.mjs +0 -63
  98. package/dist/chunk-7HFW67OR.mjs.map +0 -1
  99. package/dist/chunk-7KSBRJUY.js +0 -54
  100. package/dist/chunk-7KSBRJUY.js.map +0 -1
  101. package/dist/chunk-7ULZZHBP.mjs +0 -42
  102. package/dist/chunk-7ULZZHBP.mjs.map +0 -1
  103. package/dist/chunk-A6YWANGL.js +0 -103
  104. package/dist/chunk-A6YWANGL.js.map +0 -1
  105. package/dist/chunk-B5TBCV6N.js +0 -96
  106. package/dist/chunk-B5TBCV6N.js.map +0 -1
  107. package/dist/chunk-BAX4W3AY.mjs +0 -62
  108. package/dist/chunk-BAX4W3AY.mjs.map +0 -1
  109. package/dist/chunk-BGYXA2QV.mjs +0 -96
  110. package/dist/chunk-BGYXA2QV.mjs.map +0 -1
  111. package/dist/chunk-BRPEG3YQ.js +0 -62
  112. package/dist/chunk-BRPEG3YQ.js.map +0 -1
  113. package/dist/chunk-C5Y772G7.js +0 -152
  114. package/dist/chunk-C5Y772G7.js.map +0 -1
  115. package/dist/chunk-CEJY6QI3.mjs +0 -508
  116. package/dist/chunk-CEJY6QI3.mjs.map +0 -1
  117. package/dist/chunk-CGECDLSE.js +0 -90
  118. package/dist/chunk-CGECDLSE.js.map +0 -1
  119. package/dist/chunk-CKTJADY6.mjs +0 -348
  120. package/dist/chunk-CKTJADY6.mjs.map +0 -1
  121. package/dist/chunk-CLYXJJ6C.js +0 -66
  122. package/dist/chunk-CLYXJJ6C.js.map +0 -1
  123. package/dist/chunk-COMOCQA6.mjs +0 -13
  124. package/dist/chunk-COMOCQA6.mjs.map +0 -1
  125. package/dist/chunk-D2VRKNFF.js +0 -1672
  126. package/dist/chunk-D2VRKNFF.js.map +0 -1
  127. package/dist/chunk-D5NUUB4G.mjs +0 -225
  128. package/dist/chunk-D5NUUB4G.mjs.map +0 -1
  129. package/dist/chunk-DCTJDRBW.js +0 -40
  130. package/dist/chunk-DCTJDRBW.js.map +0 -1
  131. package/dist/chunk-DIILEB4J.js +0 -196
  132. package/dist/chunk-DIILEB4J.js.map +0 -1
  133. package/dist/chunk-DOJBPYAE.js +0 -663
  134. package/dist/chunk-DOJBPYAE.js.map +0 -1
  135. package/dist/chunk-DTEKJ3UD.mjs +0 -66
  136. package/dist/chunk-DTEKJ3UD.mjs.map +0 -1
  137. package/dist/chunk-FG3JQBJB.mjs +0 -68
  138. package/dist/chunk-FG3JQBJB.mjs.map +0 -1
  139. package/dist/chunk-FNFLZXXA.js +0 -80
  140. package/dist/chunk-FNFLZXXA.js.map +0 -1
  141. package/dist/chunk-FSACIXYG.js.map +0 -1
  142. package/dist/chunk-GFLV5NP6.mjs +0 -70
  143. package/dist/chunk-GFLV5NP6.mjs.map +0 -1
  144. package/dist/chunk-GNWMKXDU.mjs +0 -66
  145. package/dist/chunk-GNWMKXDU.mjs.map +0 -1
  146. package/dist/chunk-GPGJNBPP.js +0 -63
  147. package/dist/chunk-GPGJNBPP.js.map +0 -1
  148. package/dist/chunk-GUPNZDU7.js +0 -101
  149. package/dist/chunk-GUPNZDU7.js.map +0 -1
  150. package/dist/chunk-HDA25KWZ.js +0 -134
  151. package/dist/chunk-HDA25KWZ.js.map +0 -1
  152. package/dist/chunk-IZD5CIVE.js +0 -70
  153. package/dist/chunk-IZD5CIVE.js.map +0 -1
  154. package/dist/chunk-J3KM7ZO7.mjs +0 -152
  155. package/dist/chunk-J3KM7ZO7.mjs.map +0 -1
  156. package/dist/chunk-JQVI5CD7.mjs +0 -894
  157. package/dist/chunk-JQVI5CD7.mjs.map +0 -1
  158. package/dist/chunk-JSV75WAY.js +0 -76
  159. package/dist/chunk-JSV75WAY.js.map +0 -1
  160. package/dist/chunk-JZYHVNJR.js +0 -22
  161. package/dist/chunk-JZYHVNJR.js.map +0 -1
  162. package/dist/chunk-KT6HZNPV.js +0 -36
  163. package/dist/chunk-KT6HZNPV.js.map +0 -1
  164. package/dist/chunk-KW2W5KVS.mjs +0 -22
  165. package/dist/chunk-KW2W5KVS.mjs.map +0 -1
  166. package/dist/chunk-LA5LU5UP.js +0 -225
  167. package/dist/chunk-LA5LU5UP.js.map +0 -1
  168. package/dist/chunk-LSRJHTPL.js +0 -36
  169. package/dist/chunk-LSRJHTPL.js.map +0 -1
  170. package/dist/chunk-M3WJZUOE.js +0 -13
  171. package/dist/chunk-M3WJZUOE.js.map +0 -1
  172. package/dist/chunk-M5UNTGGK.mjs +0 -68
  173. package/dist/chunk-M5UNTGGK.mjs.map +0 -1
  174. package/dist/chunk-NQN42A2N.js +0 -348
  175. package/dist/chunk-NQN42A2N.js.map +0 -1
  176. package/dist/chunk-NYCKS3GG.js +0 -20
  177. package/dist/chunk-NYCKS3GG.js.map +0 -1
  178. package/dist/chunk-O2GHYEAE.mjs +0 -92
  179. package/dist/chunk-O2GHYEAE.mjs.map +0 -1
  180. package/dist/chunk-OGAE7BVQ.js +0 -67
  181. package/dist/chunk-OGAE7BVQ.js.map +0 -1
  182. package/dist/chunk-OMOZEGVZ.mjs +0 -22
  183. package/dist/chunk-OMOZEGVZ.mjs.map +0 -1
  184. package/dist/chunk-OMZ3FRPU.mjs +0 -65
  185. package/dist/chunk-OMZ3FRPU.mjs.map +0 -1
  186. package/dist/chunk-OOXU4LFW.js +0 -65
  187. package/dist/chunk-OOXU4LFW.js.map +0 -1
  188. package/dist/chunk-OSAFGMGH.mjs +0 -85
  189. package/dist/chunk-OSAFGMGH.mjs.map +0 -1
  190. package/dist/chunk-OXULVOBF.mjs +0 -144
  191. package/dist/chunk-OXULVOBF.mjs.map +0 -1
  192. package/dist/chunk-PONU4KJX.mjs.map +0 -1
  193. package/dist/chunk-PQA46YVG.mjs +0 -410
  194. package/dist/chunk-PQA46YVG.mjs.map +0 -1
  195. package/dist/chunk-Q6OMYVNW.js +0 -66
  196. package/dist/chunk-Q6OMYVNW.js.map +0 -1
  197. package/dist/chunk-Q7AHHFC3.mjs +0 -20
  198. package/dist/chunk-Q7AHHFC3.mjs.map +0 -1
  199. package/dist/chunk-QSMGACTW.js +0 -51
  200. package/dist/chunk-QSMGACTW.js.map +0 -1
  201. package/dist/chunk-QVQ7WDJS.mjs +0 -196
  202. package/dist/chunk-QVQ7WDJS.mjs.map +0 -1
  203. package/dist/chunk-QZRBNYW2.js.map +0 -1
  204. package/dist/chunk-R6QPBFZD.mjs +0 -63
  205. package/dist/chunk-R6QPBFZD.mjs.map +0 -1
  206. package/dist/chunk-RALJR5ZU.js +0 -80
  207. package/dist/chunk-RALJR5ZU.js.map +0 -1
  208. package/dist/chunk-S2UWK4HL.mjs +0 -36
  209. package/dist/chunk-S2UWK4HL.mjs.map +0 -1
  210. package/dist/chunk-SIXSSID3.mjs +0 -43
  211. package/dist/chunk-SIXSSID3.mjs.map +0 -1
  212. package/dist/chunk-SNKGSX5I.js +0 -42
  213. package/dist/chunk-SNKGSX5I.js.map +0 -1
  214. package/dist/chunk-SQXVLXIS.mjs +0 -90
  215. package/dist/chunk-SQXVLXIS.mjs.map +0 -1
  216. package/dist/chunk-TIAQGDR2.js +0 -34
  217. package/dist/chunk-TIAQGDR2.js.map +0 -1
  218. package/dist/chunk-U47MQ6CS.mjs +0 -67
  219. package/dist/chunk-U47MQ6CS.mjs.map +0 -1
  220. package/dist/chunk-UQ633TEF.mjs +0 -54
  221. package/dist/chunk-UQ633TEF.mjs.map +0 -1
  222. package/dist/chunk-UTXV7U7Z.js +0 -92
  223. package/dist/chunk-UTXV7U7Z.js.map +0 -1
  224. package/dist/chunk-W2BNKVWJ.mjs +0 -36
  225. package/dist/chunk-W2BNKVWJ.mjs.map +0 -1
  226. package/dist/chunk-WG7MPZXJ.mjs +0 -663
  227. package/dist/chunk-WG7MPZXJ.mjs.map +0 -1
  228. package/dist/chunk-WIXX2IDN.mjs +0 -101
  229. package/dist/chunk-WIXX2IDN.mjs.map +0 -1
  230. package/dist/chunk-WQRATXQU.mjs +0 -80
  231. package/dist/chunk-WQRATXQU.mjs.map +0 -1
  232. package/dist/chunk-WV4U2PPY.js +0 -68
  233. package/dist/chunk-WV4U2PPY.js.map +0 -1
  234. package/dist/chunk-WZTRPR6A.js +0 -43
  235. package/dist/chunk-WZTRPR6A.js.map +0 -1
  236. package/dist/chunk-XGULH63G.mjs +0 -1672
  237. package/dist/chunk-XGULH63G.mjs.map +0 -1
  238. package/dist/chunk-YBLYQYXL.js +0 -22
  239. package/dist/chunk-YBLYQYXL.js.map +0 -1
  240. package/dist/chunk-YK55ZGRQ.mjs +0 -257
  241. package/dist/chunk-YK55ZGRQ.mjs.map +0 -1
  242. package/dist/chunk-YKDTIJF2.js +0 -144
  243. package/dist/chunk-YKDTIJF2.js.map +0 -1
  244. package/dist/chunk-YKWXS2BM.js.map +0 -1
  245. package/dist/chunk-YOSDU6PV.mjs +0 -34
  246. package/dist/chunk-YOSDU6PV.mjs.map +0 -1
  247. package/dist/chunk-YP4LDCP6.mjs +0 -277
  248. package/dist/chunk-YP4LDCP6.mjs.map +0 -1
  249. package/dist/chunk-ZA5BH7IZ.js +0 -277
  250. package/dist/chunk-ZA5BH7IZ.js.map +0 -1
  251. package/dist/chunk-ZFAAOZZM.js +0 -96
  252. package/dist/chunk-ZFAAOZZM.js.map +0 -1
  253. package/dist/chunk-ZFFJYYDN.js +0 -508
  254. package/dist/chunk-ZFFJYYDN.js.map +0 -1
  255. package/dist/chunk-ZX6VUKK5.js +0 -63
  256. package/dist/chunk-ZX6VUKK5.js.map +0 -1
  257. package/dist/cli/index.d.mts +0 -1
  258. package/dist/cli/index.d.ts +0 -1
  259. package/dist/cli/index.js.map +0 -1
  260. package/dist/cli/index.mjs +0 -1336
  261. package/dist/cli/index.mjs.map +0 -1
  262. package/dist/config-DPFYZQUU.js +0 -96
  263. package/dist/config-DPFYZQUU.js.map +0 -1
  264. package/dist/config-DXWUTPTA.mjs +0 -96
  265. package/dist/config-DXWUTPTA.mjs.map +0 -1
  266. package/dist/create-2MUVHIRR.js +0 -49
  267. package/dist/create-2MUVHIRR.js.map +0 -1
  268. package/dist/create-2VO6N4CY.js +0 -50
  269. package/dist/create-2VO6N4CY.js.map +0 -1
  270. package/dist/create-5HLREIKR.mjs +0 -52
  271. package/dist/create-5HLREIKR.mjs.map +0 -1
  272. package/dist/create-7WWQNO2D.mjs +0 -88
  273. package/dist/create-7WWQNO2D.mjs.map +0 -1
  274. package/dist/create-APC6WMHS.js +0 -72
  275. package/dist/create-APC6WMHS.js.map +0 -1
  276. package/dist/create-B6AZP3AH.js +0 -42
  277. package/dist/create-B6AZP3AH.js.map +0 -1
  278. package/dist/create-BWIIJPYN.js +0 -88
  279. package/dist/create-BWIIJPYN.js.map +0 -1
  280. package/dist/create-C7HS7DAN.js +0 -91
  281. package/dist/create-C7HS7DAN.js.map +0 -1
  282. package/dist/create-CENOO2Z5.mjs +0 -94
  283. package/dist/create-CENOO2Z5.mjs.map +0 -1
  284. package/dist/create-CSENTPZ7.mjs +0 -88
  285. package/dist/create-CSENTPZ7.mjs.map +0 -1
  286. package/dist/create-F564PPYR.mjs +0 -72
  287. package/dist/create-F564PPYR.mjs.map +0 -1
  288. package/dist/create-FEVRMAGI.js +0 -75
  289. package/dist/create-FEVRMAGI.js.map +0 -1
  290. package/dist/create-FK6ZCXCA.js +0 -92
  291. package/dist/create-FK6ZCXCA.js.map +0 -1
  292. package/dist/create-G5KF3LVC.mjs +0 -50
  293. package/dist/create-G5KF3LVC.mjs.map +0 -1
  294. package/dist/create-HL6BPJBM.mjs +0 -71
  295. package/dist/create-HL6BPJBM.mjs.map +0 -1
  296. package/dist/create-KFDWNSGC.mjs +0 -87
  297. package/dist/create-KFDWNSGC.mjs.map +0 -1
  298. package/dist/create-KTPZZ7NV.mjs +0 -75
  299. package/dist/create-KTPZZ7NV.mjs.map +0 -1
  300. package/dist/create-LAKPCRNY.mjs +0 -92
  301. package/dist/create-LAKPCRNY.mjs.map +0 -1
  302. package/dist/create-LFU7Z6DS.mjs +0 -42
  303. package/dist/create-LFU7Z6DS.mjs.map +0 -1
  304. package/dist/create-MI7MQLN6.mjs +0 -48
  305. package/dist/create-MI7MQLN6.mjs.map +0 -1
  306. package/dist/create-OMO3TETI.mjs +0 -23
  307. package/dist/create-OMO3TETI.mjs.map +0 -1
  308. package/dist/create-OWODQWNJ.js +0 -48
  309. package/dist/create-OWODQWNJ.js.map +0 -1
  310. package/dist/create-POGAVC3B.mjs +0 -49
  311. package/dist/create-POGAVC3B.mjs.map +0 -1
  312. package/dist/create-QJLKTHQ6.mjs +0 -58
  313. package/dist/create-QJLKTHQ6.mjs.map +0 -1
  314. package/dist/create-R57TZY3Y.js +0 -94
  315. package/dist/create-R57TZY3Y.js.map +0 -1
  316. package/dist/create-RIHQJENZ.js +0 -71
  317. package/dist/create-RIHQJENZ.js.map +0 -1
  318. package/dist/create-UOIUDY25.js +0 -88
  319. package/dist/create-UOIUDY25.js.map +0 -1
  320. package/dist/create-URUJVBUC.js +0 -87
  321. package/dist/create-URUJVBUC.js.map +0 -1
  322. package/dist/create-VEK55UDK.mjs +0 -43
  323. package/dist/create-VEK55UDK.mjs.map +0 -1
  324. package/dist/create-VKXRDN5O.js +0 -52
  325. package/dist/create-VKXRDN5O.js.map +0 -1
  326. package/dist/create-XHAKNOTS.mjs +0 -91
  327. package/dist/create-XHAKNOTS.mjs.map +0 -1
  328. package/dist/create-YJHDG2ZO.js +0 -23
  329. package/dist/create-YJHDG2ZO.js.map +0 -1
  330. package/dist/create-Z5CM76ZW.js +0 -43
  331. package/dist/create-Z5CM76ZW.js.map +0 -1
  332. package/dist/create-Z6JTQNL6.js +0 -58
  333. package/dist/create-Z6JTQNL6.js.map +0 -1
  334. package/dist/delete-6BINMYZI.mjs +0 -52
  335. package/dist/delete-6BINMYZI.mjs.map +0 -1
  336. package/dist/delete-6T5CCDFJ.js +0 -42
  337. package/dist/delete-6T5CCDFJ.js.map +0 -1
  338. package/dist/delete-6UHWYVNZ.js +0 -52
  339. package/dist/delete-6UHWYVNZ.js.map +0 -1
  340. package/dist/delete-A5RWDQKJ.js +0 -52
  341. package/dist/delete-A5RWDQKJ.js.map +0 -1
  342. package/dist/delete-A7ZWGQPR.mjs +0 -59
  343. package/dist/delete-A7ZWGQPR.mjs.map +0 -1
  344. package/dist/delete-B5G7GAHY.mjs +0 -44
  345. package/dist/delete-B5G7GAHY.mjs.map +0 -1
  346. package/dist/delete-BGCVEG3C.js +0 -61
  347. package/dist/delete-BGCVEG3C.js.map +0 -1
  348. package/dist/delete-BYCIZOZG.js +0 -39
  349. package/dist/delete-BYCIZOZG.js.map +0 -1
  350. package/dist/delete-E5VYCRYX.mjs +0 -39
  351. package/dist/delete-E5VYCRYX.mjs.map +0 -1
  352. package/dist/delete-EK6PUMYW.js +0 -52
  353. package/dist/delete-EK6PUMYW.js.map +0 -1
  354. package/dist/delete-ERB4LGWZ.mjs +0 -41
  355. package/dist/delete-ERB4LGWZ.mjs.map +0 -1
  356. package/dist/delete-FD3IISGJ.js +0 -38
  357. package/dist/delete-FD3IISGJ.js.map +0 -1
  358. package/dist/delete-FE3MRFPM.mjs +0 -52
  359. package/dist/delete-FE3MRFPM.mjs.map +0 -1
  360. package/dist/delete-FP5MMDDA.mjs +0 -61
  361. package/dist/delete-FP5MMDDA.mjs.map +0 -1
  362. package/dist/delete-FWKI62NT.mjs +0 -39
  363. package/dist/delete-FWKI62NT.mjs.map +0 -1
  364. package/dist/delete-HLKQDPTI.js +0 -52
  365. package/dist/delete-HLKQDPTI.js.map +0 -1
  366. package/dist/delete-KAVDMRQX.mjs +0 -59
  367. package/dist/delete-KAVDMRQX.mjs.map +0 -1
  368. package/dist/delete-M4ZCKWOU.mjs +0 -52
  369. package/dist/delete-M4ZCKWOU.mjs.map +0 -1
  370. package/dist/delete-NGPOOTEX.mjs +0 -42
  371. package/dist/delete-NGPOOTEX.mjs.map +0 -1
  372. package/dist/delete-NN4CSTK5.js +0 -44
  373. package/dist/delete-NN4CSTK5.js.map +0 -1
  374. package/dist/delete-NRW5THMB.js +0 -39
  375. package/dist/delete-NRW5THMB.js.map +0 -1
  376. package/dist/delete-SZG6DJUR.mjs +0 -52
  377. package/dist/delete-SZG6DJUR.mjs.map +0 -1
  378. package/dist/delete-UMDNW3RR.mjs +0 -59
  379. package/dist/delete-UMDNW3RR.mjs.map +0 -1
  380. package/dist/delete-UVGITJ2L.mjs +0 -38
  381. package/dist/delete-UVGITJ2L.mjs.map +0 -1
  382. package/dist/delete-VBP7TKUH.js +0 -41
  383. package/dist/delete-VBP7TKUH.js.map +0 -1
  384. package/dist/delete-Y3DTH336.js +0 -59
  385. package/dist/delete-Y3DTH336.js.map +0 -1
  386. package/dist/delete-ZM3GFW2Z.js +0 -59
  387. package/dist/delete-ZM3GFW2Z.js.map +0 -1
  388. package/dist/delete-ZSN6PWGA.js +0 -59
  389. package/dist/delete-ZSN6PWGA.js.map +0 -1
  390. package/dist/docs-23TMQCLZ.js +0 -77
  391. package/dist/docs-23TMQCLZ.js.map +0 -1
  392. package/dist/docs-YG2DQVHD.mjs +0 -77
  393. package/dist/docs-YG2DQVHD.mjs.map +0 -1
  394. package/dist/download-B4Z4TAXZ.js +0 -100
  395. package/dist/download-B4Z4TAXZ.js.map +0 -1
  396. package/dist/download-JPL3BO4H.mjs +0 -100
  397. package/dist/download-JPL3BO4H.mjs.map +0 -1
  398. package/dist/duplicate-IYUSDPY2.js +0 -45
  399. package/dist/duplicate-IYUSDPY2.js.map +0 -1
  400. package/dist/duplicate-OWG7P745.mjs +0 -45
  401. package/dist/duplicate-OWG7P745.mjs.map +0 -1
  402. package/dist/export-4A6ILAPM.mjs +0 -103
  403. package/dist/export-4A6ILAPM.mjs.map +0 -1
  404. package/dist/export-BUFJDFWC.js +0 -103
  405. package/dist/export-BUFJDFWC.js.map +0 -1
  406. package/dist/get-37E7GAV3.js +0 -76
  407. package/dist/get-37E7GAV3.js.map +0 -1
  408. package/dist/get-4D2MVW4T.js +0 -49
  409. package/dist/get-4D2MVW4T.js.map +0 -1
  410. package/dist/get-576OERBE.mjs +0 -66
  411. package/dist/get-576OERBE.mjs.map +0 -1
  412. package/dist/get-5GQP5EDN.mjs +0 -71
  413. package/dist/get-5GQP5EDN.mjs.map +0 -1
  414. package/dist/get-6DKM4MZL.mjs +0 -70
  415. package/dist/get-6DKM4MZL.mjs.map +0 -1
  416. package/dist/get-BO7KWXNS.js +0 -70
  417. package/dist/get-BO7KWXNS.js.map +0 -1
  418. package/dist/get-BQH2FJBV.mjs +0 -49
  419. package/dist/get-BQH2FJBV.mjs.map +0 -1
  420. package/dist/get-DCEQN75Y.mjs +0 -71
  421. package/dist/get-DCEQN75Y.mjs.map +0 -1
  422. package/dist/get-DEFHJ7CN.js +0 -94
  423. package/dist/get-DEFHJ7CN.js.map +0 -1
  424. package/dist/get-DX5U344V.mjs +0 -149
  425. package/dist/get-DX5U344V.mjs.map +0 -1
  426. package/dist/get-EWYM6FYK.js +0 -54
  427. package/dist/get-EWYM6FYK.js.map +0 -1
  428. package/dist/get-HY3N72VT.js +0 -71
  429. package/dist/get-HY3N72VT.js.map +0 -1
  430. package/dist/get-I2CSBUKB.js +0 -56
  431. package/dist/get-I2CSBUKB.js.map +0 -1
  432. package/dist/get-I6EY4PC6.mjs +0 -54
  433. package/dist/get-I6EY4PC6.mjs.map +0 -1
  434. package/dist/get-JDHZ2YUC.mjs +0 -85
  435. package/dist/get-JDHZ2YUC.mjs.map +0 -1
  436. package/dist/get-KSATLDNX.mjs +0 -56
  437. package/dist/get-KSATLDNX.mjs.map +0 -1
  438. package/dist/get-L5HUN5CE.mjs +0 -94
  439. package/dist/get-L5HUN5CE.mjs.map +0 -1
  440. package/dist/get-LIQYXM3J.mjs +0 -76
  441. package/dist/get-LIQYXM3J.mjs.map +0 -1
  442. package/dist/get-NICBHRKG.js +0 -51
  443. package/dist/get-NICBHRKG.js.map +0 -1
  444. package/dist/get-NXV4JPXT.mjs +0 -51
  445. package/dist/get-NXV4JPXT.mjs.map +0 -1
  446. package/dist/get-OH6XFEO7.js +0 -149
  447. package/dist/get-OH6XFEO7.js.map +0 -1
  448. package/dist/get-OW77HE3C.mjs +0 -67
  449. package/dist/get-OW77HE3C.mjs.map +0 -1
  450. package/dist/get-P5MUOCUP.js +0 -68
  451. package/dist/get-P5MUOCUP.js.map +0 -1
  452. package/dist/get-PHEE7JVL.mjs +0 -71
  453. package/dist/get-PHEE7JVL.mjs.map +0 -1
  454. package/dist/get-QYIM3DCN.mjs +0 -68
  455. package/dist/get-QYIM3DCN.mjs.map +0 -1
  456. package/dist/get-R6F56IVZ.js +0 -67
  457. package/dist/get-R6F56IVZ.js.map +0 -1
  458. package/dist/get-RWF3UWIF.js +0 -71
  459. package/dist/get-RWF3UWIF.js.map +0 -1
  460. package/dist/get-T6TAL2GB.js +0 -52
  461. package/dist/get-T6TAL2GB.js.map +0 -1
  462. package/dist/get-TNDPILF3.js +0 -85
  463. package/dist/get-TNDPILF3.js.map +0 -1
  464. package/dist/get-UV3YT4VH.js +0 -66
  465. package/dist/get-UV3YT4VH.js.map +0 -1
  466. package/dist/get-X4Q4RZQC.mjs +0 -52
  467. package/dist/get-X4Q4RZQC.mjs.map +0 -1
  468. package/dist/get-XIK4FEGG.js +0 -71
  469. package/dist/get-XIK4FEGG.js.map +0 -1
  470. package/dist/health-LCGP7UDT.js +0 -73
  471. package/dist/health-LCGP7UDT.js.map +0 -1
  472. package/dist/health-MCMRR6RQ.mjs +0 -73
  473. package/dist/health-MCMRR6RQ.mjs.map +0 -1
  474. package/dist/ingestion-templates-7TLETXIF.mjs +0 -169
  475. package/dist/ingestion-templates-7TLETXIF.mjs.map +0 -1
  476. package/dist/ingestion-templates-AT5AKWJB.js +0 -169
  477. package/dist/ingestion-templates-AT5AKWJB.js.map +0 -1
  478. package/dist/init-SQ5UUFDM.js +0 -16
  479. package/dist/init-SQ5UUFDM.js.map +0 -1
  480. package/dist/init-UGSR2T2P.mjs +0 -16
  481. package/dist/init-UGSR2T2P.mjs.map +0 -1
  482. package/dist/init-shell-2JQCBGMG.mjs +0 -71
  483. package/dist/init-shell-2JQCBGMG.mjs.map +0 -1
  484. package/dist/init-shell-UDTYTWJ4.js +0 -71
  485. package/dist/init-shell-UDTYTWJ4.js.map +0 -1
  486. package/dist/install-JNBCGN7Q.mjs +0 -191
  487. package/dist/install-JNBCGN7Q.mjs.map +0 -1
  488. package/dist/install-VBJKW5WP.js +0 -191
  489. package/dist/install-VBJKW5WP.js.map +0 -1
  490. package/dist/list-2ALO3KFG.js +0 -87
  491. package/dist/list-2ALO3KFG.js.map +0 -1
  492. package/dist/list-2YGHM2AD.mjs +0 -76
  493. package/dist/list-2YGHM2AD.mjs.map +0 -1
  494. package/dist/list-3XJ7VZN4.mjs +0 -75
  495. package/dist/list-3XJ7VZN4.mjs.map +0 -1
  496. package/dist/list-47FO2DBS.js +0 -80
  497. package/dist/list-47FO2DBS.js.map +0 -1
  498. package/dist/list-4JFVZU6U.mjs +0 -78
  499. package/dist/list-4JFVZU6U.mjs.map +0 -1
  500. package/dist/list-5DNRGKML.mjs +0 -80
  501. package/dist/list-5DNRGKML.mjs.map +0 -1
  502. package/dist/list-6CPPEJQV.js +0 -75
  503. package/dist/list-6CPPEJQV.js.map +0 -1
  504. package/dist/list-6UYNGBNA.mjs +0 -75
  505. package/dist/list-6UYNGBNA.mjs.map +0 -1
  506. package/dist/list-7F3TLLLA.js +0 -85
  507. package/dist/list-7F3TLLLA.js.map +0 -1
  508. package/dist/list-AVYXRPYR.mjs +0 -53
  509. package/dist/list-AVYXRPYR.mjs.map +0 -1
  510. package/dist/list-B5QJP7XO.mjs +0 -122
  511. package/dist/list-B5QJP7XO.mjs.map +0 -1
  512. package/dist/list-BI6VDR3L.mjs +0 -80
  513. package/dist/list-BI6VDR3L.mjs.map +0 -1
  514. package/dist/list-BIXZNQNL.mjs +0 -90
  515. package/dist/list-BIXZNQNL.mjs.map +0 -1
  516. package/dist/list-E2NKP4RN.mjs +0 -71
  517. package/dist/list-E2NKP4RN.mjs.map +0 -1
  518. package/dist/list-EX74E4W3.js +0 -82
  519. package/dist/list-EX74E4W3.js.map +0 -1
  520. package/dist/list-F7RK6OGO.js +0 -71
  521. package/dist/list-F7RK6OGO.js.map +0 -1
  522. package/dist/list-FQVXBMOV.js +0 -82
  523. package/dist/list-FQVXBMOV.js.map +0 -1
  524. package/dist/list-FTAHO7RS.js +0 -53
  525. package/dist/list-FTAHO7RS.js.map +0 -1
  526. package/dist/list-HJFLTMZZ.js +0 -80
  527. package/dist/list-HJFLTMZZ.js.map +0 -1
  528. package/dist/list-HZCZZBHB.js +0 -83
  529. package/dist/list-HZCZZBHB.js.map +0 -1
  530. package/dist/list-IIUX33VL.mjs +0 -86
  531. package/dist/list-IIUX33VL.mjs.map +0 -1
  532. package/dist/list-JFASUTLY.js +0 -78
  533. package/dist/list-JFASUTLY.js.map +0 -1
  534. package/dist/list-KJIOIAVI.mjs +0 -80
  535. package/dist/list-KJIOIAVI.mjs.map +0 -1
  536. package/dist/list-LKNXTUMI.js +0 -104
  537. package/dist/list-LKNXTUMI.js.map +0 -1
  538. package/dist/list-M34E5BJ5.js +0 -80
  539. package/dist/list-M34E5BJ5.js.map +0 -1
  540. package/dist/list-MX4GYY6P.mjs +0 -87
  541. package/dist/list-MX4GYY6P.mjs.map +0 -1
  542. package/dist/list-O5SCIB3L.js +0 -75
  543. package/dist/list-O5SCIB3L.js.map +0 -1
  544. package/dist/list-O6OJ5XHC.mjs +0 -72
  545. package/dist/list-O6OJ5XHC.mjs.map +0 -1
  546. package/dist/list-ODC5L7LD.mjs +0 -83
  547. package/dist/list-ODC5L7LD.mjs.map +0 -1
  548. package/dist/list-Q5WBWW4Q.mjs +0 -82
  549. package/dist/list-Q5WBWW4Q.mjs.map +0 -1
  550. package/dist/list-QA563QDB.js +0 -90
  551. package/dist/list-QA563QDB.js.map +0 -1
  552. package/dist/list-RJFCSUUQ.mjs +0 -111
  553. package/dist/list-RJFCSUUQ.mjs.map +0 -1
  554. package/dist/list-RMHLZBQG.js +0 -76
  555. package/dist/list-RMHLZBQG.js.map +0 -1
  556. package/dist/list-SRYZRJCV.js +0 -111
  557. package/dist/list-SRYZRJCV.js.map +0 -1
  558. package/dist/list-TOSZ7BU7.js +0 -86
  559. package/dist/list-TOSZ7BU7.js.map +0 -1
  560. package/dist/list-UQQ2PAU3.mjs +0 -104
  561. package/dist/list-UQQ2PAU3.mjs.map +0 -1
  562. package/dist/list-V2WO7LLU.js +0 -72
  563. package/dist/list-V2WO7LLU.js.map +0 -1
  564. package/dist/list-VA5A3CCK.mjs +0 -75
  565. package/dist/list-VA5A3CCK.mjs.map +0 -1
  566. package/dist/list-X6EIZ5MP.js +0 -75
  567. package/dist/list-X6EIZ5MP.js.map +0 -1
  568. package/dist/list-YUYYYQ7E.js +0 -122
  569. package/dist/list-YUYYYQ7E.js.map +0 -1
  570. package/dist/list-Z4GK3RXW.js +0 -78
  571. package/dist/list-Z4GK3RXW.js.map +0 -1
  572. package/dist/list-ZBKYVBPN.mjs +0 -85
  573. package/dist/list-ZBKYVBPN.mjs.map +0 -1
  574. package/dist/list-ZDLAHVOP.mjs +0 -78
  575. package/dist/list-ZDLAHVOP.mjs.map +0 -1
  576. package/dist/list-ZONPFTHT.mjs +0 -82
  577. package/dist/list-ZONPFTHT.mjs.map +0 -1
  578. package/dist/login-UWJ4SQ3T.mjs +0 -279
  579. package/dist/login-UWJ4SQ3T.mjs.map +0 -1
  580. package/dist/login-Y3TEPZOC.js +0 -279
  581. package/dist/login-Y3TEPZOC.js.map +0 -1
  582. package/dist/logout-RTWQU22E.mjs +0 -181
  583. package/dist/logout-RTWQU22E.mjs.map +0 -1
  584. package/dist/logout-TXOAFCK7.js +0 -181
  585. package/dist/logout-TXOAFCK7.js.map +0 -1
  586. package/dist/open-2IGFGDDB.mjs +0 -47
  587. package/dist/open-2IGFGDDB.mjs.map +0 -1
  588. package/dist/open-TCBDPKWM.js +0 -47
  589. package/dist/open-TCBDPKWM.js.map +0 -1
  590. package/dist/pull-3MXPXKVF.mjs +0 -27
  591. package/dist/pull-3MXPXKVF.mjs.map +0 -1
  592. package/dist/pull-5RX2YX5P.js +0 -27
  593. package/dist/pull-5RX2YX5P.js.map +0 -1
  594. package/dist/push-7L3NXCCJ.mjs +0 -27
  595. package/dist/push-7L3NXCCJ.mjs.map +0 -1
  596. package/dist/push-QPS47QAN.js +0 -27
  597. package/dist/push-QPS47QAN.js.map +0 -1
  598. package/dist/query-2PAEPPLR.js +0 -122
  599. package/dist/query-2PAEPPLR.js.map +0 -1
  600. package/dist/query-FJ4JJLRH.mjs +0 -122
  601. package/dist/query-FJ4JJLRH.mjs.map +0 -1
  602. package/dist/records-add-K6ZRY3MM.mjs +0 -98
  603. package/dist/records-add-K6ZRY3MM.mjs.map +0 -1
  604. package/dist/records-add-OQK2SWSP.js +0 -98
  605. package/dist/records-add-OQK2SWSP.js.map +0 -1
  606. package/dist/records-delete-DPNRLQRU.mjs +0 -46
  607. package/dist/records-delete-DPNRLQRU.mjs.map +0 -1
  608. package/dist/records-delete-UC3XJNIF.js +0 -46
  609. package/dist/records-delete-UC3XJNIF.js.map +0 -1
  610. package/dist/records-list-AC7ADD4R.js +0 -89
  611. package/dist/records-list-AC7ADD4R.js.map +0 -1
  612. package/dist/records-list-EEDFGR5M.mjs +0 -89
  613. package/dist/records-list-EEDFGR5M.mjs.map +0 -1
  614. package/dist/records-update-R5G7AOMD.js +0 -53
  615. package/dist/records-update-R5G7AOMD.js.map +0 -1
  616. package/dist/records-update-V23XILMF.mjs +0 -53
  617. package/dist/records-update-V23XILMF.mjs.map +0 -1
  618. package/dist/remove-JS3XWII2.mjs +0 -114
  619. package/dist/remove-JS3XWII2.mjs.map +0 -1
  620. package/dist/remove-QU7WDHPI.js +0 -114
  621. package/dist/remove-QU7WDHPI.js.map +0 -1
  622. package/dist/rename-AQZWJOSA.js +0 -42
  623. package/dist/rename-AQZWJOSA.js.map +0 -1
  624. package/dist/rename-NX4OMJDP.mjs +0 -42
  625. package/dist/rename-NX4OMJDP.mjs.map +0 -1
  626. package/dist/request-increase-FLFEPGIC.js +0 -37
  627. package/dist/request-increase-FLFEPGIC.js.map +0 -1
  628. package/dist/request-increase-NHM27JXH.mjs +0 -37
  629. package/dist/request-increase-NHM27JXH.mjs.map +0 -1
  630. package/dist/restore-HTAPXIPP.js +0 -73
  631. package/dist/restore-HTAPXIPP.js.map +0 -1
  632. package/dist/restore-R5LY5MWO.mjs +0 -73
  633. package/dist/restore-R5LY5MWO.mjs.map +0 -1
  634. package/dist/revoke-2JIUV7JE.mjs +0 -41
  635. package/dist/revoke-2JIUV7JE.mjs.map +0 -1
  636. package/dist/revoke-GH3YEBRW.js +0 -44
  637. package/dist/revoke-GH3YEBRW.js.map +0 -1
  638. package/dist/revoke-MS5OZQHS.js +0 -41
  639. package/dist/revoke-MS5OZQHS.js.map +0 -1
  640. package/dist/revoke-TQJVF3BL.mjs +0 -44
  641. package/dist/revoke-TQJVF3BL.mjs.map +0 -1
  642. package/dist/rotate-QUP62JOC.mjs +0 -52
  643. package/dist/rotate-QUP62JOC.mjs.map +0 -1
  644. package/dist/rotate-U3RJTWOO.js +0 -52
  645. package/dist/rotate-U3RJTWOO.js.map +0 -1
  646. package/dist/run-2KC3XYCD.js +0 -77
  647. package/dist/run-2KC3XYCD.js.map +0 -1
  648. package/dist/run-35JPAOLO.mjs +0 -83
  649. package/dist/run-35JPAOLO.mjs.map +0 -1
  650. package/dist/run-5YPCH5US.mjs +0 -77
  651. package/dist/run-5YPCH5US.mjs.map +0 -1
  652. package/dist/run-6BUAGYXY.mjs +0 -142
  653. package/dist/run-6BUAGYXY.mjs.map +0 -1
  654. package/dist/run-BB27OOPE.js +0 -131
  655. package/dist/run-BB27OOPE.js.map +0 -1
  656. package/dist/run-BPTFP3HA.mjs +0 -144
  657. package/dist/run-BPTFP3HA.mjs.map +0 -1
  658. package/dist/run-DVPUVKTV.mjs +0 -131
  659. package/dist/run-DVPUVKTV.mjs.map +0 -1
  660. package/dist/run-GJEOP5LP.js +0 -144
  661. package/dist/run-GJEOP5LP.js.map +0 -1
  662. package/dist/run-JLC2AGGB.js +0 -83
  663. package/dist/run-JLC2AGGB.js.map +0 -1
  664. package/dist/run-P5B7FK6K.js +0 -142
  665. package/dist/run-P5B7FK6K.js.map +0 -1
  666. package/dist/search-FMFV6U6P.mjs +0 -108
  667. package/dist/search-FMFV6U6P.mjs.map +0 -1
  668. package/dist/search-LEF4NLQJ.js +0 -108
  669. package/dist/search-LEF4NLQJ.js.map +0 -1
  670. package/dist/set-7Q2IUUPV.mjs +0 -105
  671. package/dist/set-7Q2IUUPV.mjs.map +0 -1
  672. package/dist/set-DYXQGJNE.js +0 -59
  673. package/dist/set-DYXQGJNE.js.map +0 -1
  674. package/dist/set-FVXIBW4X.js +0 -105
  675. package/dist/set-FVXIBW4X.js.map +0 -1
  676. package/dist/set-PMA5UWDK.mjs +0 -59
  677. package/dist/set-PMA5UWDK.mjs.map +0 -1
  678. package/dist/status-DS55UJ7O.mjs +0 -153
  679. package/dist/status-DS55UJ7O.mjs.map +0 -1
  680. package/dist/status-GSPWZ255.mjs +0 -56
  681. package/dist/status-GSPWZ255.mjs.map +0 -1
  682. package/dist/status-KH64EWPP.js +0 -153
  683. package/dist/status-KH64EWPP.js.map +0 -1
  684. package/dist/status-M4GI2HR3.js +0 -56
  685. package/dist/status-M4GI2HR3.js.map +0 -1
  686. package/dist/status-OAD2U66Z.js +0 -122
  687. package/dist/status-OAD2U66Z.js.map +0 -1
  688. package/dist/status-U3EPMBTN.mjs +0 -122
  689. package/dist/status-U3EPMBTN.mjs.map +0 -1
  690. package/dist/sync-PKDE2D7V.js +0 -132
  691. package/dist/sync-PKDE2D7V.js.map +0 -1
  692. package/dist/sync-XV5HX5TO.mjs +0 -132
  693. package/dist/sync-XV5HX5TO.mjs.map +0 -1
  694. package/dist/tail-CKK6GFNI.js +0 -108
  695. package/dist/tail-CKK6GFNI.js.map +0 -1
  696. package/dist/tail-D26CEKSH.mjs +0 -108
  697. package/dist/tail-D26CEKSH.mjs.map +0 -1
  698. package/dist/unset-FGAQM4WA.js +0 -107
  699. package/dist/unset-FGAQM4WA.js.map +0 -1
  700. package/dist/unset-TVSHRR64.mjs +0 -107
  701. package/dist/unset-TVSHRR64.mjs.map +0 -1
  702. package/dist/update-337XCLM7.mjs +0 -65
  703. package/dist/update-337XCLM7.mjs.map +0 -1
  704. package/dist/update-43JHGSN7.js +0 -106
  705. package/dist/update-43JHGSN7.js.map +0 -1
  706. package/dist/update-4KGPCVCD.js +0 -71
  707. package/dist/update-4KGPCVCD.js.map +0 -1
  708. package/dist/update-5DIMZPJB.mjs +0 -71
  709. package/dist/update-5DIMZPJB.mjs.map +0 -1
  710. package/dist/update-5WVIKR5E.js +0 -48
  711. package/dist/update-5WVIKR5E.js.map +0 -1
  712. package/dist/update-AAZVLFRJ.js +0 -75
  713. package/dist/update-AAZVLFRJ.js.map +0 -1
  714. package/dist/update-APD7MSPV.js +0 -61
  715. package/dist/update-APD7MSPV.js.map +0 -1
  716. package/dist/update-AR7L7TOZ.js +0 -48
  717. package/dist/update-AR7L7TOZ.js.map +0 -1
  718. package/dist/update-C3I3BHWG.js +0 -63
  719. package/dist/update-C3I3BHWG.js.map +0 -1
  720. package/dist/update-CDBNRXSO.mjs +0 -106
  721. package/dist/update-CDBNRXSO.mjs.map +0 -1
  722. package/dist/update-CXYYWVNO.mjs +0 -75
  723. package/dist/update-CXYYWVNO.mjs.map +0 -1
  724. package/dist/update-DUJU3A4R.mjs +0 -48
  725. package/dist/update-DUJU3A4R.mjs.map +0 -1
  726. package/dist/update-E3GH3WEX.mjs +0 -83
  727. package/dist/update-E3GH3WEX.mjs.map +0 -1
  728. package/dist/update-HHGQ2DVM.js +0 -83
  729. package/dist/update-HHGQ2DVM.js.map +0 -1
  730. package/dist/update-IFDJZ6LW.js +0 -66
  731. package/dist/update-IFDJZ6LW.js.map +0 -1
  732. package/dist/update-JEGVDVSK.js +0 -51
  733. package/dist/update-JEGVDVSK.js.map +0 -1
  734. package/dist/update-JL3MKZXC.mjs +0 -66
  735. package/dist/update-JL3MKZXC.mjs.map +0 -1
  736. package/dist/update-JUTNNHSA.mjs +0 -51
  737. package/dist/update-JUTNNHSA.mjs.map +0 -1
  738. package/dist/update-MBBSJQJL.mjs +0 -79
  739. package/dist/update-MBBSJQJL.mjs.map +0 -1
  740. package/dist/update-NOYJVXCB.mjs +0 -63
  741. package/dist/update-NOYJVXCB.mjs.map +0 -1
  742. package/dist/update-OFUQFYBD.js +0 -76
  743. package/dist/update-OFUQFYBD.js.map +0 -1
  744. package/dist/update-OZC2S3BC.js +0 -79
  745. package/dist/update-OZC2S3BC.js.map +0 -1
  746. package/dist/update-P4PNDOMU.mjs +0 -63
  747. package/dist/update-P4PNDOMU.mjs.map +0 -1
  748. package/dist/update-RJFENG32.mjs +0 -48
  749. package/dist/update-RJFENG32.mjs.map +0 -1
  750. package/dist/update-W2RQW53I.js +0 -65
  751. package/dist/update-W2RQW53I.js.map +0 -1
  752. package/dist/update-WFGCL4JS.mjs +0 -61
  753. package/dist/update-WFGCL4JS.mjs.map +0 -1
  754. package/dist/update-WTIR2BYE.js +0 -63
  755. package/dist/update-WTIR2BYE.js.map +0 -1
  756. package/dist/update-X7J6WRG3.mjs +0 -76
  757. package/dist/update-X7J6WRG3.mjs.map +0 -1
  758. package/dist/upload-7O3K4YAL.mjs +0 -80
  759. package/dist/upload-7O3K4YAL.mjs.map +0 -1
  760. package/dist/upload-DJA44RJ3.js +0 -80
  761. package/dist/upload-DJA44RJ3.js.map +0 -1
  762. package/dist/versions-2JD6EKCA.js +0 -85
  763. package/dist/versions-2JD6EKCA.js.map +0 -1
  764. package/dist/versions-HXI6GAD2.mjs +0 -85
  765. package/dist/versions-HXI6GAD2.mjs.map +0 -1
  766. package/dist/whoami-EI52YRCH.js +0 -30
  767. package/dist/whoami-EI52YRCH.js.map +0 -1
  768. package/dist/whoami-KGRA4QEY.mjs +0 -30
  769. package/dist/whoami-KGRA4QEY.mjs.map +0 -1
  770. package/dist/wrap-LBMHL6N6.mjs +0 -33
  771. package/dist/wrap-LBMHL6N6.mjs.map +0 -1
  772. package/dist/wrap-O7DQWEVA.js +0 -33
  773. package/dist/wrap-O7DQWEVA.js.map +0 -1
  774. /package/dist/{chunk-RIPASL56.mjs.map → chunk-2O4ILSP5.mjs.map} +0 -0
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["/home/runner/work/langwatch/langwatch/typescript-sdk/dist/index.js","../src/client-sdk/services/experiments/experiment.ts","../src/client-sdk/services/experiments/humanReadableId.ts","../src/client-sdk/services/experiments/errors/experiment.error.ts","../src/client-sdk/services/experiments/printSummary.ts","../src/client-sdk/services/experiments/experiments.facade.ts","../src/client-sdk/services/evaluations/evaluations.facade.ts","../src/client-sdk/services/evaluations/errors.ts","../src/client-sdk/services/triggers/triggers-api.service.ts","../src/client-sdk/services/graphs/graphs-api.service.ts","../src/client-sdk/services/simulation-runs/simulation-runs-api.service.ts","../src/client-sdk/services/monitors/monitors-api.service.ts","../src/client-sdk/services/secrets/secrets-api.service.ts","../src/client-sdk/services/traces/types.ts","../src/client-sdk/services/traces/tracing/tracer.ts","../src/client-sdk/services/traces/service.ts","../src/client-sdk/services/traces/facade.ts","../src/client-sdk/index.ts","../src/index.ts"],"names":["tracer"],"mappings":"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","file":"/home/runner/work/langwatch/langwatch/typescript-sdk/dist/index.js","sourcesContent":[null,"/**\n * Experiment - Main class for running batch experiments\n *\n * Provides a clean API for running experiments over datasets with:\n * - Automatic tracing per iteration\n * - Parallel execution with concurrency control\n * - Batched result sending\n * - Built-in evaluator support\n * - Multi-target comparison with withTarget() context isolation\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { trace, SpanStatusCode, ROOT_CONTEXT } from \"@opentelemetry/api\";\nimport { createLangWatchSpan } from \"@/observability-sdk/span/implementation\";\nimport type { LangWatchSpan } from \"@/observability-sdk/span/types\";\nimport type { LangwatchApiClient } from \"@/internal/api/client\";\nimport type { Logger } from \"@/logger\";\nimport { ensureSetup } from \"@/observability-sdk/setup/node\";\nimport { generateHumanReadableId } from \"./humanReadableId\";\nimport {\n ExperimentInitError,\n TargetMetadataConflictError,\n EvaluatorError,\n} from \"./errors\";\nimport type {\n Batch,\n BatchEntry,\n EvaluationResult,\n TargetInfo,\n TargetMetadata,\n ExperimentInitOptions,\n LogOptions,\n EvaluateOptions,\n RunOptions,\n RunCallback,\n RunContext,\n ExperimentInitResponse,\n LogResultsRequest,\n RunEvaluatorResponse,\n TargetCallback,\n TargetResult,\n TargetExecutionContext,\n TargetContext,\n} from \"./types\";\nimport { printSummary } from \"./printSummary\";\nimport { buildAuthHeaders } from \"@/internal/api/auth\";\n\nconst DEFAULT_CONCURRENCY = 4;\nconst DEBOUNCE_INTERVAL_MS = 1000;\n\n// Slim projections retained across the lifetime of an Experiment for\n// printSummary() — deliberately excludes large fields (inputs, tracebacks,\n// outputs) so running thousands of items doesn't unbound memory.\ntype SummaryEvaluation = Pick<\n EvaluationResult,\n \"name\" | \"evaluator\" | \"status\" | \"passed\" | \"score\" | \"cost\" | \"target_id\"\n>;\ntype SummaryEntry = Pick<BatchEntry, \"duration\" | \"error\" | \"cost\" | \"target_id\">;\n\n/**\n * AsyncLocalStorage for iteration context isolation.\n * This stores the current item and index for each iteration,\n * preventing race conditions in concurrent execution.\n */\ntype IterationContext = {\n index: number;\n item: unknown;\n};\nconst iterationContextStorage = new AsyncLocalStorage<IterationContext>();\n\n/**\n * AsyncLocalStorage for target context isolation.\n * This allows log() calls inside withTarget() to automatically\n * infer the target without explicit specification.\n */\nconst targetContextStorage = new AsyncLocalStorage<TargetExecutionContext>();\n\n/**\n * Experiment session for running batch experiments\n */\nexport class Experiment {\n readonly name: string;\n readonly runId: string;\n readonly experimentSlug: string;\n\n private readonly apiClient: LangwatchApiClient;\n private readonly endpoint: string;\n private readonly apiKey: string;\n private readonly logger: Logger;\n private readonly concurrency: number;\n\n private initialized = false;\n private createdAtMs: number;\n private total = 0;\n private progress = 0;\n\n // Batching state\n private batch: Batch = { dataset: [], evaluations: [], targets: [] };\n private lastSentMs = 0;\n private pendingFlush: Promise<void> | null = null;\n private flushTimeout: ReturnType<typeof setTimeout> | null = null;\n\n // Cumulative record for printSummary() — never cleared, mirrors batch.\n // Store only the fields printSummary() needs, not the full payloads —\n // inputs/tracebacks/outputs can be large and don't belong in retained summary state.\n private cumulativeEvaluations: SummaryEvaluation[] = [];\n private cumulativeEntries: SummaryEntry[] = [];\n private runUrl = \"\";\n\n // Target registry\n private targets = new Map<string, TargetInfo>();\n\n // Current iteration context (for log/evaluate calls)\n private currentTraceId: string | null = null;\n private currentIndex: number | null = null;\n\n // Track whether withTarget() was used in the current iteration\n // If so, we don't create dataset entries in executeItem()\n // Note: This is now checked via iterationContextStorage to be thread-safe\n private iterationUsedWithTarget = new Map<number, boolean>();\n\n // Track whether withTarget() has EVER been used in this evaluation\n // Once set to true, we stop creating iteration-level traces\n private evaluationUsesTargets = false;\n\n private constructor(\n name: string,\n options: {\n apiClient: LangwatchApiClient;\n endpoint: string;\n apiKey: string;\n logger: Logger;\n runId?: string;\n concurrency?: number;\n }\n ) {\n this.name = name;\n this.experimentSlug = name;\n this.runId = options.runId ?? generateHumanReadableId();\n this.apiClient = options.apiClient;\n this.endpoint = options.endpoint;\n this.apiKey = options.apiKey;\n this.logger = options.logger;\n this.concurrency = options.concurrency ?? DEFAULT_CONCURRENCY;\n this.createdAtMs = Date.now();\n }\n\n /**\n * Initialize an evaluation session\n */\n static async init(\n name: string,\n options: {\n apiClient: LangwatchApiClient;\n endpoint: string;\n apiKey: string;\n logger: Logger;\n } & ExperimentInitOptions\n ): Promise<Experiment> {\n // Ensure observability is set up for proper tracing\n ensureSetup();\n\n const experiment = new Experiment(name, options);\n await experiment.initialize();\n return experiment;\n }\n\n /**\n * Initialize the evaluation by creating/getting the experiment\n */\n private async initialize(): Promise<void> {\n if (!this.apiKey) {\n throw new ExperimentInitError(\n \"API key is required. Set LANGWATCH_API_KEY or pass apiKey to LangWatch constructor.\"\n );\n }\n\n try {\n const response = await fetch(`${this.endpoint}/api/experiment/init`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...buildAuthHeaders({ apiKey: this.apiKey }),\n },\n body: JSON.stringify({\n experiment_name: this.name,\n experiment_slug: this.experimentSlug,\n experiment_type: \"BATCH_EVALUATION_V2\",\n }),\n });\n\n if (response.status === 401) {\n throw new ExperimentInitError(\"Invalid API key\");\n }\n\n if (!response.ok) {\n const text = await response.text();\n throw new ExperimentInitError(`Failed to initialize experiment: ${text}`);\n }\n\n const data = (await response.json()) as ExperimentInitResponse;\n (this as { experimentSlug: string }).experimentSlug = data.slug;\n\n const encodedRunId = encodeURIComponent(this.runId);\n this.runUrl = `${this.endpoint.replace(/\\/$/, \"\")}${data.path}?runId=${encodedRunId}`;\n console.log(`Follow results at: ${this.runUrl}`);\n\n this.initialized = true;\n } catch (error) {\n if (error instanceof ExperimentInitError) {\n throw error;\n }\n throw new ExperimentInitError(\n `Failed to initialize evaluation: ${error instanceof Error ? error.message : String(error)}`,\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Run evaluation over a dataset with a callback\n *\n * @param dataset - Array of items to evaluate\n * @param callback - Function called for each item with { item, index, span }\n * @param options - Concurrency options\n *\n * @example\n * ```typescript\n * await evaluation.run(dataset, async ({ item, index, span }) => {\n * const response = await myAgent(item.question);\n * evaluation.log('accuracy', { index, score: 0.95 });\n * }, { concurrency: 4 });\n * ```\n */\n async run<T>(\n dataset: T[],\n callback: RunCallback<T>,\n options?: RunOptions\n ): Promise<void> {\n if (!this.initialized) {\n await this.initialize();\n }\n\n const concurrency = options?.concurrency ?? this.concurrency;\n this.total = dataset.length;\n this.progress = 0;\n\n const tracer = trace.getTracer(\"langwatch\");\n\n // Process items with concurrency control\n const executing = new Set<Promise<void>>();\n\n for (let index = 0; index < dataset.length; index++) {\n const item = dataset[index] as T;\n\n const itemPromise = this.executeItem(tracer, item, index, callback);\n\n executing.add(itemPromise);\n void itemPromise.finally(() => executing.delete(itemPromise));\n\n // Wait if we've hit concurrency limit\n if (executing.size >= concurrency) {\n await Promise.race(executing);\n }\n }\n\n // Wait for all remaining items\n await Promise.all(executing);\n\n // Flush OTEL spans so all child spans created inside callbacks are exported\n const provider = trace.getTracerProvider();\n const delegate = \"getDelegate\" in provider && typeof provider.getDelegate === \"function\"\n ? provider.getDelegate()\n : provider;\n if (delegate && \"forceFlush\" in delegate && typeof delegate.forceFlush === \"function\") {\n await delegate.forceFlush();\n }\n\n // Send final batch with finished timestamp\n await this.flush(true);\n }\n\n /**\n * Execute a single item in the dataset\n */\n private async executeItem<T>(\n tracer: ReturnType<typeof trace.getTracer>,\n item: T,\n index: number,\n callback: RunCallback<T>\n ): Promise<void> {\n const startTime = Date.now();\n let error: Error | undefined;\n let capturedTraceId: string | null = null;\n\n // Reset withTarget tracking for this iteration\n this.iterationUsedWithTarget.set(index, false);\n\n // Set up iteration context (thread-safe via AsyncLocalStorage)\n const iterationContext: IterationContext = { index, item };\n\n // If evaluation uses targets, skip creating iteration-level traces\n // Each withTarget() call will create its own independent trace\n if (this.evaluationUsesTargets) {\n await iterationContextStorage.run(iterationContext, async () => {\n this.currentIndex = index;\n\n try {\n // Create a minimal span context for the callback\n const span = {\n setStatus: () => { /* no-op */ },\n recordException: () => { /* no-op */ },\n end: () => { /* no-op */ },\n } as unknown as LangWatchSpan;\n\n const ctx: RunContext<T> = { item, index, span };\n const result = callback(ctx);\n\n if (result && typeof result.then === \"function\") {\n await result;\n }\n } catch (err) {\n error = err instanceof Error ? err : new Error(String(err));\n this.logger.error(`Evaluation error at index ${index}:`, error);\n } finally {\n this.currentIndex = null;\n }\n });\n } else {\n await iterationContextStorage.run(iterationContext, async () => {\n await tracer.startActiveSpan(\n \"evaluation.iteration\",\n {\n attributes: {\n \"langwatch.origin\": \"evaluation\",\n \"evaluation.run_id\": this.runId,\n \"evaluation.index\": index,\n },\n },\n async (otelSpan) => {\n const span = createLangWatchSpan(otelSpan);\n const spanContext = otelSpan.spanContext();\n const traceId = spanContext.traceId;\n\n // Set current context for log/evaluate calls\n this.currentTraceId = traceId;\n this.currentIndex = index;\n capturedTraceId = traceId;\n\n try {\n const ctx: RunContext<T> = { item, index, span };\n const result = callback(ctx);\n\n if (result && typeof result.then === \"function\") {\n await result;\n }\n\n span.setStatus({ code: SpanStatusCode.OK });\n } catch (err) {\n error = err instanceof Error ? err : new Error(String(err));\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error.message,\n });\n span.recordException(error);\n this.logger.error(`Evaluation error at index ${index}:`, error);\n } finally {\n span.end();\n this.currentTraceId = null;\n this.currentIndex = null;\n }\n }\n );\n });\n }\n\n // Only add a dataset entry if withTarget() was NOT used\n // When withTarget() is used, it creates its own dataset entries per target\n if (!this.iterationUsedWithTarget.get(index)) {\n const duration = Date.now() - startTime;\n const entry: BatchEntry = {\n index,\n entry: this.serializeItem(item),\n duration,\n error: error?.message ?? null,\n trace_id: capturedTraceId ?? this.getTraceIdFromContext(),\n };\n\n this.batch.dataset.push(entry);\n this.cumulativeEntries.push({\n duration: entry.duration,\n error: entry.error,\n cost: entry.cost,\n target_id: entry.target_id,\n });\n }\n\n // Clean up\n this.iterationUsedWithTarget.delete(index);\n\n this.progress++;\n\n // Debounced send\n this.scheduleSend();\n }\n\n /**\n * Log a custom metric result\n *\n * @param metric - Name of the metric\n * @param options - Metric options including index, score, passed, etc.\n *\n * If called inside a withTarget() block, the target and index are automatically\n * inferred from the context and don't need to be specified.\n *\n * @example\n * ```typescript\n * // Explicit target (outside withTarget)\n * evaluation.log('accuracy', { index, score: 0.95, target: 'gpt-4' });\n *\n * // Implicit target (inside withTarget)\n * await evaluation.withTarget('gpt-4', { model: 'openai/gpt-4' }, async () => {\n * evaluation.log('accuracy', { score: 0.95 }); // target and index auto-inferred\n * });\n * ```\n */\n log(metric: string, options: LogOptions): void {\n // Get context from AsyncLocalStorage (if inside withTarget)\n const targetContext = targetContextStorage.getStore();\n\n const {\n data = {},\n score,\n passed,\n label,\n details,\n status = options.error ? \"error\" : \"processed\",\n duration,\n cost,\n error,\n // Use context values as defaults, allow explicit override\n target = targetContext?.targetId,\n metadata,\n index = targetContext?.index ?? options.index,\n } = options;\n\n // Register target if provided (explicit or from context)\n let targetId: string | undefined;\n if (target) {\n targetId = this.registerTarget(target, metadata);\n }\n\n // Use trace ID from context, then current iteration, then OTEL context\n const traceId =\n targetContext?.traceId ?? this.currentTraceId ?? this.getTraceIdFromContext();\n\n const result: EvaluationResult = {\n name: metric,\n evaluator: metric,\n trace_id: traceId,\n status,\n data,\n score: score ?? null,\n passed: passed ?? null,\n details: details ?? (error ? error.message : null),\n index,\n label: label ?? null,\n cost: cost ?? null,\n duration: duration ?? null,\n error_type: error ? error.name : null,\n traceback: error ? [error.stack ?? error.message] : null,\n target_id: targetId ?? null,\n };\n\n this.batch.evaluations.push(result);\n this.cumulativeEvaluations.push({\n name: result.name,\n evaluator: result.evaluator,\n status: result.status,\n passed: result.passed,\n score: result.score,\n cost: result.cost,\n target_id: result.target_id,\n });\n this.scheduleSend();\n }\n\n /**\n * Run a built-in evaluator\n *\n * @param evaluatorSlug - The evaluator identifier (e.g., 'ragas/faithfulness')\n * @param options - Evaluator options including data and settings\n *\n * If called inside a withTarget() block, the target and index are automatically\n * inferred from the context and don't need to be specified.\n *\n * @example\n * ```typescript\n * // Inside withTarget() - target and index auto-inferred\n * await evaluation.withTarget('gpt-4', { model: 'openai/gpt-4' }, async () => {\n * await evaluation.evaluate('ragas/faithfulness', {\n * data: { input, output, contexts },\n * });\n * });\n *\n * // Or explicit index/target\n * await evaluation.evaluate('ragas/faithfulness', {\n * index,\n * data: { input, output, contexts },\n * target: 'gpt-4',\n * });\n * ```\n */\n async evaluate(evaluatorSlug: string, options: EvaluateOptions): Promise<void> {\n // Get context from AsyncLocalStorage (if inside withTarget)\n const targetContext = targetContextStorage.getStore();\n\n const {\n data,\n settings,\n name,\n asGuardrail = false,\n // Use context values as defaults, allow explicit override\n target = targetContext?.targetId,\n metadata,\n index = targetContext?.index ?? options.index,\n } = options;\n\n const startTime = Date.now();\n // Use trace ID from context, then current iteration, then OTEL context\n const traceId =\n targetContext?.traceId ?? this.currentTraceId ?? this.getTraceIdFromContext();\n const spanId = targetContext?.spanId ?? this.getSpanIdFromContext();\n\n try {\n const response = await fetch(\n `${this.endpoint}/api/evaluations/${evaluatorSlug}/evaluate`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...buildAuthHeaders({ apiKey: this.apiKey }),\n },\n body: JSON.stringify({\n trace_id: traceId ?? null,\n span_id: spanId ?? null,\n name: name ?? evaluatorSlug,\n data,\n settings,\n as_guardrail: asGuardrail,\n }),\n }\n );\n\n if (!response.ok) {\n const text = await response.text();\n throw new EvaluatorError(evaluatorSlug, text);\n }\n\n const result = (await response.json()) as RunEvaluatorResponse;\n const duration = Date.now() - startTime;\n\n // Log the result\n this.log(name ?? evaluatorSlug, {\n index,\n data,\n status: result.status,\n score: result.score ?? undefined,\n passed: result.passed ?? undefined,\n details: result.details ?? undefined,\n label: result.label ?? undefined,\n duration,\n cost: result.cost?.amount,\n target,\n metadata,\n });\n } catch (error) {\n const duration = Date.now() - startTime;\n\n if (error instanceof EvaluatorError) {\n this.log(name ?? evaluatorSlug, {\n index,\n data,\n status: \"error\",\n duration,\n error: error,\n target,\n metadata,\n });\n throw error;\n }\n\n const wrappedError = new EvaluatorError(\n evaluatorSlug,\n error instanceof Error ? error.message : String(error),\n error instanceof Error ? error : undefined\n );\n\n this.log(name ?? evaluatorSlug, {\n index,\n data,\n status: \"error\",\n duration,\n error: wrappedError,\n target,\n metadata,\n });\n\n throw wrappedError;\n }\n }\n\n /**\n * Execute code within a target context with automatic tracing\n *\n * Creates a new span for this target execution and sets up context\n * so that log() calls inside the callback automatically use this target.\n * Duration and output are captured automatically.\n *\n * This creates a dataset entry per target (like Evaluations V3), enabling\n * proper per-target latency and cost tracking.\n *\n * @param targetName - Unique identifier for the target\n * @param metadata - Optional metadata for comparison (e.g., { model: 'gpt-4' })\n * @param callback - Function to execute within the target context\n * @returns The callback result along with captured metrics\n *\n * @example\n * ```typescript\n * await evaluation.run(dataset, async ({ item, index }) => {\n * // Compare GPT-4 and Claude on the same input\n * const [gpt4Result, claudeResult] = await Promise.all([\n * evaluation.withTarget('gpt-4', { model: 'openai/gpt-4' }, async () => {\n * const response = await openai.chat(item.question);\n * evaluation.log('quality', { score: 0.95 }); // target auto-inferred\n * return response;\n * }),\n * evaluation.withTarget('claude-3', { model: 'anthropic/claude-3' }, async () => {\n * const response = await anthropic.messages(item.question);\n * evaluation.log('quality', { score: 0.85 }); // target auto-inferred\n * return response;\n * }),\n * ]);\n * });\n * ```\n */\n async withTarget<R>(\n targetName: string,\n metadata: TargetMetadata | null,\n callback: TargetCallback<R>\n ): Promise<TargetResult<R>>;\n async withTarget<R>(\n targetName: string,\n callback: TargetCallback<R>\n ): Promise<TargetResult<R>>;\n async withTarget<R>(\n targetName: string,\n metadataOrCallback: TargetMetadata | null | TargetCallback<R>,\n maybeCallback?: TargetCallback<R>\n ): Promise<TargetResult<R>> {\n // Handle overloads\n const metadata =\n typeof metadataOrCallback === \"function\" ? null : metadataOrCallback;\n const callback =\n typeof metadataOrCallback === \"function\" ? metadataOrCallback : maybeCallback!;\n\n // On FIRST withTarget() call ever in this evaluation:\n // - Set flag to skip creating iteration-level traces going forward\n if (!this.evaluationUsesTargets) {\n this.evaluationUsesTargets = true;\n }\n\n // Get iteration context (thread-safe via AsyncLocalStorage)\n const iterationContext = iterationContextStorage.getStore();\n const index = iterationContext?.index ?? this.currentIndex ?? 0;\n const currentItem = iterationContext?.item;\n\n // Mark that withTarget() was used - prevents executeItem from creating a dataset entry\n this.iterationUsedWithTarget.set(index, true);\n\n // Register target\n this.registerTarget(targetName, metadata ?? undefined);\n\n const tracer = trace.getTracer(\"langwatch\");\n const startTime = Date.now();\n let result: R | undefined;\n let traceId = \"\";\n let spanId = \"\";\n let callbackError: Error | undefined;\n\n // Create an INDEPENDENT root span using ROOT_CONTEXT\n // This ensures each target gets a unique trace_id, not shared with iteration\n await tracer.startActiveSpan(\n `evaluation.target.${targetName}`,\n {\n attributes: {\n \"langwatch.origin\": \"evaluation\",\n \"evaluation.run_id\": this.runId,\n \"evaluation.target\": targetName,\n \"evaluation.index\": index,\n },\n },\n ROOT_CONTEXT,\n async (otelSpan) => {\n const span = createLangWatchSpan(otelSpan);\n const spanContext = otelSpan.spanContext();\n const rawTraceId = spanContext.traceId;\n spanId = spanContext.spanId;\n\n // Check if this is a no-op trace (all zeros = no tracer configured)\n const isNoOpTrace = rawTraceId === \"00000000000000000000000000000000\";\n traceId = isNoOpTrace ? \"\" : rawTraceId;\n\n // Set up the target execution context\n const executionContext: TargetExecutionContext = {\n targetId: targetName,\n traceId,\n spanId,\n index,\n };\n\n try {\n // Run callback within AsyncLocalStorage context\n result = await targetContextStorage.run(executionContext, async () => {\n const ctx: TargetContext = { span, traceId, spanId };\n const callbackResult = callback(ctx);\n\n if (callbackResult && typeof (callbackResult as Promise<R>).then === \"function\") {\n return await callbackResult;\n }\n return callbackResult as R;\n });\n\n span.setStatus({ code: SpanStatusCode.OK });\n } catch (err) {\n callbackError = err instanceof Error ? err : new Error(String(err));\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: callbackError.message,\n });\n span.recordException(callbackError);\n throw err;\n } finally {\n span.end();\n }\n }\n );\n\n const duration = Date.now() - startTime;\n\n // Serialize the result as \"predicted\" output (similar to Evaluations V3)\n let predicted: Record<string, unknown> | null = null;\n if (result !== undefined && result !== null) {\n predicted = typeof result === \"object\"\n ? (result as Record<string, unknown>)\n : { output: result };\n }\n\n // Create a dataset entry for this target execution (like Evaluations V3)\n // This captures per-target duration/latency properly\n // Use currentItem from iteration context (thread-safe), NOT shared instance variable\n const entry: BatchEntry = {\n index,\n entry: this.serializeItem(currentItem),\n duration,\n error: callbackError?.message ?? null,\n trace_id: traceId || null, // null if no tracer configured (no-op)\n target_id: targetName,\n predicted,\n };\n\n this.batch.dataset.push(entry);\n this.cumulativeEntries.push({\n duration: entry.duration,\n error: entry.error,\n cost: entry.cost,\n target_id: entry.target_id,\n });\n this.scheduleSend();\n\n return {\n result: result!,\n duration,\n traceId,\n spanId,\n };\n }\n\n /**\n * Register a target for multi-target comparison\n */\n private registerTarget(name: string, metadata?: TargetMetadata): string {\n const existing = this.targets.get(name);\n\n if (existing) {\n // Check for metadata conflict\n if (metadata) {\n const existingMeta = existing.metadata ?? {};\n if (JSON.stringify(existingMeta) !== JSON.stringify(metadata)) {\n throw new TargetMetadataConflictError(name, existingMeta, metadata);\n }\n }\n return name;\n }\n\n // Register new target\n const targetInfo: TargetInfo = {\n id: name,\n name,\n type: \"custom\",\n metadata: metadata ?? null,\n };\n\n this.targets.set(name, targetInfo);\n this.batch.targets.push(targetInfo);\n\n return name;\n }\n\n /**\n * Schedule a debounced send\n */\n private scheduleSend(): void {\n const now = Date.now();\n\n if (now - this.lastSentMs >= DEBOUNCE_INTERVAL_MS) {\n this.sendBatch();\n } else {\n this.flushTimeout ??= setTimeout(() => {\n this.flushTimeout = null;\n this.sendBatch();\n }, DEBOUNCE_INTERVAL_MS - (now - this.lastSentMs));\n }\n }\n\n /**\n * Print a CI-friendly summary and optionally exit with code 1 on failure.\n *\n * Mirrors `ExperimentRunResult.printSummary` for parity — SDK-driven experiments\n * can now fail CI builds the same way platform experiments do.\n *\n * @param exitOnFailure - If true (default), calls `process.exit(1)` when any evaluation failed.\n *\n * @example\n * ```typescript\n * const experiment = await langwatch.experiments.init(\"ci-quality-check\");\n * await experiment.run(dataset, async ({ item, index }) => {\n * const response = await myLLM(item.input);\n * await experiment.evaluate(\"ragas/faithfulness\", { index, data: { input: item.input, output: response } });\n * });\n * experiment.printSummary();\n * ```\n */\n printSummary(exitOnFailure = true): void {\n const evaluators = new Map<\n string,\n { passed: number; failed: number; scoreSum: number; scoreCount: number }\n >();\n let totalPassed = 0;\n let totalFailed = 0;\n let totalCost = 0;\n\n for (const e of this.cumulativeEvaluations) {\n const name = e.name ?? e.evaluator ?? \"unknown\";\n if (!evaluators.has(name)) {\n evaluators.set(name, { passed: 0, failed: 0, scoreSum: 0, scoreCount: 0 });\n }\n const stats = evaluators.get(name)!;\n // Evaluators that crashed come back as status:\"error\" with passed often null;\n // treat them as failures so CI doesn't silently succeed on evaluator crashes.\n if (e.status === \"error\" || e.passed === false) {\n stats.failed += 1;\n totalFailed += 1;\n } else if (e.passed === true) {\n stats.passed += 1;\n totalPassed += 1;\n }\n if (typeof e.score === \"number\") {\n stats.scoreSum += e.score;\n stats.scoreCount += 1;\n }\n if (typeof e.cost === \"number\") {\n totalCost += e.cost;\n }\n }\n\n const targets = new Map<\n string,\n { passed: number; failed: number; latencySum: number; latencyCount: number; cost: number }\n >();\n for (const entry of this.cumulativeEntries) {\n const tid = entry.target_id;\n if (!tid) continue;\n if (!targets.has(tid)) {\n targets.set(tid, { passed: 0, failed: 0, latencySum: 0, latencyCount: 0, cost: 0 });\n }\n const stats = targets.get(tid)!;\n if (typeof entry.duration === \"number\") {\n stats.latencySum += entry.duration;\n stats.latencyCount += 1;\n }\n if (typeof entry.cost === \"number\") {\n stats.cost += entry.cost;\n }\n }\n // Lazily seed target stats from evaluations too — a user can log an\n // evaluation with an explicit target_id without ever going through\n // withTarget(), in which case the per-target entry row may not carry\n // target_id. Without this, such a target would be silently dropped from\n // the per-target summary.\n for (const e of this.cumulativeEvaluations) {\n const tid = e.target_id;\n if (!tid) continue;\n if (!targets.has(tid)) {\n targets.set(tid, { passed: 0, failed: 0, latencySum: 0, latencyCount: 0, cost: 0 });\n }\n const stats = targets.get(tid)!;\n if (e.status === \"error\" || e.passed === false) stats.failed += 1;\n else if (e.passed === true) stats.passed += 1;\n if (typeof e.cost === \"number\") stats.cost += e.cost;\n }\n\n const total = totalPassed + totalFailed;\n const passRate = total > 0 ? (totalPassed / total) * 100 : 0;\n\n // Wall-clock duration from init — summing entry durations over-counts\n // under concurrent withTarget() calls (each target produces its own entry).\n const duration = Math.max(0, Date.now() - this.createdAtMs);\n\n // Count entries whose target/loop execution errored out — distinct from\n // evaluator failures but must also trigger CI exit.\n let failedCells = 0;\n for (const entry of this.cumulativeEntries) {\n if (typeof entry.cost === \"number\") totalCost += entry.cost;\n if (entry.error) failedCells += 1;\n }\n\n const hasFailures = totalFailed > 0 || failedCells > 0;\n\n printSummary({\n runId: this.runId,\n status: hasFailures ? \"failed\" : \"completed\",\n passed: totalPassed,\n failed: totalFailed,\n passRate,\n duration,\n runUrl: this.runUrl,\n summary: {\n runId: this.runId,\n totalCells: this.cumulativeEntries.length || total,\n completedCells: Math.max(0, (this.cumulativeEntries.length || total) - failedCells),\n failedCells,\n duration,\n runUrl: this.runUrl,\n totalPassed,\n totalFailed,\n passRate,\n totalCost,\n targets: Array.from(targets.entries()).map(([targetId, s]) => ({\n targetId,\n name: targetId,\n passed: s.passed,\n failed: s.failed,\n avgLatency: s.latencyCount > 0 ? s.latencySum / s.latencyCount : 0,\n totalCost: s.cost,\n })),\n evaluators: Array.from(evaluators.entries()).map(([name, s]) => ({\n evaluatorId: name,\n name,\n passed: s.passed,\n failed: s.failed,\n passRate: s.passed + s.failed > 0 ? (s.passed / (s.passed + s.failed)) * 100 : 0,\n avgScore: s.scoreCount > 0 ? s.scoreSum / s.scoreCount : undefined,\n })),\n },\n });\n\n if (exitOnFailure && hasFailures) {\n process.exit(1);\n }\n }\n\n /**\n * Send current batch to the API\n */\n private sendBatch(finished = false): void {\n if (\n this.batch.dataset.length === 0 &&\n this.batch.evaluations.length === 0 &&\n this.batch.targets.length === 0 &&\n !finished\n ) {\n return;\n }\n\n const body: LogResultsRequest = {\n experiment_slug: this.experimentSlug,\n name: this.name,\n run_id: this.runId,\n dataset: this.batch.dataset.map((entry) => ({\n index: entry.index,\n entry: entry.entry,\n duration: entry.duration,\n error: entry.error,\n trace_id: entry.trace_id,\n target_id: entry.target_id ?? null,\n cost: entry.cost ?? null,\n // Only include predicted if it's defined (omit entirely when null/undefined)\n ...(entry.predicted !== undefined && entry.predicted !== null\n ? { predicted: entry.predicted }\n : {}),\n })),\n evaluations: this.batch.evaluations.map((e) => ({\n name: e.name,\n evaluator: e.evaluator,\n trace_id: e.trace_id,\n status: e.status,\n inputs: e.data,\n score: e.score,\n passed: e.passed,\n details: e.details,\n index: e.index,\n label: e.label,\n cost: e.cost,\n duration: e.duration,\n target_id: e.target_id,\n })),\n targets: this.batch.targets,\n progress: this.progress,\n total: this.total,\n timestamps: {\n created_at: this.createdAtMs,\n finished_at: finished ? Date.now() : null,\n },\n };\n\n // Fire and forget (with error logging)\n this.pendingFlush = fetch(`${this.endpoint}/api/evaluations/batch/log_results`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...buildAuthHeaders({ apiKey: this.apiKey }),\n },\n body: JSON.stringify(body),\n })\n .then((response) => {\n if (!response.ok) {\n this.logger.error(`Failed to send batch: ${response.status}`);\n }\n })\n .catch((error) => {\n this.logger.error(\"Failed to send batch:\", error);\n });\n\n // Clear batch\n this.batch = { dataset: [], evaluations: [], targets: [] };\n this.lastSentMs = Date.now();\n }\n\n /**\n * Flush all pending data\n */\n private async flush(finished = false): Promise<void> {\n if (this.flushTimeout) {\n clearTimeout(this.flushTimeout);\n this.flushTimeout = null;\n }\n\n this.sendBatch(finished);\n\n if (this.pendingFlush) {\n await this.pendingFlush;\n }\n }\n\n /**\n * Serialize a dataset item for the API\n */\n private serializeItem(item: unknown): unknown {\n if (item === null || item === undefined) {\n return item;\n }\n\n if (typeof item === \"object\") {\n // Handle objects with toJSON method\n if (\"toJSON\" in item && typeof (item as { toJSON: unknown }).toJSON === \"function\") {\n return (item as { toJSON: () => unknown }).toJSON();\n }\n // Return as-is, JSON.stringify will handle it\n return item;\n }\n\n return item;\n }\n\n /**\n * Get trace ID from current OpenTelemetry context\n */\n private getTraceIdFromContext(): string {\n const span = trace.getActiveSpan();\n if (span) {\n return span.spanContext().traceId;\n }\n return \"\";\n }\n\n /**\n * Get span ID from current OpenTelemetry context\n */\n private getSpanIdFromContext(): string | null {\n const span = trace.getActiveSpan();\n if (span) {\n return span.spanContext().spanId;\n }\n return null;\n }\n}\n","/**\n * Human-readable ID generator\n *\n * Generates memorable, human-readable identifiers using adjective-adjective-noun combinations.\n * Similar to Docker container names, Heroku app names, etc.\n */\n\nconst ADJECTIVES = [\n \"swift\", \"bright\", \"calm\", \"eager\", \"bold\", \"keen\", \"warm\", \"cool\", \"wise\", \"fair\",\n \"glad\", \"kind\", \"neat\", \"pure\", \"safe\", \"true\", \"vast\", \"wild\", \"zesty\", \"agile\",\n \"brave\", \"crisp\", \"dense\", \"epic\", \"fresh\", \"grand\", \"happy\", \"ideal\", \"jolly\", \"lively\",\n \"merry\", \"noble\", \"proud\", \"quick\", \"rapid\", \"sharp\", \"smart\", \"solid\", \"sunny\", \"vivid\",\n \"gentle\", \"silent\", \"cosmic\", \"golden\", \"silver\", \"ancient\", \"modern\", \"mighty\", \"humble\",\n];\n\nconst NOUNS = [\n \"fox\", \"owl\", \"bee\", \"elk\", \"hawk\", \"lynx\", \"wolf\", \"bear\", \"deer\", \"dove\",\n \"eagle\", \"finch\", \"heron\", \"koala\", \"lemur\", \"moose\", \"otter\", \"panda\", \"raven\", \"robin\",\n \"seal\", \"swan\", \"tiger\", \"whale\", \"zebra\", \"atlas\", \"bloom\", \"cloud\", \"delta\", \"ember\",\n \"flame\", \"grove\", \"haven\", \"iris\", \"jade\", \"leaf\", \"moon\", \"nova\", \"ocean\", \"peak\",\n \"river\", \"spark\", \"storm\", \"tide\", \"wave\", \"comet\", \"prism\", \"coral\",\n];\n\n/**\n * Generate a human-readable ID with 3 words like \"swift-bright-fox\"\n * Uses adjective-adjective-noun pattern for ~125,000 combinations.\n */\nexport const generateHumanReadableId = (separator = \"-\"): string => {\n // Pick two different adjectives\n const adj1Index = Math.floor(Math.random() * ADJECTIVES.length);\n let adj2Index = Math.floor(Math.random() * ADJECTIVES.length);\n if (adj2Index === adj1Index) {\n adj2Index = (adj2Index + 1) % ADJECTIVES.length;\n }\n\n const adjective1 = ADJECTIVES[adj1Index]!;\n const adjective2 = ADJECTIVES[adj2Index]!;\n const noun = NOUNS[Math.floor(Math.random() * NOUNS.length)]!;\n\n return `${adjective1}${separator}${adjective2}${separator}${noun}`;\n};\n","/**\n * Errors for the Experiments API\n */\n\n/**\n * Base error for experiment-related issues\n */\nexport class ExperimentError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ExperimentError\";\n }\n}\n\n/**\n * Thrown when initialization fails\n */\nexport class ExperimentInitError extends ExperimentError {\n constructor(message: string, public readonly cause?: Error) {\n super(message);\n this.name = \"ExperimentInitError\";\n }\n}\n\n/**\n * Thrown when API calls fail\n */\nexport class ExperimentApiError extends ExperimentError {\n constructor(\n message: string,\n public readonly statusCode?: number,\n public readonly cause?: Error\n ) {\n super(message);\n this.name = \"ExperimentApiError\";\n }\n}\n\n/**\n * Thrown when target metadata conflicts\n */\nexport class TargetMetadataConflictError extends ExperimentError {\n constructor(\n public readonly targetName: string,\n public readonly existingMetadata: Record<string, unknown>,\n public readonly newMetadata: Record<string, unknown>\n ) {\n super(\n `Target '${targetName}' was previously registered with different metadata.\\n` +\n `Original: ${JSON.stringify(existingMetadata)}\\n` +\n `New: ${JSON.stringify(newMetadata)}\\n` +\n `If you want to use different metadata, please use a different target name.`\n );\n this.name = \"TargetMetadataConflictError\";\n }\n}\n\n/**\n * Thrown when an evaluator call fails\n */\nexport class EvaluatorError extends ExperimentError {\n constructor(\n public readonly evaluatorSlug: string,\n message: string,\n public readonly cause?: Error\n ) {\n super(`Evaluator '${evaluatorSlug}' failed: ${message}`);\n this.name = \"EvaluatorError\";\n }\n}\n","import type { ExperimentRunResult } from \"./platformTypes\";\n\n/**\n * Print a CI-friendly summary of experiment results to stdout.\n *\n * Shared between platform runs (`langwatch.experiments.run`) and SDK-driven\n * experiments (`langwatch.experiments.init` → `experiment.printSummary()`).\n */\nexport function printSummary(result: Omit<ExperimentRunResult, \"printSummary\" | \"toString\">): void {\n const { runId, status, passed, failed, passRate, duration, runUrl, summary } = result;\n\n console.log(\"\\n\" + \"═\".repeat(60));\n console.log(\" EXPERIMENT RESULTS\");\n console.log(\"═\".repeat(60));\n console.log(` Run ID: ${runId}`);\n console.log(` Status: ${status.toUpperCase()}`);\n console.log(` Duration: ${(duration / 1000).toFixed(1)}s`);\n console.log(\"─\".repeat(60));\n console.log(` Passed: ${passed}`);\n console.log(` Failed: ${failed}`);\n console.log(` Pass Rate: ${passRate.toFixed(1)}%`);\n if (summary.totalCost) {\n console.log(` Total Cost: $${summary.totalCost.toFixed(4)}`);\n }\n\n if (summary.targets && summary.targets.length > 0) {\n console.log(\"─\".repeat(60));\n console.log(\" TARGETS:\");\n for (const target of summary.targets) {\n console.log(` ${target.name}: ${target.passed} passed, ${target.failed} failed`);\n if (target.avgLatency) {\n console.log(` Avg latency: ${target.avgLatency.toFixed(0)}ms`);\n }\n if (target.totalCost) {\n console.log(` Total cost: $${target.totalCost.toFixed(4)}`);\n }\n }\n }\n\n if (summary.evaluators && summary.evaluators.length > 0) {\n console.log(\"─\".repeat(60));\n console.log(\" EVALUATORS:\");\n for (const evaluator of summary.evaluators) {\n console.log(` ${evaluator.name}: ${evaluator.passRate.toFixed(1)}% pass rate`);\n if (evaluator.avgScore !== undefined) {\n console.log(` Avg score: ${evaluator.avgScore.toFixed(2)}`);\n }\n }\n }\n\n console.log(\"─\".repeat(60));\n console.log(` View details: ${runUrl}`);\n console.log(\"═\".repeat(60) + \"\\n\");\n}\n","/**\n * ExperimentsFacade - Entry point for the experiments API\n *\n * Provides:\n * - `init()` method to create experiment sessions (SDK-defined experiments)\n * - `run()` method to execute platform-configured experiments (Experiments Workbench)\n */\n\nimport type { LangwatchApiClient } from \"@/internal/api/client\";\nimport type { Logger } from \"@/logger\";\nimport { Experiment } from \"./experiment\";\nimport {\n ExperimentsApiService,\n toRunStartRequest,\n} from \"./experiments-api.service\";\nimport type { ExperimentInitOptions } from \"./types\";\nimport type {\n ExperimentRunResult,\n RunExperimentOptions,\n RunWithResultsOptions,\n ExperimentRunWithResults,\n ExperimentRunSummary,\n} from \"./platformTypes\";\nimport {\n ExperimentsApiError,\n ExperimentNotFoundError,\n ExperimentTimeoutError,\n ExperimentRunFailedError,\n} from \"./platformErrors\";\nimport {\n pollExperimentRun,\n rebaseUrlToEndpoint,\n fetchResultsWithRetry,\n} from \"./run-status\";\nimport { mapRunResultsToRows } from \"./mapResults\";\nimport { printSummary } from \"./printSummary\";\n\nconst DEFAULT_POLL_INTERVAL = 2000;\nconst DEFAULT_TIMEOUT = 600000; // 10 minutes\n\ntype ExperimentsFacadeConfig = {\n langwatchApiClient: LangwatchApiClient;\n endpoint: string;\n apiKey: string;\n logger: Logger;\n};\n\n/**\n * Facade for creating experiment sessions and running platform-configured experiments\n */\nexport class ExperimentsFacade {\n private readonly config: ExperimentsFacadeConfig;\n private readonly apiService: ExperimentsApiService;\n\n constructor(config: ExperimentsFacadeConfig) {\n this.config = config;\n this.apiService = new ExperimentsApiService({\n langwatchApiClient: config.langwatchApiClient,\n });\n }\n\n /**\n * Initialize a new experiment session (SDK-defined)\n *\n * @param name - Name of the experiment (used as slug)\n * @param options - Optional configuration\n * @returns An initialized Experiment instance\n *\n * @example\n * ```typescript\n * const experiment = await langwatch.experiments.init('my-experiment');\n *\n * await experiment.run(dataset, async ({ item, index }) => {\n * const response = await myAgent(item.question);\n * experiment.log('accuracy', { index, score: 0.95 });\n * });\n * ```\n */\n async init(name: string, options?: ExperimentInitOptions): Promise<Experiment> {\n return Experiment.init(name, {\n apiClient: this.config.langwatchApiClient,\n endpoint: this.config.endpoint,\n apiKey: this.config.apiKey,\n logger: this.config.logger,\n ...options,\n });\n }\n\n /**\n * Run a platform-configured experiment (Experiments Workbench)\n *\n * This runs an experiment that was configured in the LangWatch platform.\n * The method automatically prints a summary and exits with code 1 on failure\n * (unless `exitOnFailure: false` is passed).\n *\n * @param slug - The slug of the experiment (found in the experiment URL)\n * @param options - Optional configuration\n * @returns The experiment results including pass rate and summary\n *\n * @example\n * ```typescript\n * import { LangWatch } from \"langwatch\";\n *\n * const langwatch = new LangWatch();\n *\n * const result = await langwatch.experiments.run(\"my-experiment-slug\");\n * result.printSummary();\n * ```\n */\n async run(slug: string, options?: RunExperimentOptions): Promise<ExperimentRunResult> {\n this.config.logger.info(`Running platform experiment: ${slug}`);\n const result = await this.runWithPolling(slug, options);\n return result;\n }\n\n /**\n * Run a platform experiment and return per-row structured results.\n *\n * Starts the run through the unified evaluations-v3 backend (optionally\n * overriding the configured inputs via `data` / `datasetId` / `parameters` /\n * `rowIndices`), polls to completion, fetches the per-row results, and maps\n * them to the same row structure as the python SDK's results DataFrame.\n *\n * @param slug - The slug of the experiment (found in the experiment URL)\n * @param options - Optional inputs and polling configuration\n * @returns The run id, results URL, status, summary, and per-row results\n *\n * @example\n * ```typescript\n * const langwatch = new LangWatch();\n * const { rows, runUrl } = await langwatch.experiments.runWithResults(\n * \"my-experiment-slug\",\n * { data: [{ question: \"What is 2 + 2?\" }] },\n * );\n * for (const row of rows) {\n * console.log(row.output, row.evaluations);\n * }\n * ```\n */\n async runWithResults(\n slug: string,\n options: RunWithResultsOptions = {},\n ): Promise<ExperimentRunWithResults> {\n this.config.logger.info(`Running platform experiment with results: ${slug}`);\n\n const body = toRunStartRequest({\n data: options.data,\n datasetId: options.datasetId,\n parameters: options.parameters,\n rowIndices: options.rowIndices,\n });\n\n const startResponse = await this.apiService.startV3Run({ slug, body });\n const { runId } = startResponse;\n\n const { status, summary } = await pollExperimentRun({\n runId,\n getStatus: (id) => this.apiService.getV3RunStatus(id),\n pollInterval: options.pollInterval,\n timeout: options.timeout,\n onProgress: options.onProgress,\n });\n\n // ClickHouse can lag right after completion: the results endpoint may 404\n // (\"not yet available\") or return 200 with an empty dataset before the rows\n // materialize. Retry both cases when the run reported rows, mirroring the\n // python SDK, instead of failing or returning an empty result.\n const results = await fetchResultsWithRetry({\n getResults: () =>\n this.apiService.getV3RunResults({ runId, experimentSlug: slug }),\n isEmpty: (r) => (r.dataset?.length ?? 0) === 0,\n expectsRows: (summary.totalCells ?? 0) > 0,\n delay: options.pollInterval ?? DEFAULT_POLL_INTERVAL,\n });\n\n // Always return the URL rebased onto the configured endpoint, so a\n // self-hosted run does not surface a cloud (app.langwatch.ai) link. Both\n // the start response and the summary carry the platform's own URL; whichever\n // is present gets its domain replaced. Mirrors the python SDK.\n const rawRunUrl = startResponse.runUrl ?? summary.runUrl;\n const runUrl = rawRunUrl\n ? rebaseUrlToEndpoint(rawRunUrl, this.config.endpoint)\n : \"\";\n\n return {\n runId,\n runUrl,\n status,\n summary,\n rows: mapRunResultsToRows(results),\n };\n }\n\n /**\n * Run an experiment and wait for completion using polling\n */\n private async runWithPolling(\n slug: string,\n options: RunExperimentOptions = {}\n ): Promise<ExperimentRunResult> {\n const pollInterval = options.pollInterval ?? DEFAULT_POLL_INTERVAL;\n const timeout = options.timeout ?? DEFAULT_TIMEOUT;\n\n // Start the run\n const startResponse = await this.startRun(slug);\n const { runId } = startResponse;\n\n // Use the run URL from API but replace domain with configured endpoint\n const apiRunUrl = startResponse.runUrl ?? \"\";\n const runUrl = apiRunUrl ? rebaseUrlToEndpoint(apiRunUrl, this.config.endpoint) : \"\";\n\n console.log(`Started experiment run: ${runId}`);\n if (runUrl) {\n console.log(`Follow live: ${runUrl}`);\n }\n\n const total = startResponse.total;\n let lastProgress = 0;\n\n // Print initial progress\n if (total > 0) {\n process.stdout.write(`Progress: 0/${total} (0%)`);\n }\n options.onProgress?.(0, total);\n\n const startTime = Date.now();\n\n // Poll until complete\n while (true) {\n if (Date.now() - startTime > timeout) {\n console.log(); // Newline after progress\n const finalStatus = await this.getRunStatus(runId);\n throw new ExperimentTimeoutError(runId, finalStatus.progress, finalStatus.total);\n }\n\n await this.sleep(pollInterval);\n\n const status = await this.getRunStatus(runId);\n const progress = status.progress;\n\n // Update progress display if changed\n if (progress !== lastProgress && status.total > 0) {\n const percentage = Math.round((progress / status.total) * 100);\n process.stdout.write(`\\rProgress: ${progress}/${status.total} (${percentage}%)`);\n lastProgress = progress;\n }\n\n options.onProgress?.(status.progress, status.total);\n\n if (status.status === \"completed\") {\n console.log(); // Newline after progress\n const summary = status.summary ?? {};\n return this.buildResult(runId, \"completed\", summary, runUrl ?? \"\");\n }\n\n if (status.status === \"failed\") {\n console.log(); // Newline after progress\n throw new ExperimentRunFailedError(runId, status.error ?? \"Unknown error\");\n }\n\n if (status.status === \"stopped\") {\n console.log(); // Newline after progress\n return this.buildResult(runId, \"stopped\", status.summary ?? {\n runId,\n totalCells: status.total,\n completedCells: status.progress,\n failedCells: 0,\n duration: Date.now() - startTime,\n }, runUrl ?? \"\");\n }\n }\n }\n\n /**\n * Start an experiment run\n */\n private async startRun(slug: string): Promise<{ runId: string; total: number; runUrl?: string }> {\n const response = await this.config.langwatchApiClient.POST(\n \"/api/experiments/{slug}/run\",\n {\n params: {\n path: { slug },\n },\n }\n );\n\n if (response.error) {\n const status = response.response.status;\n\n if (status === 404) {\n throw new ExperimentNotFoundError(slug);\n }\n\n if (status === 401) {\n throw new ExperimentsApiError(\"Unauthorized - check your API key\", 401);\n }\n\n const errorMessage =\n \"error\" in response.error ? response.error.error : `Failed to start experiment: ${slug}`;\n throw new ExperimentsApiError(errorMessage ?? `HTTP ${status}`, status);\n }\n\n return response.data as { runId: string; total: number; runUrl?: string };\n }\n\n /**\n * Get the status of a run\n */\n private async getRunStatus(runId: string): Promise<{\n status: string;\n progress: number;\n total: number;\n summary?: ExperimentRunSummary;\n error?: string;\n }> {\n const response = await this.config.langwatchApiClient.GET(\n \"/api/experiments/runs/{runId}\",\n {\n params: {\n path: { runId },\n },\n }\n );\n\n if (response.error) {\n const status = response.response.status;\n\n if (status === 404) {\n throw new ExperimentsApiError(`Run not found: ${runId}`, 404);\n }\n\n if (status === 401) {\n throw new ExperimentsApiError(\"Unauthorized - check your API key\", 401);\n }\n\n const errorMessage =\n \"error\" in response.error ? response.error.error : `Failed to get run status: ${runId}`;\n throw new ExperimentsApiError(errorMessage ?? `HTTP ${status}`, status);\n }\n\n return response.data as {\n status: string;\n progress: number;\n total: number;\n summary?: ExperimentRunSummary;\n error?: string;\n };\n }\n\n /**\n * Build the result object from API response\n */\n private buildResult(\n runId: string,\n status: \"completed\" | \"failed\" | \"stopped\",\n summary: ExperimentRunSummary,\n runUrl: string\n ): ExperimentRunResult {\n const completedCells = summary.completedCells ?? 0;\n const failedCells = summary.failedCells ?? 0;\n const duration = summary.duration ?? 0;\n\n const totalPassed = summary.totalPassed ?? completedCells - failedCells;\n const totalFailed = summary.totalFailed ?? failedCells;\n const passRate = summary.passRate ??\n (completedCells > 0 ? (totalPassed / completedCells) * 100 : 0);\n\n const result: ExperimentRunResult = {\n runId,\n status,\n passed: totalPassed,\n failed: totalFailed,\n passRate,\n duration,\n runUrl,\n summary,\n printSummary: (exitOnFailure = true) => {\n printSummary({\n runId,\n status,\n passed: totalPassed,\n failed: totalFailed,\n passRate,\n duration,\n runUrl: summary.runUrl ?? runUrl,\n summary,\n });\n\n if (exitOnFailure && totalFailed > 0) {\n process.exit(1);\n }\n },\n toString: () =>\n `ExperimentRunResult { status: ${status.toUpperCase()}, passed: ${totalPassed}, failed: ${totalFailed}, passRate: ${passRate.toFixed(1)}%, duration: ${(duration / 1000).toFixed(1)}s }`,\n };\n\n // Custom Node.js inspect for console.log\n (result as Record<string | symbol, unknown>)[Symbol.for(\"nodejs.util.inspect.custom\")] =\n () => result.toString();\n\n return result;\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n\n}\n","/**\n * EvaluationsFacade - Entry point for the Evaluations API (Online Evaluations / Guardrails)\n *\n * Provides an API for running evaluators and guardrails in real-time against LLM inputs/outputs.\n *\n * @example\n * ```typescript\n * const langwatch = new LangWatch({ apiKey: \"your-api-key\" });\n *\n * // Run a guardrail\n * const guardrail = await langwatch.evaluations.evaluate(\"presidio/pii_detection\", {\n * data: { input: userInput, output: generatedResponse },\n * name: \"PII Detection\",\n * asGuardrail: true,\n * settings: {},\n * });\n *\n * if (!guardrail.passed) {\n * return \"I'm sorry, I can't do that.\";\n * }\n * ```\n */\n\nimport { trace, SpanStatusCode, context as otelContext } from \"@opentelemetry/api\";\nimport { createLangWatchSpan } from \"@/observability-sdk/span/implementation\";\nimport type {\n EvaluationResult,\n EvaluateOptions,\n EvaluateRequest,\n EvaluateResponse,\n} from \"./types\";\nimport {\n EvaluatorCallError,\n EvaluatorNotFoundError,\n EvaluationsApiError,\n} from \"./errors\";\nimport type { Logger } from \"@/logger\";\nimport { buildAuthHeaders } from \"@/internal/api/auth\";\n\ntype EvaluationsFacadeConfig = {\n endpoint: string;\n apiKey: string;\n logger: Logger;\n};\n\nexport class EvaluationsFacade {\n readonly #endpoint: string;\n readonly #apiKey: string;\n readonly #logger: Logger;\n\n constructor(config: EvaluationsFacadeConfig) {\n this.#endpoint = config.endpoint;\n this.#apiKey = config.apiKey;\n this.#logger = config.logger;\n }\n\n /**\n * Run an evaluator or guardrail against provided data\n *\n * Creates an OpenTelemetry span attached to the current trace context,\n * calls the LangWatch evaluation API, and returns the result.\n *\n * @param slug - The evaluator slug (e.g., \"presidio/pii_detection\", \"langevals/llm_boolean\")\n * @param options - Evaluation options including data, name, settings, and asGuardrail flag\n * @returns The evaluation result with status, passed, score, details, label, and cost\n *\n * @example\n * ```typescript\n * // Run as a guardrail (synchronous evaluation that can block responses)\n * const guardrail = await langwatch.evaluations.evaluate(\"presidio/pii_detection\", {\n * data: { input: userInput, output: generatedResponse },\n * name: \"PII Detection Guardrail\",\n * asGuardrail: true,\n * });\n *\n * if (!guardrail.passed) {\n * console.log(\"PII detected:\", guardrail.details);\n * return \"Sorry, I cannot process that request.\";\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Run as an online evaluation (async scoring for monitoring)\n * const result = await langwatch.evaluations.evaluate(\"langevals/llm_boolean\", {\n * data: { input: question, output: response },\n * name: \"Quality Check\",\n * settings: { prompt: \"Check if the response answers the question.\" },\n * });\n *\n * console.log(\"Score:\", result.score);\n * console.log(\"Details:\", result.details);\n * ```\n */\n evaluate = async (\n slug: string,\n options: EvaluateOptions\n ): Promise<EvaluationResult> => {\n const { data, name, settings, asGuardrail } = options;\n const spanName = name ?? slug;\n const spanType = asGuardrail ? \"guardrail\" : \"evaluation\";\n\n // Get tracer and create a span attached to the current context\n const tracer = trace.getTracer(\"langwatch-evaluations\");\n\n // Get current trace/span IDs from active context\n const activeSpan = trace.getActiveSpan();\n const traceId = activeSpan\n ? activeSpan.spanContext().traceId\n : undefined;\n const parentSpanId = activeSpan\n ? activeSpan.spanContext().spanId\n : undefined;\n\n // Start the evaluation span\n const otelSpan = tracer.startSpan(\n spanName,\n {\n attributes: {\n \"langwatch.span.type\": spanType,\n },\n },\n otelContext.active()\n );\n\n const langwatchSpan = createLangWatchSpan(otelSpan);\n\n // Set span input\n langwatchSpan.setType(spanType);\n langwatchSpan.setInput({\n data,\n ...(settings && { settings }),\n });\n\n try {\n // Build request payload\n const requestBody: EvaluateRequest = {\n trace_id: traceId ?? null,\n span_id: parentSpanId ?? null,\n name: name ?? null,\n data,\n settings,\n as_guardrail: asGuardrail,\n };\n\n // Call the evaluation API\n const url = `${this.#endpoint}/api/evaluations/${slug}/evaluate`;\n\n this.#logger.debug(`Calling evaluation API: ${url}`);\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...buildAuthHeaders({ apiKey: this.#apiKey }),\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n\n if (response.status === 404) {\n throw new EvaluatorNotFoundError(slug);\n }\n\n throw new EvaluationsApiError(\n `Evaluation API returned ${response.status}: ${errorText}`,\n response.status\n );\n }\n\n const responseData = (await response.json()) as EvaluateResponse;\n\n // Map response to result\n const result: EvaluationResult = {\n status: responseData.status,\n ...(responseData.passed !== null && responseData.passed !== undefined && { passed: responseData.passed }),\n ...(responseData.score !== null && responseData.score !== undefined && { score: responseData.score }),\n ...(responseData.details !== null && responseData.details !== undefined && { details: responseData.details }),\n ...(responseData.label !== null && responseData.label !== undefined && { label: responseData.label }),\n ...(responseData.cost !== null && responseData.cost !== undefined && { cost: responseData.cost }),\n };\n\n // Update span with output\n langwatchSpan.setOutput({\n type: asGuardrail ? \"guardrail_result\" : \"evaluation_result\",\n value: result,\n });\n\n // Set span status based on result\n if (result.status === \"error\") {\n otelSpan.setStatus({\n code: SpanStatusCode.ERROR,\n message: result.details ?? \"Evaluation failed\",\n });\n } else {\n otelSpan.setStatus({ code: SpanStatusCode.OK });\n }\n\n return result;\n } catch (error) {\n // Handle errors\n const errorResult: EvaluationResult = {\n status: \"error\",\n details: error instanceof Error ? error.message : String(error),\n };\n\n // For guardrails, default to passed=true on error to avoid blocking\n if (asGuardrail) {\n errorResult.passed = true;\n }\n\n // Update span with error\n langwatchSpan.setOutput({\n type: asGuardrail ? \"guardrail_result\" : \"evaluation_result\",\n value: errorResult,\n });\n\n otelSpan.setStatus({\n code: SpanStatusCode.ERROR,\n message: errorResult.details,\n });\n\n if (error instanceof Error) {\n otelSpan.recordException(error);\n }\n\n // Re-throw known errors\n if (\n error instanceof EvaluatorNotFoundError ||\n error instanceof EvaluationsApiError ||\n error instanceof EvaluatorCallError\n ) {\n throw error;\n }\n\n // Wrap unknown errors\n throw new EvaluatorCallError(\n slug,\n error instanceof Error ? error.message : String(error)\n );\n } finally {\n // Always end the span\n otelSpan.end();\n }\n };\n}\n","/**\n * Error classes for the Evaluations API\n */\n\n/**\n * Base error for evaluation operations\n */\nexport class EvaluationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"EvaluationError\";\n }\n}\n\n/**\n * Error when an evaluator call fails\n */\nexport class EvaluatorCallError extends EvaluationError {\n readonly evaluatorSlug: string;\n readonly statusCode?: number;\n\n constructor(evaluatorSlug: string, message: string, statusCode?: number) {\n super(`Evaluator '${evaluatorSlug}' failed: ${message}`);\n this.name = \"EvaluatorCallError\";\n this.evaluatorSlug = evaluatorSlug;\n this.statusCode = statusCode;\n }\n}\n\n/**\n * Error when evaluator is not found\n */\nexport class EvaluatorNotFoundError extends EvaluationError {\n readonly evaluatorSlug: string;\n\n constructor(evaluatorSlug: string) {\n super(`Evaluator not found: ${evaluatorSlug}`);\n this.name = \"EvaluatorNotFoundError\";\n this.evaluatorSlug = evaluatorSlug;\n }\n}\n\n/**\n * Error from the evaluations API\n */\nexport class EvaluationsApiError extends EvaluationError {\n readonly statusCode: number;\n\n constructor(message: string, statusCode: number) {\n super(message);\n this.name = \"EvaluationsApiError\";\n this.statusCode = statusCode;\n }\n}\n","import type { paths } from \"@/internal/generated/openapi/api-client\";\nimport {\n createLangWatchApiClient,\n type LangwatchApiClient,\n} from \"@/internal/api/client\";\nimport type { InternalConfig } from \"@/client-sdk/types\";\nimport {\n extractStatusFromResponse,\n formatApiErrorForOperation,\n} from \"@/client-sdk/services/_shared/format-api-error\";\n\nexport type TriggerResponse = NonNullable<\n paths[\"/api/triggers\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"]\n>[number];\n\nexport type CreateTriggerBody = NonNullable<\n paths[\"/api/triggers\"][\"post\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\nexport type UpdateTriggerBody = NonNullable<\n paths[\"/api/triggers/{id}\"][\"patch\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\nexport type TriggerDeleteResponse =\n paths[\"/api/triggers/{id}\"][\"delete\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\n\nexport class TriggersApiError extends Error {\n constructor(\n message: string,\n public readonly operation: string,\n public readonly originalError?: unknown,\n ) {\n super(message);\n this.name = \"TriggersApiError\";\n }\n}\n\nexport class TriggersApiService {\n private readonly apiClient: LangwatchApiClient;\n\n constructor(config?: Pick<InternalConfig, \"langwatchApiClient\">) {\n this.apiClient = config?.langwatchApiClient ?? createLangWatchApiClient();\n }\n\n private handleApiError(operation: string, error: unknown): never {\n const message = formatApiErrorForOperation({ operation: operation, error: error, options: {\n status: extractStatusFromResponse(error),\n } });\n throw new TriggersApiError(message, operation, error);\n }\n\n async getAll(): Promise<TriggerResponse[]> {\n const { data, error } = await this.apiClient.GET(\"/api/triggers\");\n if (error) this.handleApiError(\"list triggers\", error);\n return data;\n }\n\n async get(id: string): Promise<TriggerResponse> {\n const { data, error } = await this.apiClient.GET(\"/api/triggers/{id}\", {\n params: { path: { id } },\n });\n if (error) this.handleApiError(`get trigger \"${id}\"`, error);\n return data;\n }\n\n async create(params: CreateTriggerBody): Promise<TriggerResponse> {\n const { data, error } = await this.apiClient.POST(\"/api/triggers\", {\n body: params,\n });\n if (error) this.handleApiError(\"create trigger\", error);\n return data;\n }\n\n async update(id: string, params: UpdateTriggerBody): Promise<TriggerResponse> {\n const { data, error } = await this.apiClient.PATCH(\"/api/triggers/{id}\", {\n params: { path: { id } },\n body: params,\n });\n if (error) this.handleApiError(`update trigger \"${id}\"`, error);\n return data;\n }\n\n async delete(id: string): Promise<TriggerDeleteResponse> {\n const { data, error } = await this.apiClient.DELETE(\"/api/triggers/{id}\", {\n params: { path: { id } },\n });\n if (error) this.handleApiError(`delete trigger \"${id}\"`, error);\n return data;\n }\n}\n","import type { paths } from \"@/internal/generated/openapi/api-client\";\nimport {\n createLangWatchApiClient,\n type LangwatchApiClient,\n} from \"@/internal/api/client\";\nimport type { InternalConfig } from \"@/client-sdk/types\";\nimport {\n extractStatusFromResponse,\n formatApiErrorForOperation,\n} from \"@/client-sdk/services/_shared/format-api-error\";\n\nexport type GraphResponse = NonNullable<\n paths[\"/api/graphs\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"]\n>[number];\n\nexport type CreateGraphBody = NonNullable<\n paths[\"/api/graphs\"][\"post\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\nexport type UpdateGraphBody = NonNullable<\n paths[\"/api/graphs/{id}\"][\"patch\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\nexport type GraphDeleteResponse =\n paths[\"/api/graphs/{id}\"][\"delete\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\n\nexport class GraphsApiError extends Error {\n constructor(\n message: string,\n public readonly operation: string,\n public readonly originalError?: unknown,\n ) {\n super(message);\n this.name = \"GraphsApiError\";\n }\n}\n\nexport class GraphsApiService {\n private readonly apiClient: LangwatchApiClient;\n\n constructor(config?: Pick<InternalConfig, \"langwatchApiClient\">) {\n this.apiClient = config?.langwatchApiClient ?? createLangWatchApiClient();\n }\n\n private handleApiError(operation: string, error: unknown): never {\n const message = formatApiErrorForOperation({ operation: operation, error: error, options: {\n status: extractStatusFromResponse(error),\n } });\n throw new GraphsApiError(message, operation, error);\n }\n\n async getAll(dashboardId?: string): Promise<GraphResponse[]> {\n const { data, error } = await this.apiClient.GET(\"/api/graphs\", {\n params: { query: { dashboardId } },\n });\n if (error) this.handleApiError(\"list graphs\", error);\n return data;\n }\n\n async get(id: string): Promise<GraphResponse> {\n const { data, error } = await this.apiClient.GET(\"/api/graphs/{id}\", {\n params: { path: { id } },\n });\n if (error) this.handleApiError(`get graph \"${id}\"`, error);\n return data;\n }\n\n async create(params: CreateGraphBody): Promise<GraphResponse> {\n const { data, error } = await this.apiClient.POST(\"/api/graphs\", {\n body: params,\n });\n if (error) this.handleApiError(\"create graph\", error);\n return data;\n }\n\n async update(id: string, params: UpdateGraphBody): Promise<GraphResponse> {\n const { data, error } = await this.apiClient.PATCH(\"/api/graphs/{id}\", {\n params: { path: { id } },\n body: params,\n });\n if (error) this.handleApiError(`update graph \"${id}\"`, error);\n return data;\n }\n\n async delete(id: string): Promise<GraphDeleteResponse> {\n const { data, error } = await this.apiClient.DELETE(\"/api/graphs/{id}\", {\n params: { path: { id } },\n });\n if (error) this.handleApiError(`delete graph \"${id}\"`, error);\n return data;\n }\n}\n","import type { paths } from \"@/internal/generated/openapi/api-client\";\nimport {\n createLangWatchApiClient,\n type LangwatchApiClient,\n} from \"@/internal/api/client\";\nimport type { InternalConfig } from \"@/client-sdk/types\";\nimport {\n extractStatusFromResponse,\n formatApiErrorForOperation,\n} from \"@/client-sdk/services/_shared/format-api-error\";\n\nexport type SimulationRunsListResponse =\n paths[\"/api/simulation-runs\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\n\nexport type SimulationRunResponse =\n paths[\"/api/simulation-runs/{scenarioRunId}\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\n\nexport type SimulationRunsBatchesListResponse =\n paths[\"/api/simulation-runs/batches/list\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\n\nexport type SimulationRunsListParams = NonNullable<\n paths[\"/api/simulation-runs\"][\"get\"][\"parameters\"][\"query\"]\n>;\n\nexport type SimulationRunsBatchesListParams =\n paths[\"/api/simulation-runs/batches/list\"][\"get\"][\"parameters\"][\"query\"];\n\nexport class SimulationRunsApiError extends Error {\n constructor(\n message: string,\n public readonly operation: string,\n public readonly originalError?: unknown,\n ) {\n super(message);\n this.name = \"SimulationRunsApiError\";\n }\n}\n\nexport class SimulationRunsApiService {\n private readonly apiClient: LangwatchApiClient;\n\n constructor(config?: Pick<InternalConfig, \"langwatchApiClient\">) {\n this.apiClient = config?.langwatchApiClient ?? createLangWatchApiClient();\n }\n\n private handleApiError(operation: string, error: unknown): never {\n const message = formatApiErrorForOperation({ operation: operation, error: error, options: {\n status: extractStatusFromResponse(error),\n } });\n throw new SimulationRunsApiError(message, operation, error);\n }\n\n async getAll(params?: SimulationRunsListParams): Promise<SimulationRunsListResponse> {\n const { data, error } = await this.apiClient.GET(\"/api/simulation-runs\", {\n params: { query: params },\n });\n if (error) this.handleApiError(\"list simulation runs\", error);\n return data;\n }\n\n async get(scenarioRunId: string): Promise<SimulationRunResponse> {\n const { data, error } = await this.apiClient.GET(\n \"/api/simulation-runs/{scenarioRunId}\",\n {\n params: { path: { scenarioRunId } },\n },\n );\n if (error)\n this.handleApiError(`get simulation run \"${scenarioRunId}\"`, error);\n return data;\n }\n\n async listBatches(\n params: SimulationRunsBatchesListParams,\n ): Promise<SimulationRunsBatchesListResponse> {\n const { data, error } = await this.apiClient.GET(\n \"/api/simulation-runs/batches/list\",\n {\n params: { query: params },\n },\n );\n if (error) this.handleApiError(\"list simulation run batches\", error);\n return data;\n }\n}\n","import { DEFAULT_ENDPOINT } from \"@/internal/constants\";\nimport { buildAuthHeaders } from \"@/internal/api/auth\";\nimport { formatApiErrorMessage } from \"@/client-sdk/services/_shared/format-api-error\";\n\nexport interface MonitorResponse {\n id: string;\n name: string;\n slug: string;\n checkType: string;\n enabled: boolean;\n executionMode: string;\n sample: number;\n level: string;\n evaluatorId: string | null;\n preconditions: unknown[];\n parameters: Record<string, unknown>;\n mappings: Record<string, unknown>;\n threadIdleTimeout: number | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface CreateMonitorBody {\n name: string;\n checkType: string;\n executionMode?: string;\n sample?: number;\n level?: string;\n preconditions?: unknown[];\n parameters?: Record<string, unknown>;\n mappings?: Record<string, unknown>;\n}\n\nexport interface UpdateMonitorBody {\n name?: string;\n enabled?: boolean;\n executionMode?: string;\n sample?: number;\n preconditions?: unknown[];\n parameters?: Record<string, unknown>;\n mappings?: Record<string, unknown>;\n}\n\nexport interface MonitorDeleteResponse {\n id: string;\n deleted: boolean;\n}\n\nexport class MonitorsApiError extends Error {\n constructor(\n message: string,\n public readonly operation: string,\n public readonly originalError?: unknown,\n ) {\n super(message);\n this.name = \"MonitorsApiError\";\n }\n}\n\nexport class MonitorsApiService {\n private readonly apiKey: string;\n private readonly endpoint: string;\n\n constructor(config?: { apiKey?: string; endpoint?: string }) {\n this.apiKey = config?.apiKey ?? process.env.LANGWATCH_API_KEY ?? \"\";\n this.endpoint = config?.endpoint ?? process.env.LANGWATCH_ENDPOINT ?? DEFAULT_ENDPOINT;\n }\n\n private async request<T>(path: string, options?: RequestInit): Promise<T> {\n const response = await fetch(`${this.endpoint}${path}`, {\n ...options,\n headers: {\n ...buildAuthHeaders({ apiKey: this.apiKey }),\n \"Content-Type\": \"application/json\",\n ...options?.headers,\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n let parsed: unknown = errorText;\n try {\n parsed = JSON.parse(errorText);\n } catch {\n // leave as raw text\n }\n const message = formatApiErrorMessage({ error: parsed, options: { status: response.status } });\n throw new MonitorsApiError(\n `HTTP ${response.status}: ${message}`,\n options?.method ?? \"GET\",\n parsed,\n );\n }\n\n return response.json() as Promise<T>;\n }\n\n async getAll(): Promise<MonitorResponse[]> {\n return this.request<MonitorResponse[]>(\"/api/monitors\");\n }\n\n async get(id: string): Promise<MonitorResponse> {\n return this.request<MonitorResponse>(`/api/monitors/${encodeURIComponent(id)}`);\n }\n\n async create(body: CreateMonitorBody): Promise<MonitorResponse> {\n return this.request<MonitorResponse>(\"/api/monitors\", {\n method: \"POST\",\n body: JSON.stringify(body),\n });\n }\n\n async update(id: string, body: UpdateMonitorBody): Promise<MonitorResponse> {\n return this.request<MonitorResponse>(`/api/monitors/${encodeURIComponent(id)}`, {\n method: \"PATCH\",\n body: JSON.stringify(body),\n });\n }\n\n async toggle(id: string, enabled: boolean): Promise<MonitorResponse> {\n return this.request<MonitorResponse>(`/api/monitors/${encodeURIComponent(id)}/toggle`, {\n method: \"POST\",\n body: JSON.stringify({ enabled }),\n });\n }\n\n async delete(id: string): Promise<MonitorDeleteResponse> {\n return this.request<MonitorDeleteResponse>(`/api/monitors/${encodeURIComponent(id)}`, {\n method: \"DELETE\",\n });\n }\n}\n","import { DEFAULT_ENDPOINT } from \"@/internal/constants\";\nimport { buildAuthHeaders } from \"@/internal/api/auth\";\nimport { formatApiErrorMessage } from \"@/client-sdk/services/_shared/format-api-error\";\n\nexport interface SecretResponse {\n id: string;\n projectId: string;\n name: string;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface SecretDeleteResponse {\n id: string;\n deleted: boolean;\n}\n\nexport class SecretsApiError extends Error {\n constructor(\n message: string,\n public readonly operation: string,\n public readonly originalError?: unknown,\n ) {\n super(message);\n this.name = \"SecretsApiError\";\n }\n}\n\nexport class SecretsApiService {\n private readonly apiKey: string;\n private readonly endpoint: string;\n\n constructor(config?: { apiKey?: string; endpoint?: string }) {\n this.apiKey = config?.apiKey ?? process.env.LANGWATCH_API_KEY ?? \"\";\n this.endpoint = config?.endpoint ?? process.env.LANGWATCH_ENDPOINT ?? DEFAULT_ENDPOINT;\n }\n\n private async request<T>(path: string, options?: RequestInit): Promise<T> {\n const response = await fetch(`${this.endpoint}${path}`, {\n ...options,\n headers: {\n ...buildAuthHeaders({ apiKey: this.apiKey }),\n \"Content-Type\": \"application/json\",\n ...options?.headers,\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n let parsed: unknown = errorText;\n try {\n parsed = JSON.parse(errorText);\n } catch {\n // leave as raw text\n }\n const message = formatApiErrorMessage({ error: parsed, options: { status: response.status } });\n throw new SecretsApiError(\n `HTTP ${response.status}: ${message}`,\n options?.method ?? \"GET\",\n parsed,\n );\n }\n\n return response.json() as Promise<T>;\n }\n\n async getAll(): Promise<SecretResponse[]> {\n return this.request<SecretResponse[]>(\"/api/secrets\");\n }\n\n async get(id: string): Promise<SecretResponse> {\n return this.request<SecretResponse>(`/api/secrets/${encodeURIComponent(id)}`);\n }\n\n async create(body: { name: string; value: string }): Promise<SecretResponse> {\n return this.request<SecretResponse>(\"/api/secrets\", {\n method: \"POST\",\n body: JSON.stringify(body),\n });\n }\n\n async update(id: string, body: { value: string }): Promise<SecretResponse> {\n return this.request<SecretResponse>(`/api/secrets/${encodeURIComponent(id)}`, {\n method: \"PUT\",\n body: JSON.stringify(body),\n });\n }\n\n async delete(id: string): Promise<SecretDeleteResponse> {\n return this.request<SecretDeleteResponse>(`/api/secrets/${encodeURIComponent(id)}`, {\n method: \"DELETE\",\n });\n }\n}\n","import type { paths } from \"@/internal/generated/openapi/api-client\";\n\nexport interface GetTraceParams {\n includeSpans?: boolean;\n}\n\nexport type GetTraceResponse = NonNullable<\n paths[\"/api/trace/{id}\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"]\n>;\n\n/**\n * Custom error class for Traces API operations.\n * Provides context about the failed operation and the original error.\n */\nexport class TracesError extends Error {\n constructor(\n message: string,\n public readonly operation: string,\n public readonly originalError?: any,\n ) {\n super(message);\n this.name = \"TracesError\";\n }\n}\n","import { LANGWATCH_SDK_NAME_CLIENT, LANGWATCH_SDK_VERSION } from \"@/internal/constants\";\nimport { getLangWatchTracer } from \"@/observability-sdk/tracer\";\n\nexport const tracer = getLangWatchTracer(`${LANGWATCH_SDK_NAME_CLIENT}.traces`, LANGWATCH_SDK_VERSION);\n","import { createTracingProxy } from \"@/client-sdk/tracing/create-tracing-proxy\";\nimport { type InternalConfig } from \"@/client-sdk/types\";\nimport { type GetTraceParams, TracesError, type GetTraceResponse } from \"./types\";\nimport { tracer } from \"./tracing\";\n\n/**\n * Service for managing trace resources via the Langwatch API.\n * Constructor creates a proxy that wraps the service and traces all methods.\n *\n * Responsibilities:\n * - Retrieving trace data\n * - Error handling with contextual information\n *\n * All methods return trace response objects directly.\n */\nexport class TracesService {\n private config: InternalConfig;\n\n constructor(config: InternalConfig) {\n this.config = config;\n\n /**\n * Wraps the service in a tracing proxy via the decorator.\n */\n return createTracingProxy(\n this as TracesService,\n tracer,\n );\n }\n\n /**\n * Handles API errors by throwing a TracesError with operation context.\n * @param operation Description of the operation being performed.\n * @param error The error object returned from the API client.\n * @throws {TracesError}\n */\n private handleApiError(operation: string, error: any): never {\n const errorMessage =\n typeof error === \"string\"\n ? error\n : error?.error ?? error?.message ?? \"Unknown error occurred\";\n throw new TracesError(\n `Failed to ${operation}: ${errorMessage}`,\n operation,\n error,\n );\n }\n\n /**\n * Retrieves a trace by its ID.\n * @param traceId The trace's unique identifier.\n * @param params Optional parameters for the request.\n * @returns The trace response object.\n * @throws {TracesError} If the API call fails.\n */\n async get(\n traceId: string,\n params?: GetTraceParams,\n ): Promise<GetTraceResponse> {\n const { data, error } = await this.config.langwatchApiClient.GET(\"/api/trace/{id}\", {\n params: {\n path: {\n id: traceId,\n },\n },\n query: params,\n });\n\n if (error) {\n this.handleApiError(\"get trace\", error);\n }\n\n return data;\n }\n}\n","import { type InternalConfig } from \"../../types\";\nimport { TracesService } from \"./service\";\nimport { type GetTraceParams, type GetTraceResponse } from \"./types\";\n\nexport class TracesFacade {\n readonly #service: TracesService;\n\n constructor(config: InternalConfig) {\n this.#service = new TracesService(config);\n }\n\n async get(traceId: string, params?: GetTraceParams): Promise<GetTraceResponse> {\n return this.#service.get(traceId, params);\n }\n}\n","import { PromptsFacade, PromptsApiService } from \"./services/prompts\";\nexport { FetchPolicy, type GetPromptOptions } from \"./services/prompts\";\nexport type {\n Dataset,\n DatasetEntry,\n DatasetMetadata,\n DatasetColumnType,\n DatasetListItem,\n Pagination,\n PaginatedResponse,\n GetDatasetOptions,\n ListDatasetsOptions,\n ListDatasetsApiResponse,\n ListRecordsOptions,\n ListRecordsApiResponse,\n CreateDatasetOptions,\n UpdateDatasetOptions,\n CreateFromUploadResponse,\n BatchCreateRecordsResponse,\n DeleteRecordsResponse,\n UploadResponse,\n DatasetRecordResponse,\n} from \"./services/datasets\";\nexport { DatasetError, DatasetNotFoundError, DatasetApiError, DatasetValidationError, DatasetPlanLimitError } from \"./services/datasets\";\nexport type {\n ExperimentRunResult,\n RunExperimentOptions,\n RunWithResultsOptions,\n ExperimentRowResult,\n ExperimentRunWithResults,\n} from \"./services/experiments\";\nexport {\n ExperimentsError,\n ExperimentNotFoundError,\n ExperimentTimeoutError,\n ExperimentRunFailedError,\n ExperimentsApiError,\n} from \"./services/experiments\";\nexport type { EvaluationResult, EvaluateOptions, EvaluationStatus, EvaluationCost } from \"./services/evaluations\";\nexport {\n EvaluationError,\n EvaluatorCallError,\n EvaluatorNotFoundError,\n EvaluationsApiError,\n} from \"./services/evaluations\";\nexport { EvaluatorsApiService, EvaluatorsApiError } from \"./services/evaluators\";\nexport { ScenariosApiService, ScenariosApiError } from \"./services/scenarios\";\nexport { SuitesApiService, SuitesApiError } from \"./services/suites\";\nexport { WorkflowsApiService, WorkflowsApiError } from \"./services/workflows/workflows-api.service\";\nexport { AgentsApiService, AgentsApiError } from \"./services/agents/agents-api.service\";\nexport { AnnotationsApiService, AnnotationsApiError } from \"./services/annotations/annotations-api.service\";\nexport { DashboardsApiService, DashboardsApiError } from \"./services/dashboards/dashboards-api.service\";\nexport { ModelProvidersApiService, ModelProvidersApiError } from \"./services/model-providers/model-providers-api.service\";\nexport { AnalyticsApiService, AnalyticsApiError } from \"./services/analytics/analytics-api.service\";\nexport { TriggersApiService, TriggersApiError } from \"./services/triggers\";\nexport { GraphsApiService, GraphsApiError } from \"./services/graphs\";\nexport { SimulationRunsApiService, SimulationRunsApiError } from \"./services/simulation-runs\";\nexport { TracesApiService, TracesApiError } from \"./services/traces/traces-api.service\";\nexport { MonitorsApiService, MonitorsApiError } from \"./services/monitors\";\nexport { SecretsApiService, SecretsApiError } from \"./services/secrets\";\nimport { LocalPromptsService } from \"./services/prompts/local-prompts.service\";\nimport { ExperimentsFacade } from \"./services/experiments\";\nimport { DatasetsFacade } from \"./services/datasets\";\nimport { EvaluationsFacade } from \"./services/evaluations\";\nimport { EvaluatorsApiService } from \"./services/evaluators\";\nimport { ScenariosApiService } from \"./services/scenarios\";\nimport { SuitesApiService } from \"./services/suites\";\nimport { WorkflowsApiService } from \"./services/workflows/workflows-api.service\";\nimport { AgentsApiService } from \"./services/agents/agents-api.service\";\nimport { AnnotationsApiService } from \"./services/annotations/annotations-api.service\";\nimport { DashboardsApiService } from \"./services/dashboards/dashboards-api.service\";\nimport { ModelProvidersApiService } from \"./services/model-providers/model-providers-api.service\";\nimport { AnalyticsApiService } from \"./services/analytics/analytics-api.service\";\nimport { TriggersApiService } from \"./services/triggers\";\nimport { GraphsApiService } from \"./services/graphs\";\nimport { SimulationRunsApiService } from \"./services/simulation-runs\";\nimport { MonitorsApiService } from \"./services/monitors\";\nimport { SecretsApiService } from \"./services/secrets\";\nimport { type InternalConfig } from \"./types\";\nimport { createLangWatchApiClient, type LangwatchApiClient } from \"../internal/api/client\";\nimport { type Logger, NoOpLogger } from \"../logger\";\nimport { TracesFacade } from \"./services/traces/facade\";\nimport { DEFAULT_ENDPOINT } from \"@/internal/constants\";\n\nexport interface LangWatchConstructorOptions {\n apiKey?: string;\n endpoint?: string;\n options?: {\n logger?: Logger;\n };\n}\n\nexport class LangWatch {\n private readonly config: InternalConfig & { endpoint: string; apiKey: string };\n\n readonly prompts: PromptsFacade;\n readonly traces: TracesFacade;\n readonly datasets: DatasetsFacade;\n\n /**\n * Run experiments on LangWatch platform or via SDK.\n *\n * Platform experiments (CI/CD):\n * ```typescript\n * const result = await langwatch.experiments.run(\"my-experiment-slug\");\n * result.printSummary();\n * ```\n *\n * SDK-defined experiments:\n * ```typescript\n * const experiment = await langwatch.experiments.init(\"my-experiment\");\n * // ... run evaluators using experiment.evaluate()\n * ```\n */\n readonly experiments: ExperimentsFacade;\n\n /**\n * Run evaluators and guardrails in real-time (Online Evaluations).\n *\n * @example\n * ```typescript\n * const guardrail = await langwatch.evaluations.evaluate(\"presidio/pii_detection\", {\n * data: { input: userInput, output: generatedResponse },\n * name: \"PII Detection\",\n * asGuardrail: true,\n * });\n *\n * if (!guardrail.passed) {\n * return \"I'm sorry, I can't do that.\";\n * }\n * ```\n */\n readonly evaluations: EvaluationsFacade;\n\n readonly evaluators: EvaluatorsApiService;\n readonly scenarios: ScenariosApiService;\n readonly suites: SuitesApiService;\n readonly workflows: WorkflowsApiService;\n readonly agents: AgentsApiService;\n readonly annotations: AnnotationsApiService;\n readonly dashboards: DashboardsApiService;\n readonly modelProviders: ModelProvidersApiService;\n readonly analytics: AnalyticsApiService;\n readonly triggers: TriggersApiService;\n readonly graphs: GraphsApiService;\n readonly simulationRuns: SimulationRunsApiService;\n readonly monitors: MonitorsApiService;\n readonly secrets: SecretsApiService;\n\n constructor(options: LangWatchConstructorOptions = {}) {\n const apiKey = options.apiKey ?? process.env.LANGWATCH_API_KEY ?? \"\";\n const endpoint = options.endpoint ?? process.env.LANGWATCH_ENDPOINT ?? DEFAULT_ENDPOINT;\n\n this.config = this.#createInternalConfig({\n apiKey,\n endpoint,\n options: options.options,\n });\n\n this.prompts = new PromptsFacade({\n promptsApiService: new PromptsApiService(this.config),\n localPromptsService: new LocalPromptsService(),\n ...this.config,\n });\n this.traces = new TracesFacade(this.config);\n\n this.experiments = new ExperimentsFacade({\n langwatchApiClient: this.config.langwatchApiClient,\n endpoint: this.config.endpoint,\n apiKey: this.config.apiKey,\n logger: this.config.logger,\n });\n\n this.datasets = new DatasetsFacade({\n langwatchApiClient: this.config.langwatchApiClient,\n logger: this.config.logger,\n endpoint: this.config.endpoint,\n apiKey: this.config.apiKey,\n });\n\n this.evaluations = new EvaluationsFacade({\n endpoint: this.config.endpoint,\n apiKey: this.config.apiKey,\n logger: this.config.logger,\n });\n\n this.evaluators = new EvaluatorsApiService(this.config);\n this.scenarios = new ScenariosApiService(this.config);\n this.suites = new SuitesApiService(this.config);\n this.workflows = new WorkflowsApiService(this.config);\n this.agents = new AgentsApiService(this.config);\n this.annotations = new AnnotationsApiService(this.config);\n this.dashboards = new DashboardsApiService(this.config);\n this.modelProviders = new ModelProvidersApiService(this.config);\n this.analytics = new AnalyticsApiService(this.config);\n this.triggers = new TriggersApiService(this.config);\n this.graphs = new GraphsApiService(this.config);\n this.simulationRuns = new SimulationRunsApiService(this.config);\n this.monitors = new MonitorsApiService({ apiKey, endpoint });\n this.secrets = new SecretsApiService({ apiKey, endpoint });\n }\n\n get apiClient(): LangwatchApiClient {\n return this.config.langwatchApiClient;\n }\n\n #createInternalConfig({\n apiKey,\n endpoint,\n options,\n }: {\n apiKey: string;\n endpoint: string;\n options?: LangWatchConstructorOptions[\"options\"];\n }): InternalConfig & { endpoint: string; apiKey: string } {\n return {\n logger: options?.logger ?? new NoOpLogger(),\n langwatchApiClient: createLangWatchApiClient(apiKey, endpoint),\n endpoint,\n apiKey,\n };\n }\n}\n","import { ConsoleLogger, NoOpLogger } from \"./logger\";\n\nexport {\n getLangWatchTracer,\n getLangWatchLogger,\n attributes,\n} from \"./observability-sdk\";\n\nexport {\n FilterableBatchSpanProcessor,\n type SpanProcessingExcludeRule,\n} from \"./observability-sdk/processors\";\nexport { LangWatchExporter } from \"./observability-sdk/exporters\";\nexport { LangWatch, FetchPolicy, type GetPromptOptions } from \"./client-sdk\";\n\n// Experiments API exports\nexport {\n Experiment,\n ExperimentsFacade,\n type EvaluationStatus as ExperimentEvaluationStatus,\n type TargetType,\n type TargetMetadata,\n type TargetInfo,\n type EvaluationResult as ExperimentEvaluationResult,\n type ExperimentInitOptions,\n type LogOptions,\n type EvaluateOptions as ExperimentEvaluateOptions,\n type RunOptions,\n type RunCallback,\n type RunContext,\n type RunWithResultsOptions,\n type ExperimentRowResult,\n type ExperimentRunWithResults,\n ExperimentError,\n ExperimentInitError,\n ExperimentApiError,\n TargetMetadataConflictError,\n EvaluatorError,\n} from \"./client-sdk/services/experiments\";\n\n// Evaluators API exports\nexport {\n EvaluatorsApiService,\n type EvaluatorResponse,\n type EvaluatorField,\n type CreateEvaluatorBody,\n EvaluatorsApiError,\n} from \"./client-sdk/services/evaluators\";\n\n// Dataset API exports\nexport {\n DatasetsFacade,\n DatasetError,\n DatasetNotFoundError,\n DatasetApiError,\n DatasetValidationError,\n DatasetPlanLimitError,\n type Dataset,\n type DatasetEntry,\n type DatasetMetadata,\n type DatasetColumnType,\n type DatasetListItem,\n type Pagination,\n type PaginatedResponse,\n type GetDatasetOptions,\n type ListDatasetsOptions,\n type ListDatasetsApiResponse,\n type ListRecordsOptions,\n type ListRecordsApiResponse,\n type CreateDatasetOptions,\n type UpdateDatasetOptions,\n type CreateFromUploadResponse,\n type BatchCreateRecordsResponse,\n type DeleteRecordsResponse,\n type UploadResponse,\n type DatasetRecordResponse,\n} from \"./client-sdk/services/datasets\";\n\n// Evaluations API exports (Online Evaluations / Guardrails)\nexport {\n EvaluationsFacade,\n type EvaluationResult,\n type EvaluateOptions,\n type EvaluationStatus,\n type EvaluationCost,\n EvaluationError,\n EvaluatorCallError,\n EvaluatorNotFoundError,\n EvaluationsApiError,\n} from \"./client-sdk/services/evaluations\";\n\nexport const logger = {\n ConsoleLogger,\n NoOpLogger,\n};\n"]}
1
+ {"version":3,"sources":["/home/runner/work/langwatch/langwatch/typescript-sdk/dist/index.js","../src/client-sdk/services/prompts/prompts-api.service.ts","../src/cli/utils/responseFormat.ts","../src/cli/utils/promptConverter.ts","../src/client-sdk/services/prompts/tracing/prompt-tracing.decorator.ts","../src/client-sdk/services/prompts/tracing/prompt-service-tracing.decorator.ts","../src/client-sdk/services/prompts/tracing/tracer.ts","../src/client-sdk/tracing/create-tracing-proxy.ts","../src/internal/api/client.ts","../../packages/langy/src/cards/handled-error.ts","../src/internal/api/errors.ts","../src/client-sdk/services/prompts/errors/prompt-compilation.error.ts","../src/client-sdk/services/prompts/errors/prompt-validation.error.ts","../src/client-sdk/services/prompts/errors/prompts.error.ts","../src/client-sdk/services/prompts/errors/prompts-api.error.ts","../src/client-sdk/services/_shared/format-api-error.ts","../src/client-sdk/services/prompts/prompt.ts","../src/client-sdk/services/prompts/schema/prompt.schema.ts","../src/client-sdk/services/prompts/constants.ts","../src/client-sdk/services/prompts/types.ts","../src/cli/utils/fileManager.ts","../src/cli/types-prompt.ts","../src/cli/utils/errors/prompt-not-found.error.ts","../src/client-sdk/services/prompts/local-prompts.service.ts","../src/client-sdk/services/prompts/prompts.facade.ts","../src/client-sdk/services/datasets/errors.ts","../src/client-sdk/services/datasets/tracing/tracer.ts","../src/client-sdk/services/datasets/dataset.service.ts","../src/client-sdk/services/datasets/datasets.facade.ts","../src/client-sdk/services/experiments/experiment.ts","../src/client-sdk/services/experiments/humanReadableId.ts","../src/client-sdk/services/experiments/errors/experiment.error.ts","../src/client-sdk/services/experiments/printSummary.ts","../src/client-sdk/services/experiments/experiments-api.service.ts","../src/client-sdk/services/experiments/platformErrors.ts","../src/client-sdk/services/experiments/run-status.ts","../src/client-sdk/services/experiments/mapResults.ts","../src/client-sdk/services/experiments/experiments.facade.ts","../src/client-sdk/services/evaluations/evaluations.facade.ts","../src/client-sdk/services/evaluations/errors.ts","../src/client-sdk/services/evaluators/errors.ts","../src/client-sdk/services/evaluators/evaluators-api.service.ts","../src/client-sdk/services/scenarios/errors.ts","../src/client-sdk/services/scenarios/scenarios-api.service.ts","../src/client-sdk/services/suites/suites-api.service.ts","../src/client-sdk/services/workflows/workflows-api.service.ts","../src/client-sdk/services/agents/agents-api.service.ts","../src/client-sdk/services/annotations/annotations-api.service.ts","../src/client-sdk/services/dashboards/dashboards-api.service.ts","../src/client-sdk/services/model-providers/model-providers-api.service.ts","../src/client-sdk/services/analytics/analytics-api.service.ts","../src/client-sdk/services/triggers/triggers-api.service.ts","../src/client-sdk/services/graphs/graphs-api.service.ts","../src/client-sdk/services/simulation-runs/simulation-runs-api.service.ts","../src/client-sdk/services/_shared/throw-handled-error.ts","../src/client-sdk/services/monitors/monitors-api.service.ts","../src/client-sdk/services/secrets/secrets-api.service.ts","../src/client-sdk/services/traces/types.ts","../src/client-sdk/services/traces/tracing/tracer.ts","../src/client-sdk/services/traces/service.ts","../src/client-sdk/services/traces/facade.ts","../src/client-sdk/index.ts","../src/index.ts"],"names":["target","path","z","FetchPolicy","tracer","_a","DEFAULT_POLL_INTERVAL"],"mappings":"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ACF,EAAA;AACF;AATW;A5DwuKF;AACA;A6D9uKT;AA4Fa;AAyDX,EAAA;AAzDK,IAAA;AA5FP,IAAA;AAsJI,IAAA;AACA,IAAA;AAEK,IAAA;AACH,MAAA;AACA,MAAA;AACA,MAAA;AACF,IAAA;AAEK,IAAA;AACH,MAAA;AACA,MAAA;AACG,IAAA;AAEA,IAAA;AAEA,IAAA;AACH,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACD,IAAA;AAEI,IAAA;AACH,MAAA;AACA,MAAA;AACA,MAAA;AACA,MAAA;AACD,IAAA;AAEI,IAAA;AACH,MAAA;AACA,MAAA;AACA,MAAA;AACD,IAAA;AAEI,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACP,EAAA;AAEI,EAAA;AACF,IAAA;AACF,EAAA;AAkBF;AAlIO;AAkHL;AACE,EAAA;AACA,EAAA;AACA,EAAA;AAKwD;AAtN5D,EAAA;AAuNW,EAAA;AACL,IAAA;AACA,IAAA;AACA,IAAA;AACA,IAAA;AACF,EAAA;AACF;A7DqlKO;AACA;A8DrrKI;AACX,EAAA;AACA,EAAA;AACF;A9DurKS;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/langwatch/langwatch/typescript-sdk/dist/index.js","sourcesContent":[null,"import { z } from \"zod\";\nimport type { paths, operations } from \"@/internal/generated/openapi/api-client\";\nimport { type PromptResponse, type TagDefinition, type CreatedTag } from \"./types\";\nimport { PromptConverter } from \"@/cli/utils/promptConverter\";\nimport { PromptServiceTracingDecorator, tracer } from \"./tracing\";\nimport { createTracingProxy } from \"@/client-sdk/tracing/create-tracing-proxy\";\nimport { type InternalConfig } from \"@/client-sdk/types\";\nimport { type CreatePromptBody, type UpdatePromptBody } from \"./types\";\nimport { createLangWatchApiClient, type LangwatchApiClient } from \"@/internal/api/client\";\nimport { isLangWatchHandledError } from \"@/internal/api/errors\";\nimport { PromptsApiError } from \"./errors\";\nimport {\n extractStatusFromResponse,\n formatApiErrorForOperation,\n formatApiErrorMessage,\n} from \"@/client-sdk/services/_shared/format-api-error\";\nimport type { RuntimeParameters } from \"@/cli/types\";\n\nconst syncActionSchema = z.enum([\n \"created\",\n \"updated\",\n \"conflict\",\n \"up_to_date\",\n]);\n\nexport type SyncAction = z.infer<typeof syncActionSchema>;\n\nconst syncResultSchema = z.object({\n action: syncActionSchema,\n // `prompt` and `conflictInfo` are passed through untyped — they come from\n // the OpenAPI-derived shape which is already validated on the server side.\n prompt: z.unknown().optional(),\n conflictInfo: z\n .object({\n localVersion: z.number(),\n remoteVersion: z.number(),\n differences: z.array(z.string()),\n remoteConfigData: z.unknown(),\n })\n .passthrough()\n .optional(),\n});\n\nexport type AssignTagResult = NonNullable<\n operations[\"putApiPromptsByIdTagsByTag\"][\"responses\"][\"200\"][\"content\"][\"application/json\"]\n>;\n\nexport type ConfigData = NonNullable<\n paths[\"/api/prompts/{id}/sync\"][\"post\"][\"requestBody\"]\n>[\"content\"][\"application/json\"][\"configData\"];\n\nexport interface SyncResult {\n action: SyncAction;\n prompt?: PromptResponse;\n conflictInfo?: {\n localVersion: number;\n remoteVersion: number;\n differences: string[];\n remoteConfigData: ConfigData;\n remoteParameters?: RuntimeParameters;\n };\n}\n\n/**\n * Service for managing prompt resources via the Langwatch API.\n * Constructor creates a proxy that wraps the service and traces all methods.\n *\n * Responsibilities:\n * - CRUD operations for prompts\n * - Creating prompt versions\n * - Error handling with contextual information\n *\n * All methods return raw PromptResponse data from the API.\n */\nexport class PromptsApiService {\n private readonly apiClient: LangwatchApiClient;\n\n constructor(config?: Pick<InternalConfig, \"langwatchApiClient\">) {\n this.apiClient = config?.langwatchApiClient ?? createLangWatchApiClient();\n\n /**\n * Wraps the service in a tracing proxy via the decorator.\n */\n return createTracingProxy(\n this as PromptsApiService,\n tracer,\n PromptServiceTracingDecorator,\n );\n }\n\n /**\n * Handles API errors by throwing a PromptsApiError with operation context.\n * @param operation Description of the operation being performed.\n * @param error The error object returned from the API client.\n * @throws {PromptsApiError}\n */\n private handleApiError(operation: string, error: any, status?: number): never {\n const resolvedStatus = status ?? extractStatusFromResponse(error);\n const message = formatApiErrorForOperation({ operation: operation, error: error, options: {\n status: resolvedStatus,\n } });\n\n throw new PromptsApiError(message, operation, error);\n }\n\n /**\n * Fetches all prompts from the API.\n * @returns Array of raw PromptResponse data.\n * @throws {PromptsApiError} If the API call fails.\n */\n async getAll(): Promise<PromptResponse[]> {\n const { data, error } =\n await this.apiClient.GET(\"/api/prompts\");\n if (error) this.handleApiError(\"fetch all prompts\", error);\n return data;\n }\n\n /**\n * Fetches a single prompt by its ID.\n * @param id The prompt's unique identifier.\n * @param options Optional parameters for the request.\n * @param options.version Specific version to fetch (numeric string or \"latest\").\n * @param options.tag Tag to fetch (e.g., \"production\", \"staging\", or a custom tag).\n * @returns Raw PromptResponse data.\n * @throws {PromptsApiError} If the API call fails.\n */\n get = async (id: string, options?: { version?: string; tag?: string }): Promise<PromptResponse> => {\n // Parse version to number, skip for \"latest\" or invalid values\n const versionNumber = options?.version && options.version !== \"latest\"\n ? parseInt(options.version, 10)\n : undefined;\n\n const { data, error } = await this.apiClient.GET(\n \"/api/prompts/{id}\",\n {\n params: {\n path: { id },\n query: {\n version: Number.isNaN(versionNumber) ? undefined : versionNumber,\n tag: options?.tag,\n },\n },\n },\n );\n\n if (error) {\n this.handleApiError(`fetch prompt with ID \"${id}\"`, error);\n }\n\n return data;\n }\n\n /**\n * Validates if a prompt exists.\n * @param id The prompt's unique identifier.\n * @returns True if prompt exists, false otherwise.\n * @throws {PromptsApiError} If the API call fails (not 404).\n */\n async exists(id: string): Promise<boolean> {\n try {\n await this.get(id);\n return true;\n } catch (error) {\n // A named 404 from the platform (\"prompt_not_found\") now arrives typed, so\n // read the status off the domain error first. Without this, the very thing\n // that makes the failure legible — the platform naming it — would stop\n // `exists()` recognising a missing prompt and turn a `false` into a throw.\n if (isLangWatchHandledError(error) && error.httpStatus === 404) {\n return false;\n }\n\n const originalError = error instanceof PromptsApiError ? error.originalError : null;\n const statusCode = originalError != null && typeof originalError === \"object\" && \"statusCode\" in originalError\n ? (originalError as { statusCode: unknown }).statusCode\n : null;\n\n if (statusCode === 404) {\n return false;\n }\n\n throw error;\n }\n }\n\n /**\n * Creates a new prompt.\n * @param params The prompt creation payload, matching the OpenAPI schema.\n * @returns Raw PromptResponse data of the created prompt.\n * @throws {PromptsApiError} If the API call fails.\n */\n async create(params: CreatePromptBody): Promise<PromptResponse> {\n const { data, error } = await this.apiClient.POST(\n \"/api/prompts\",\n {\n body: params,\n },\n );\n if (error) this.handleApiError(\"create prompt\", error);\n return data;\n }\n\n /**\n * Updates an existing prompt.\n * @param id The prompt's unique identifier.\n * @param params The update payload, matching the OpenAPI schema.\n * @returns Raw PromptResponse data of the updated prompt.\n * @throws {PromptsApiError} If the API call fails.\n */\n async update(id: string, params: UpdatePromptBody): Promise<PromptResponse> {\n const { error, data: updatedPrompt } =\n await this.apiClient.PUT(\"/api/prompts/{id}\", {\n params: { path: { id } },\n body: params,\n });\n if (error) this.handleApiError(`update prompt with ID \"${id}\"`, error);\n return updatedPrompt;\n }\n\n /**\n * Lists all prompt tags (built-in and custom) for the organization.\n * @returns Array of tag definitions.\n * @throws {PromptsApiError} If the API call fails.\n */\n async listTags(): Promise<TagDefinition[]> {\n const { data, error } = await this.apiClient.GET(\"/api/prompts/tags\");\n if (error) this.handleApiError(\"list tags\", error);\n return data;\n }\n\n /**\n * Creates a custom prompt tag for the organization.\n * @param params.name The tag name (must match /^[a-z][a-z0-9_-]*$/).\n * @returns The created tag.\n * @throws {PromptsApiError} If the API call fails.\n */\n async createTag({ name }: { name: string }): Promise<CreatedTag> {\n const { data, error } = await this.apiClient.POST(\"/api/prompts/tags\", {\n body: { name },\n });\n if (error) this.handleApiError(\"create tag\", error);\n return data;\n }\n\n /**\n * Deletes a custom prompt tag by name.\n * @param tagName The tag name to delete.\n * @throws {PromptsApiError} If the API call fails.\n */\n async deleteTag(tagName: string): Promise<void> {\n const { error } = await this.apiClient.DELETE(\n \"/api/prompts/tags/{tag}\" as any,\n { params: { path: { tag: tagName } } } as any,\n );\n if (error) this.handleApiError(`delete tag \"${tagName}\"`, error);\n }\n\n /**\n * Renames an existing prompt tag.\n * @param tag The current tag name.\n * @param name The new tag name.\n * @throws {PromptsApiError} If the API call fails.\n */\n async renameTag({ tag, name }: { tag: string; name: string }): Promise<void> {\n const { error } = await this.apiClient.PUT(\n \"/api/prompts/tags/{tag}\",\n { params: { path: { tag } }, body: { name } },\n );\n if (error) this.handleApiError(`rename tag \"${tag}\"`, error);\n }\n\n async assignTag({\n id,\n tag,\n versionId,\n }: {\n id: string;\n tag: string;\n versionId: string;\n }): Promise<AssignTagResult> {\n const { data, error } = await this.apiClient.PUT(\n \"/api/prompts/{id}/tags/{tag}\",\n {\n params: { path: { id, tag } },\n body: { versionId },\n },\n );\n if (error) this.handleApiError(`assign tag \"${tag}\" to prompt \"${id}\"`, error);\n return data;\n }\n\n /**\n * Deletes a prompt by its ID.\n * @param id The prompt's unique identifier.\n * @throws {PromptsApiError} If the API call fails.\n */\n async delete(id: string): Promise<{ success: boolean }> {\n const { data, error } = await this.apiClient.DELETE(\n \"/api/prompts/{id}\",\n {\n params: { path: { id } },\n },\n );\n if (error) this.handleApiError(`delete prompt with ID \"${id}\"`, error);\n\n return data;\n }\n\n /**\n * Fetches all versions for a given prompt.\n * @param id The prompt's unique identifier.\n * @returns Array of raw PromptResponse data for each version.\n * @throws {PromptsApiError} If the API call fails.\n */\n async getVersions(id: string): Promise<PromptResponse[]> {\n const { data, error } = await this.apiClient.GET(\n \"/api/prompts/{id}/versions\",\n {\n params: { path: { id } },\n },\n );\n if (error)\n this.handleApiError(`fetch versions for prompt with ID \"${id}\"`, error);\n\n return data;\n }\n\n /**\n * Upserts a prompt with local configuration - creates if doesn't exist, updates version if exists.\n * @param handle The prompt's handle/identifier.\n * @param config Local prompt configuration.\n * @returns Object with created flag and raw PromptResponse data.\n * @throws {PromptsApiError} If the API call fails.\n */\n async upsert(\n handle: string,\n config: {\n model: string;\n modelParameters?: {\n temperature?: number;\n max_tokens?: number;\n };\n messages: Array<{\n role: \"system\" | \"user\" | \"assistant\";\n content: string;\n }>;\n parameters?: RuntimeParameters;\n },\n ): Promise<{ created: boolean; prompt: PromptResponse }> {\n const payload = {\n handle,\n model: config.model,\n prompt: PromptConverter.extractSystemPrompt(config.messages),\n messages: PromptConverter.filterNonSystemMessages(config.messages),\n temperature: config.modelParameters?.temperature,\n maxTokens: config.modelParameters?.max_tokens,\n inputs: [{ identifier: \"input\", type: \"str\" as const }],\n outputs: [{ identifier: \"output\", type: \"str\" as const }],\n parameters: config.parameters ?? {},\n commitMessage: `Updated via CLI sync`,\n schemaVersion: \"1.0\" as const,\n };\n\n // Creating a prompt with the same handle will fail, so we try to update instead\n try {\n const prompt = await this.create(payload);\n return {\n created: true,\n prompt,\n };\n } catch {\n const prompt = await this.update(handle, payload);\n\n return {\n created: false,\n prompt,\n };\n }\n }\n\n /**\n * Sync a prompt with local content, handling conflicts and version management\n * You probably don't need to use this method directly.\n */\n async sync(params: {\n name: string;\n configData: ConfigData;\n parameters?: RuntimeParameters;\n localVersion?: number;\n commitMessage?: string;\n }): Promise<SyncResult> {\n // openapi-fetch returns `{ data?, error?, response }`; we only need\n // these fields from the response so an explicit shape keeps the\n // no-redundant-type-constituents lint happy (the generic POST return is\n // widened to `any` by the generated types).\n interface SyncApiResponse {\n data?: unknown;\n error?: unknown;\n response?: { status?: number };\n }\n let response: SyncApiResponse | undefined;\n try {\n response = await this.apiClient.POST(\n \"/api/prompts/{id}/sync\",\n {\n params: { path: { id: params.name } },\n body: {\n configData: params.configData,\n parameters: params.parameters ?? {},\n localVersion: params.localVersion,\n commitMessage: params.commitMessage,\n },\n },\n );\n } catch (error) {\n // Transport-level failures (network errors, timeouts, unresolved DNS)\n // surface here. Preserve the underlying message so the user knows\n // whether the API is reachable.\n const message = formatApiErrorForOperation({ operation: \"sync prompt\", error: error });\n throw new PromptsApiError(message, \"sync\", error);\n }\n\n if (response?.error) {\n const err: unknown = response.error;\n const status =\n response.response?.status ?? extractStatusFromResponse(err);\n const message = formatApiErrorMessage({ error: err, options: { status } });\n throw new PromptsApiError(\n `Failed to sync prompt: ${message}`,\n \"sync\",\n err,\n );\n }\n\n // Validate the shape at the boundary so a malformed 2xx payload\n // (e.g. `{ action: undefined }`) surfaces as a PromptsApiError here\n // instead of crashing downstream code with a confusing stack trace.\n const parsed = syncResultSchema.safeParse(response?.data);\n if (!parsed.success) {\n throw new PromptsApiError(\n \"Failed to sync prompt: server returned an invalid response body\",\n \"sync\",\n response?.data ?? response,\n );\n }\n return {\n action: parsed.data.action,\n prompt: parsed.data.prompt as SyncResult[\"prompt\"],\n conflictInfo: parsed.data.conflictInfo as SyncResult[\"conflictInfo\"],\n };\n }\n}\n","/**\n * Bidirectional mapping between the platform's `outputs` array and the\n * local YAML `response_format` block.\n *\n * The platform is the single source of truth and stores structured output as\n * an `outputs` array. The local `.prompt.yaml` follows the GitHub Prompts\n * convention and carries a `response_format` block. Push and pull must be\n * exact inverses, so both directions live here and share one definition of\n * what \"flat structured fields\" vs. \"an opaque JSON schema\" means.\n *\n * Two shapes round-trip losslessly:\n *\n * - Flat platform fields (e.g. l1, l2, l3, reasoning) ⇆ a single-level\n * JSON-schema object whose properties are those fields. The platform keeps\n * showing them as individual fields after a pull → edit → push cycle.\n *\n * - A rich JSON schema (enums, nested objects, arrays, descriptions, …) ⇆ a\n * single `json_schema` output that preserves the schema verbatim.\n */\n\nexport type CliOutputType = \"str\" | \"float\" | \"bool\" | \"json_schema\";\n\nexport interface CliOutput {\n identifier: string;\n type: CliOutputType;\n json_schema?: Record<string, unknown>;\n}\n\nexport interface LocalResponseFormat {\n name?: string;\n schema: Record<string, unknown>;\n}\n\n/**\n * The CLI default output for an unstructured (plain text) prompt. A prompt\n * with exactly this single output has no structured response and therefore no\n * `response_format` block.\n */\nexport const DEFAULT_TEXT_OUTPUT: CliOutput = {\n identifier: \"output\",\n type: \"str\",\n};\n\nconst SCALAR_OUTPUT_TO_JSON_TYPE: Record<\n Exclude<CliOutputType, \"json_schema\">,\n string\n> = {\n str: \"string\",\n float: \"number\",\n bool: \"boolean\",\n};\n\nconst JSON_TYPE_TO_SCALAR_OUTPUT: Record<\n string,\n Exclude<CliOutputType, \"json_schema\">\n> = {\n string: \"str\",\n number: \"float\",\n integer: \"float\",\n boolean: \"bool\",\n};\n\nconst isPlainObject = (value: unknown): value is Record<string, unknown> =>\n typeof value === \"object\" && value !== null && !Array.isArray(value);\n\n/**\n * Accepts either the canonical local form `{ name?, schema }` or the\n * OpenAI-standard wrapper `{ type: \"json_schema\", json_schema: { name, schema } }`\n * and normalizes to `{ name?, schema }`. Returns undefined when there is no\n * usable schema.\n */\nexport const normalizeResponseFormat = (\n raw: unknown,\n): LocalResponseFormat | undefined => {\n if (!isPlainObject(raw)) return undefined;\n\n // OpenAI-standard wrapper\n if (raw.type === \"json_schema\" && isPlainObject(raw.json_schema)) {\n const inner = raw.json_schema;\n if (isPlainObject(inner.schema)) {\n return {\n name: typeof inner.name === \"string\" ? inner.name : undefined,\n schema: inner.schema,\n };\n }\n return undefined;\n }\n\n // Canonical local form\n if (isPlainObject(raw.schema)) {\n return {\n name: typeof raw.name === \"string\" ? raw.name : undefined,\n schema: raw.schema,\n };\n }\n\n return undefined;\n};\n\n/**\n * A \"simple flat object schema\" has only scalar properties (string / number /\n * integer / boolean), no extra JSON-schema keywords on the schema or on any\n * property, and (when present) `required` listing exactly the properties.\n * These map losslessly to flat platform fields. Anything richer (enums,\n * arrays, nested objects, descriptions, …) is opaque and must be preserved\n * verbatim as a json_schema output.\n */\nexport const asFlatFields = (\n schema: Record<string, unknown>,\n): { identifier: string; type: Exclude<CliOutputType, \"json_schema\"> }[] | null => {\n if (schema.type !== \"object\") return null;\n if (!isPlainObject(schema.properties)) return null;\n\n const allowedSchemaKeys = new Set([\n \"type\",\n \"properties\",\n \"required\",\n \"additionalProperties\",\n ]);\n if (Object.keys(schema).some((k) => !allowedSchemaKeys.has(k))) return null;\n\n if (\n schema.additionalProperties !== undefined &&\n schema.additionalProperties !== false\n ) {\n return null;\n }\n\n const properties = schema.properties;\n const propertyNames = Object.keys(properties);\n if (propertyNames.length === 0) return null;\n\n const fields: {\n identifier: string;\n type: Exclude<CliOutputType, \"json_schema\">;\n }[] = [];\n\n for (const name of propertyNames) {\n const prop = properties[name];\n if (!isPlainObject(prop)) return null;\n if (Object.keys(prop).some((k) => k !== \"type\")) return null;\n const jsonType = prop.type;\n if (typeof jsonType !== \"string\") return null;\n const scalar = JSON_TYPE_TO_SCALAR_OUTPUT[jsonType];\n if (!scalar) return null;\n fields.push({ identifier: name, type: scalar });\n }\n\n if (schema.required !== undefined) {\n if (!Array.isArray(schema.required)) return null;\n const required = [...(schema.required as unknown[])].sort();\n const names = [...propertyNames].sort();\n if (\n required.length !== names.length ||\n required.some((r, i) => r !== names[i])\n ) {\n return null;\n }\n }\n\n return fields;\n};\n\n/**\n * Pull direction: reconstruct the local `response_format` block from the\n * platform `outputs` array. Returns undefined for a plain-text prompt so we\n * never invent a schema that wasn't there.\n */\nexport const outputsToResponseFormat = (\n outputs: CliOutput[] | undefined | null,\n fallbackName?: string,\n): LocalResponseFormat | undefined => {\n if (!outputs || outputs.length === 0) return undefined;\n\n const jsonSchemaOutput = outputs.find(\n (o) => o.type === \"json_schema\" && o.json_schema,\n );\n if (jsonSchemaOutput?.json_schema) {\n return {\n name: jsonSchemaOutput.identifier,\n schema: jsonSchemaOutput.json_schema,\n };\n }\n\n // Exactly the CLI default single text output → unstructured, no schema.\n if (\n outputs.length === 1 &&\n outputs[0]!.identifier === DEFAULT_TEXT_OUTPUT.identifier &&\n outputs[0]!.type === DEFAULT_TEXT_OUTPUT.type\n ) {\n return undefined;\n }\n\n // Flat structured fields → a single-level JSON schema object.\n const properties: Record<string, { type: string }> = {};\n for (const output of outputs) {\n if (output.type === \"json_schema\") continue;\n properties[output.identifier] = {\n type: SCALAR_OUTPUT_TO_JSON_TYPE[output.type],\n };\n }\n if (Object.keys(properties).length === 0) return undefined;\n\n return {\n name: fallbackName ?? \"output\",\n schema: {\n type: \"object\",\n properties,\n required: Object.keys(properties),\n additionalProperties: false,\n },\n };\n};\n\n/**\n * Push direction: turn the local `response_format` block back into the\n * platform `outputs` array. The exact inverse of {@link outputsToResponseFormat}:\n * a flat object schema expands to flat fields (so the platform keeps showing\n * them individually), anything richer becomes one json_schema output.\n */\nexport const responseFormatToOutputs = (\n raw: unknown,\n): CliOutput[] | undefined => {\n const rf = normalizeResponseFormat(raw);\n if (!rf) return undefined;\n\n const flat = asFlatFields(rf.schema);\n if (flat) {\n return flat.map((f) => ({ identifier: f.identifier, type: f.type }));\n }\n\n return [\n {\n identifier: rf.name ?? \"output\",\n type: \"json_schema\",\n json_schema: rf.schema,\n },\n ];\n};\n","import type {\n LocalPromptConfig,\n MaterializedPrompt,\n RuntimeParameters,\n} from \"../types\";\nimport { type PromptResponse, type UpdatePromptBody } from \"@/client-sdk/services/prompts/types\";\nimport {\n type CliOutput,\n type LocalResponseFormat,\n outputsToResponseFormat,\n} from \"./responseFormat\";\n\n/**\n * Converter utility for transforming between YAML prompt format and API service format.\n *\n * The YAML format follows the GitHub .prompt.yaml file format standard,\n * while the API format is our internal prompt service schema tied to the database.\n *\n * This separation allows us to maintain and evolve both formats independently\n * while keeping the conversion logic centralized and well-tested.\n */\nexport class PromptConverter {\n /**\n * Converts a Prompt instance from the API service to the MaterializedPrompt format\n * used for saving to the .materialized directory.\n */\n static fromApiToMaterialized(prompt: PromptResponse): MaterializedPrompt {\n return {\n id: prompt.id,\n name: prompt.name,\n version: prompt.version,\n versionId: prompt.versionId,\n model: prompt.model,\n messages: prompt.messages,\n prompt: prompt.prompt,\n temperature: prompt.temperature,\n maxTokens: prompt.maxTokens,\n inputs: prompt.inputs,\n outputs: prompt.outputs,\n parameters: prompt.parameters ?? {},\n updatedAt: prompt.updatedAt,\n };\n }\n\n /**\n * Converts a MaterializedPrompt to the YAML content structure\n * for saving to .prompt.yaml files.\n */\n static fromMaterializedToYaml(prompt: MaterializedPrompt): {\n model: string;\n modelParameters?: {\n temperature?: number;\n maxTokens?: number;\n };\n messages: Array<{\n role: \"system\" | \"user\" | \"assistant\";\n content: string;\n }>;\n response_format?: LocalResponseFormat;\n parameters?: RuntimeParameters;\n } {\n const result: any = {\n model: prompt.model,\n messages: prompt.messages,\n };\n\n if (Object.keys(prompt.parameters ?? {}).length > 0) {\n result.parameters = prompt.parameters;\n }\n\n // Add modelParameters if temperature or maxTokens exist. The server is the\n // source of truth for which sampling parameters a model accepts and omits\n // the ones it would reject (e.g. temperature on the gpt-5 family), so we\n // simply mirror what the API returned — never inject a default here.\n if (prompt.temperature !== undefined || prompt.maxTokens !== undefined) {\n result.modelParameters = {};\n if (prompt.temperature !== undefined) {\n result.modelParameters.temperature = prompt.temperature;\n }\n if (prompt.maxTokens !== undefined) {\n result.modelParameters.maxTokens = prompt.maxTokens;\n }\n }\n\n // Reconstruct the structured-output block from the platform outputs so a\n // pull never drops a response_format the user configured. Inverse of the\n // push direction in pushPrompts.\n const responseFormat = outputsToResponseFormat(\n prompt.outputs as CliOutput[] | undefined,\n prompt.name,\n );\n if (responseFormat) {\n result.response_format = responseFormat;\n }\n\n return result;\n }\n\n /**\n * Converts a LocalPromptConfig (loaded from YAML) to the format\n * expected by the API service for upserting.\n */\n static fromLocalToApiFormat(\n config: LocalPromptConfig,\n ): Omit<UpdatePromptBody, \"commitMessage\"> & { parameters?: RuntimeParameters }\n {\n return {\n model: config.model,\n temperature: config.modelParameters?.temperature,\n maxTokens: config.modelParameters?.max_tokens,\n messages: config.messages,\n parameters: config.parameters ?? {},\n };\n }\n\n /**\n * Extracts the system prompt from messages array.\n * Used when converting to API format that separates system prompt from messages.\n */\n static extractSystemPrompt(\n messages: Array<{ role: string; content: string }>,\n ): string {\n return messages.find((m) => m.role === \"system\")?.content ?? \"\";\n }\n\n /**\n * Filters out system messages from the messages array.\n * Used when converting to API format that handles system prompt separately.\n */\n static filterNonSystemMessages(\n messages: Array<{\n role: \"system\" | \"user\" | \"assistant\";\n content: string;\n }>,\n ): Array<{ role: \"user\" | \"assistant\"; content: string }> {\n return messages.filter((m) => m.role !== \"system\") as Array<{\n role: \"user\" | \"assistant\";\n content: string;\n }>;\n }\n}\n","import { type Prompt, type TemplateVariables, type CompiledPrompt } from \"../prompt\";\nimport { shouldCaptureInput, shouldCaptureOutput } from \"@/observability-sdk\";\nimport type { LangWatchSpan } from \"@/observability-sdk\";\n\n/**\n * Class that decorates the target prompt,\n * adding tracing to specific methods.\n */\nexport class PromptTracingDecorator {\n constructor(private readonly target: Prompt) {}\n\n private traceCompilation(\n span: LangWatchSpan,\n variables: TemplateVariables,\n compileFn: () => CompiledPrompt\n ): CompiledPrompt {\n span.setType(\"prompt\");\n\n if (shouldCaptureInput()) {\n span.setInput(this.target);\n\n if (variables) {\n span.setAttribute(\n 'langwatch.prompt.variables',\n JSON.stringify({\n type: \"json\",\n value: variables,\n }),\n );\n }\n }\n\n const result = compileFn();\n\n // Only emit combined handle:version format when both are available\n if (result.handle != null && result.version != null) {\n span.setAttribute(\n 'langwatch.prompt.id',\n `${result.handle}:${result.version}`,\n );\n }\n\n if (shouldCaptureOutput()) {\n span.setOutput({\n ...result,\n raw: void 0, // TODO(afr): Figure out a better way to do this.\n });\n }\n\n return result;\n }\n\n compile(span: LangWatchSpan, variables: TemplateVariables = {}): CompiledPrompt {\n return this.traceCompilation(\n span,\n variables,\n () => this.target.compile(variables),\n );\n }\n\n compileStrict(span: LangWatchSpan, variables: TemplateVariables): CompiledPrompt {\n return this.traceCompilation(\n span,\n variables,\n () => this.target.compileStrict(variables),\n );\n }\n}\n","import { type PromptsApiService } from \"../prompts-api.service\";\nimport type { LangWatchSpan } from \"@/observability-sdk\";\nimport { shouldCaptureInput, shouldCaptureOutput } from \"@/observability-sdk\";\nimport type { CreatePromptBody, UpdatePromptBody, PromptResponse } from \"../types\";\n\n/**\n * Class that decorates the target prompt service,\n * adding tracing to key methods.\n */\nexport class PromptServiceTracingDecorator {\n constructor(private readonly target: PromptsApiService) {}\n\n async get(\n span: LangWatchSpan,\n id: string,\n options?: { version?: string }\n ): Promise<PromptResponse> {\n span.setType(\"prompt\");\n\n const result = await this.target.get(id, options);\n\n if (result) {\n // Only emit combined format when both handle and version are available\n if (result.handle != null && result.version != null) {\n span.setAttribute(\n 'langwatch.prompt.id',\n `${result.handle}:${result.version}`,\n );\n }\n }\n\n if (result && shouldCaptureOutput()) {\n span.setOutput(\"json\", result);\n }\n\n return result;\n }\n\n async create(\n span: LangWatchSpan,\n params: CreatePromptBody\n ): Promise<PromptResponse> {\n span.setType(\"prompt\");\n\n if (shouldCaptureInput()) {\n span.setInput(params);\n }\n\n const result = await this.target.create(params);\n\n span.setAttributes({\n 'langwatch.prompt.id': result.id,\n 'langwatch.prompt.handle': result.handle ?? undefined,\n 'langwatch.prompt.scope': result.scope,\n 'langwatch.prompt.version.id': result.versionId,\n 'langwatch.prompt.version.number': result.version,\n });\n\n return result;\n }\n\n async update(\n span: LangWatchSpan,\n id: string,\n params: UpdatePromptBody\n ): Promise<PromptResponse> {\n\n if (shouldCaptureInput()) {\n span.setInput(params);\n }\n\n const result = await this.target.update(id, params);\n\n span.setType(\"prompt\");\n span.setAttributes({\n 'langwatch.prompt.id': id,\n 'langwatch.prompt.handle': result.handle ?? undefined,\n 'langwatch.prompt.scope': result.scope,\n 'langwatch.prompt.version.id': result.versionId,\n 'langwatch.prompt.version.number': result.version,\n });\n\n return result;\n }\n\n async delete(\n span: LangWatchSpan,\n id: string\n ): Promise<{ success: boolean }> {\n const result = await this.target.delete(id);\n\n span.setType(\"prompt\");\n span.setAttribute('langwatch.prompt.id', id);\n span.setAttribute('langwatch.prompt.deleted', 'true');\n\n return result;\n }\n\n async upsert(\n span: LangWatchSpan,\n handle: string,\n config: any\n ): Promise<{ created: boolean; prompt: PromptResponse }> {\n if (shouldCaptureInput()) {\n span.setInput(config);\n }\n\n const result = await this.target.upsert(handle, config);\n\n span.setType(\"prompt\");\n span.setAttributes({\n 'langwatch.prompt.handle': handle,\n 'langwatch.prompt.created': result.created.toString(),\n 'langwatch.prompt.id': result.prompt.id,\n 'langwatch.prompt.version.id': result.prompt.versionId,\n 'langwatch.prompt.version.number': result.prompt.version,\n });\n\n return result;\n }\n\n async sync(\n span: LangWatchSpan,\n params: any\n ): Promise<any> {\n if (shouldCaptureInput()) {\n span.setInput(params);\n }\n\n const result = await this.target.sync(params);\n\n span.setType(\"prompt\");\n span.setAttribute('langwatch.prompt.name', params.name);\n span.setAttribute('langwatch.prompt.sync.action', result.action);\n\n if (result.conflictInfo) {\n span.setAttributes({\n 'langwatch.prompt.sync.has_conflict': 'true',\n 'langwatch.prompt.sync.local_version': result.conflictInfo.localVersion.toString(),\n 'langwatch.prompt.sync.remote_version': result.conflictInfo.remoteVersion.toString(),\n });\n }\n\n return result;\n }\n}\n","import { getLangWatchTracer } from \"@/observability-sdk/tracer\";\nimport { LANGWATCH_SDK_NAME_CLIENT, LANGWATCH_SDK_VERSION } from \"@/internal/constants\";\n\nexport const tracer = getLangWatchTracer(`${LANGWATCH_SDK_NAME_CLIENT}.prompts`, LANGWATCH_SDK_VERSION);\n","import { type LangWatchTracer } from \"@/observability-sdk\";\nimport { SpanKind } from \"@opentelemetry/api\";\n\n// Type for decorator methods that receive span as first parameter\ntype DecoratorMethodWithSpan<T extends (...args: any[]) => any> =\n (span: any, ...args: Parameters<T>) => ReturnType<T>;\n\n// Type for decorator class that maps original methods to span-aware versions\n// Only requires methods that are actually implemented in the decorator\ntype DecoratorClass<T> = new (target: T) => Partial<{\n [K in keyof T]: T[K] extends (...args: any[]) => any\n ? DecoratorMethodWithSpan<T[K]>\n : T[K];\n }>;\n\n/**\n * Creates a proxy that always creates spans for public methods.\n * Decorators can access the span as the first parameter to add additional attributes.\n *\n * @param target - The target to wrap\n * @param tracer - The tracer instance to use\n * @param DecoratorClass - Optional decorator class for custom logic\n * @returns A proxy that wraps the target with consistent tracing\n */\nexport function createTracingProxy<\n T extends object,\n D extends DecoratorClass<T> | undefined = undefined\n>(\n target: T,\n tracer: LangWatchTracer,\n DecoratorClass?: D,\n): T {\n const decorator = DecoratorClass ? new DecoratorClass(target) : null;\n\n return new Proxy(target, {\n get(target, prop, receiver) {\n const value = Reflect.get(target, prop, receiver);\n\n // If it's not a function, return as-is\n if (typeof value !== \"function\") {\n return value;\n }\n\n // Only trace public methods\n if (\n typeof prop === \"string\" &&\n !prop.startsWith(\"_\") && // Skip private methods\n !isGetterOrSetter(target, prop) && // Skip actual getters/setters\n !isBuiltInMethod(prop) // Skip built-in methods\n ) {\n return (...args: any[]) => {\n const spanName = `${target.constructor.name}.${prop}`;\n\n return tracer.withActiveSpan(spanName, {\n kind: SpanKind.CLIENT,\n attributes: {\n 'code.function': prop,\n 'code.namespace': target.constructor.name,\n },\n }, (span) => {\n // If decorator has this method, call it with span as first parameter\n if (decorator && prop in decorator) {\n const decoratorMethod = decorator[prop as keyof typeof decorator];\n if (typeof decoratorMethod === \"function\") {\n return decoratorMethod.apply(decorator, [span, ...args]);\n }\n }\n\n // Default: just call the original method\n return value.apply(target, args);\n });\n };\n }\n\n return typeof value === \"function\" ? value.bind(target) : value;\n },\n });\n}\n\n// Helper function to check if a property is a getter or setter\nconst isGetterOrSetter = (target: any, prop: string | symbol): boolean => {\n // First check own properties\n let descriptor = Object.getOwnPropertyDescriptor(target, prop);\n\n // If not found on own properties, check prototype chain\n if (!descriptor) {\n const prototype = Object.getPrototypeOf(target);\n if (prototype) {\n descriptor = Object.getOwnPropertyDescriptor(prototype, prop);\n }\n }\n\n // Return true if it's a getter or setter\n return !!(descriptor?.get ?? descriptor?.set);\n};\n\n// Helper function to check if a method is a built-in method that should not be traced\nconst isBuiltInMethod = (prop: string | symbol): boolean => {\n if (typeof prop !== \"string\") {\n return false;\n }\n\n // List of built-in methods that should not be traced\n const builtInMethods = [\n 'toString',\n 'valueOf',\n 'toJSON',\n 'toLocaleString',\n 'hasOwnProperty',\n 'isPrototypeOf',\n 'propertyIsEnumerable',\n 'constructor'\n ];\n\n return builtInMethods.includes(prop);\n};\n","import openApiCreateClient, { type Middleware } from \"openapi-fetch\";\nimport type { paths } from \"../generated/openapi/api-client\";\nimport { version } from \"../../../package.json\";\nimport {\n LANGWATCH_SDK_LANGUAGE,\n LANGWATCH_SDK_NAME_OBSERVABILITY,\n LANGWATCH_SDK_RUNTIME,\n LANGWATCH_SDK_VERSION,\n} from \"../constants\";\nimport { DEFAULT_ENDPOINT } from \"@/internal/constants\";\nimport { buildAuthHeaders } from \"./auth\";\nimport { handledErrorFrom } from \"./errors\";\n\n/**\n * Turns a NAMED failure into a typed throw, once, for every call that goes\n * through this client.\n *\n * This lives in the transport rather than in each service because it is a\n * property of the WIRE, not of any one resource: the platform answers a declined\n * request with a `HandledError` — a `kind`, a status, a `meta` bag — and that is\n * true of `/api/traces` and `/api/prompts` alike. Reading it here means no\n * service has to remember to, and a service added tomorrow gets it for free.\n *\n * WHAT IT DOES NOT DO is just as load-bearing: a response whose body is not a\n * domain error — a 5xx, a proxy's HTML error page, a truncated body, anything at\n * all it cannot read — is left completely alone. `onResponse` returns nothing,\n * openapi-fetch carries on and hands the service the `{ error }` it always did,\n * and the service throws the same generic error it always threw. This is a\n * strict superset of the old behaviour: it only ever ADDS a type where there was\n * a string.\n */\nconst handledErrorMiddleware: Middleware = {\n async onResponse({ request, response }) {\n if (response.ok) return;\n\n // openapi-fetch reads the body itself further down the pipeline, and a body\n // can only be read once. Clone, or the non-domain path gets an empty error.\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (!contentType.includes(\"json\")) return;\n\n let body: unknown;\n try {\n body = await response.clone().json();\n } catch {\n // A body that claims JSON and isn't is exactly the case this must not\n // crash on. Leave it to the generic path.\n return;\n }\n\n const handledError = handledErrorFrom({\n body,\n status: response.status,\n // The platform's own sentence is the message; there is no operation to\n // prefix it with down here, and the CLI adds \"Failed to <action>\" itself.\n operation: `${request.method} ${new URL(request.url).pathname}`,\n message: undefined,\n });\n\n if (handledError) throw handledError;\n },\n};\n\n\n/**\n * Creates a new LangWatch API client.\n * @param apiKey - The API key or Personal Access Token used for authentication.\n * Defaults to `LANGWATCH_API_KEY`.\n * @param endpoint - The endpoint to use for the API client. Defaults to `LANGWATCH_ENDPOINT`\n * or the internal `DEFAULT_ENDPOINT`.\n * @param projectId - Project identifier. Required when `apiKey` is a PAT\n * (`pat-lw-*`). Defaults to `LANGWATCH_PROJECT_ID`.\n * @returns A new LangWatch API client.\n */\nexport const createLangWatchApiClient = (\n apiKey: string = process.env.LANGWATCH_API_KEY ?? \"\",\n endpoint: string = process.env.LANGWATCH_ENDPOINT ?? DEFAULT_ENDPOINT,\n projectId: string | undefined = process.env.LANGWATCH_PROJECT_ID,\n) => {\n const client = openApiCreateClient<paths>({\n baseUrl: endpoint,\n headers: {\n ...buildAuthHeaders({ apiKey, projectId }),\n \"content-type\": \"application/json\",\n \"user-agent\": `langwatch-sdk-node/${version}`,\n \"x-langwatch-sdk-name\": LANGWATCH_SDK_NAME_OBSERVABILITY,\n \"x-langwatch-sdk-language\": LANGWATCH_SDK_LANGUAGE,\n \"x-langwatch-sdk-version\": LANGWATCH_SDK_VERSION,\n \"x-langwatch-sdk-platform\": LANGWATCH_SDK_RUNTIME(),\n },\n });\n\n client.use(handledErrorMiddleware);\n\n return client;\n};\n\n\nexport type LangwatchApiClient = ReturnType<typeof createLangWatchApiClient>;\n","/**\n * The failure contract between the platform, the CLI and the Langy panel.\n *\n * The API already speaks a precise language of failure: server-side, a\n * `HandledError` carries a `code` (\"dataset_not_found\", \"validation_error\"), an\n * HTTP status and a `meta` bag, and `handleError` flattens it onto the wire as:\n *\n * HTTP <httpStatus> { \"error\": <code>, \"message\": <message>, ...meta }\n *\n * By the time that reaches the CLI it has usually been mashed back down into a\n * single English string, and the panel can only print it. That is a real loss: a\n * 404 \"dataset not found\" is a fact the UI can act on (offer to list what does\n * exist); a 500 is not. So the CLI reads the wire shape back into the structured\n * error it always was and puts THAT on the event — code and status as their own\n * attributes — rather than flattening a structured failure into prose twice.\n *\n * The split that matters is domain vs infrastructure:\n * - a domain error is the platform saying \"no, and here is precisely why\" — the\n * user's problem, actionable, safe to show, worth a card;\n * - anything else (a dead socket, a 500, a proxy's HTML error page) is OUR\n * problem, and the panel must say so rather than blame the user.\n *\n * DELIBERATELY ZOD-FREE, and importable on its own (`@langwatch/langy/cards/handled-error`).\n * This module sits on the CLI's hot path: every instrumented command imports it,\n * including the overwhelming majority of runs where telemetry is switched off.\n * Importing zod here costs ~28ms on EVERY `langwatch` invocation — measured — and\n * a shape check this small does not need a schema engine to do it. The card\n * schemas, which are zod and which nothing on the hot path imports, live next\n * door.\n */\n\n/**\n * One link in the platform's `reasons` chain — the failure BEHIND the failure.\n * Recursive, and named by kind only: the platform masks anything it did not\n * raise itself as `{ code: \"unknown\" }` rather than leaking an internal message.\n */\nexport interface CliHandledErrorReason {\n kind: string;\n meta?: Record<string, unknown>;\n reasons?: CliHandledErrorReason[];\n}\n\n/** A failure, read back into the structure the platform originally gave it. */\nexport interface CliHandledError {\n /** The platform's serialisable discriminant, e.g. `dataset_not_found`. */\n code: string;\n /**\n * @deprecated Back-compat alias of `code`, emitted while the platform's\n * `DomainError` → `HandledError` rename rolls out (the serialised error\n * carries the same pair — see `SerializedHandledError.kind`). Read `code` in\n * new code; this alias is removed once no consumer reads `kind`.\n */\n kind: string;\n /** The human sentence. Safe to show: the platform wrote it for a user. */\n message: string;\n /** The status the platform answered with; 0 when the request never landed. */\n httpStatus: number;\n /** Whatever context the platform attached to the failure (ids, field errors). */\n meta: Record<string, unknown>;\n /**\n * True when the platform answered with a structured domain failure — i.e. it\n * understood the request and declined it. False for infrastructure failures,\n * where the CLI is guessing and the panel must not present it as the user's\n * fault.\n */\n isHandled: boolean;\n /**\n * The OTel trace the failure happened on, when the route sent it.\n *\n * Read when offered and simply absent otherwise — never fabricated. It now\n * survives all three REST dialects: the shared Hono handler nests it under\n * `trace: { traceId, … }`, and the routes that forward `serialize()` (or the\n * new framework envelope) carry it top-level.\n */\n traceId?: string;\n /** A clickable link to that trace, when the route sent one. */\n traceUrl?: string;\n /** A clickable link to the logs for that trace, when the route sent one. */\n logsUrl?: string;\n /** The reason chain, when the route sent it. Same availability as `traceId`. */\n reasons?: CliHandledErrorReason[];\n /**\n * What the user can DO about it — the platform's own next steps.\n *\n * The platform spells this `tips` (`HandledError.tips`, authored centrally in\n * `server/app-layer/error-remediation.ts` and keyed by code, with its docs\n * paths verified by CI). It is read here under both names: `tips` is what the\n * wire actually carries, `suggestions` is kept because the CLI's own error\n * document has always written that name and older documents must keep\n * parsing.\n *\n * This is the remediation channel ADR-045 added for exactly this consumer —\n * `specs/features/domain-error-contract.feature` requires that \"consumers\n * without a client-side explainer (CLI, API, MCP) can self-diagnose\". When\n * the server sends these they WIN over the CLI's own code-keyed fallback,\n * which only knows a handful of generic codes and cannot know, say, that\n * traces are deleted after the retention window.\n */\n suggestions?: string[];\n /** The docs page that explains the failure (`docsUrl` on the wire). */\n docUrl?: string;\n}\n\n/** Anything at or above this is the platform failing, not the caller. */\nconst SERVER_ERROR_STATUS = 500;\n\n/**\n * Codes the platform uses when it has NOT actually named a domain failure — the\n * generic 500 lane of `handleError`. They matter because the status is not always\n * recoverable: some of the SDK's service wrappers surface the error body without\n * the `Response` it came on. When that happens the code is the only thing left to\n * judge by, and these are the codes that mean \"we fell over\", not \"you asked for\n * something that cannot be done\".\n */\nconst GENERIC_CODES = new Set([\n \"internal server error\",\n \"internal_error\",\n \"unknown\",\n \"unknown error\",\n]);\n\nconst isGenericCode = (code: string): boolean =>\n GENERIC_CODES.has(code.trim().toLowerCase());\n\nconst asRecord = (value: unknown): Record<string, unknown> | null =>\n value && typeof value === \"object\" && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : null;\n\n/** The reason chain, defensively: anything without a code is not a reason. */\nconst asReasons = (value: unknown): CliHandledErrorReason[] | undefined => {\n if (!Array.isArray(value)) return undefined;\n\n const reasons = value\n .map(asRecord)\n .filter(\n (r): r is Record<string, unknown> =>\n !!r && (typeof r.code === \"string\" || typeof r.kind === \"string\"),\n )\n .map((r) => ({\n kind: (typeof r.code === \"string\" ? r.code : r.kind) as string,\n ...(asRecord(r.meta) ? { meta: asRecord(r.meta)! } : {}),\n ...(asReasons(r.reasons) ? { reasons: asReasons(r.reasons) } : {}),\n }));\n\n return reasons.length > 0 ? reasons : undefined;\n};\n\n/**\n * A libuv/Node system error, not a platform error body.\n *\n * `fetch` reports a transport failure by throwing a `TypeError(\"fetch failed\")`\n * whose `cause` is the system error, and `handledErrorFromThrown` unwraps to that\n * cause. Its own enumerable keys are `{ errno, code, syscall, address, port }` —\n * so its `code` is `ECONNREFUSED`/`ENOTFOUND`/`ETIMEDOUT`/a TLS cert code, NOT a\n * discriminant the platform ever chose. Reading one as a domain error is the\n * worst kind of wrong: it blames the user for the network being down, and it\n * lifts the local `address`/`port` into `meta` as though they were domain\n * context. `errno`/`syscall` are the tell, and no platform envelope carries\n * them, so their presence disqualifies the record outright — a transport\n * failure is infrastructure, always.\n */\nconst isSystemError = (record: Record<string, unknown>): boolean =>\n \"errno\" in record || \"syscall\" in record;\n\n/**\n * Does this record look like the platform's envelope at all?\n *\n * Only asked of a BARE top-level `code` — the one field a system error shares\n * with dialect 3. The platform never sends a lone `code`: its envelope always\n * carries the sentence, the meta bag, or the deprecated `kind` alongside it. So\n * a `code` with none of them is not the platform speaking, and is not trusted to\n * name a domain failure.\n */\nconst looksLikeErrorEnvelope = (record: Record<string, unknown>): boolean =>\n \"message\" in record || \"meta\" in record || \"kind\" in record;\n\n/** Next steps, defensively: only real strings survive. */\nconst asSuggestions = (value: unknown): string[] | undefined => {\n if (!Array.isArray(value)) return undefined;\n const suggestions = value.filter(\n (s): s is string => typeof s === \"string\" && s.trim().length > 0,\n );\n return suggestions.length > 0 ? suggestions : undefined;\n};\n\ninterface ErrorBody {\n code: string;\n message?: string;\n meta: Record<string, unknown>;\n traceId?: string;\n traceUrl?: string;\n logsUrl?: string;\n reasons?: CliHandledErrorReason[];\n suggestions?: string[];\n docUrl?: string;\n}\n\n/**\n * Read the platform's error body. The REST surface speaks this in THREE\n * dialects, and all are real — verified against the routes, not assumed:\n *\n * 1. THE COMMON ONE, from the shared Hono error handler every `SecuredApp`\n * mounts (`app/api/middleware/error-handler.ts`): the HandledError is\n * FLATTENED to `{ error: <code>, message: <sentence>, ...meta }` — meta\n * spread across the top level, and `reasons`/`traceUrl` dropped entirely.\n * So `error` is the CODE here, not the sentence. The trace ids survive,\n * but nested: `trace: { traceId, spanId, traceUrl?, logsUrl? }`.\n *\n * 2. THE VERBATIM ONE, from routes that forward `HandledError.serialize()`\n * whole (e.g. `routes/scenario-generate.ts`):\n * `{ error: <sentence>, domainError: { code, kind, meta, traceId, reasons } }`.\n *\n * 3. THE FRAMEWORK ONE, from the new API framework\n * (`langwatch/packages/api/src/errors.ts`): the envelope top-level —\n * `{ code, type, kind, message, meta, reasons, traceId, spanId, traceUrl }`,\n * with `error` carrying the HTTP status text on unversioned routes. `meta`\n * is a NESTED object here rather than spread, and `message` is usually the\n * code rather than a sentence: a handled error's own message is server copy\n * and never crosses the boundary (ADR-045). Prose, when the server\n * deliberately authored some, arrives as `meta.message` and wins.\n *\n * `code` is the name TypeScript uses, `type` the OpenAI-compatible name Go\n * emits; the framework sets all three to the same value (`errors.ts` assigns\n * `body.kind = body.code` and `body.type = body.code`), so which one answers\n * first only decides anything when a writer sent just one of them.\n *\n * A route that names the code explicitly under the deprecated `kind` only (an\n * older server, mid-rename) is read correctly too: `code ?? kind` always wins,\n * which means `error` is free to be the sentence.\n */\nconst asErrorBody = (value: unknown): ErrorBody | null => {\n const record = asRecord(value);\n if (!record) return null;\n\n // A libuv system error is a transport failure wearing a `code`. It is never\n // any of the three dialects, whatever else it carries, so it never gets to\n // name a domain failure — it falls through to the status-derived reading,\n // which calls it `network_error` and means it.\n if (isSystemError(record)) return null;\n\n // Dialect 2: the serialised HandledError, carried whole under `domainError`.\n const serialized = asRecord(record.domainError);\n if (\n serialized &&\n (typeof serialized.code === \"string\" || typeof serialized.kind === \"string\")\n ) {\n const telemetry = asRecord(serialized.telemetry);\n return {\n code:\n typeof serialized.code === \"string\"\n ? serialized.code\n : (serialized.kind as string),\n message:\n typeof record.error === \"string\"\n ? record.error\n : typeof record.message === \"string\"\n ? record.message\n : undefined,\n meta: asRecord(serialized.meta) ?? {},\n traceId:\n typeof serialized.traceId === \"string\"\n ? serialized.traceId\n : typeof telemetry?.traceId === \"string\"\n ? telemetry.traceId\n : undefined,\n traceUrl:\n typeof serialized.traceUrl === \"string\" ? serialized.traceUrl : undefined,\n logsUrl:\n typeof serialized.logsUrl === \"string\" ? serialized.logsUrl : undefined,\n reasons: asReasons(serialized.reasons),\n suggestions:\n asSuggestions(serialized.tips) ?? asSuggestions(serialized.suggestions),\n docUrl:\n typeof serialized.docsUrl === \"string\"\n ? serialized.docsUrl\n : typeof serialized.docUrl === \"string\"\n ? serialized.docUrl\n : undefined,\n };\n }\n\n // Dialects 1 and 3 (and the deprecated `kind`-only variant). One of them must\n // name the failure; without any, this is not the platform's shape at all.\n //\n // The ordering guards a hijack: dialect 1 spreads meta FLAT, so a meta bag\n // holding a literal `code` (or `type`) key would shadow the real discriminant\n // on `error` if it were read first. Dialect 3 always emits `kind` alongside\n // `code`, so a `kind` present means the envelope named itself and wins; with\n // no `kind`, `error` is the dialect-1 discriminant and a bare `code`/`type` is\n // only trusted when nothing else named the failure — and only then if the\n // record looks like the platform's envelope at all, so a stray `code`/`type`\n // on some other object cannot pass itself off as a discriminant the platform\n // chose.\n //\n // `type` sits at the same trust tier as `code` throughout: it is the same\n // value under the OpenAI-compatible name Go writes, so a writer that sent only\n // `type` must still resolve to the same failure — and must clear the same\n // envelope check, since `type` is a far more common field on ordinary objects\n // than `code` is.\n const named =\n typeof record.kind === \"string\"\n ? typeof record.code === \"string\"\n ? record.code\n : typeof record.type === \"string\"\n ? record.type\n : record.kind\n : typeof record.error === \"string\"\n ? record.error\n : looksLikeErrorEnvelope(record)\n ? typeof record.code === \"string\"\n ? record.code\n : typeof record.type === \"string\"\n ? record.type\n : null\n : null;\n if (named === null) return null;\n\n // Everything the platform did NOT put in meta gets lifted out, so the flat\n // spread does not smuggle the envelope's own fields back in as domain context.\n // `code`/`type` are discriminants, not context — they belong here too.\n const {\n error,\n message,\n kind,\n code,\n type,\n meta: explicitMeta,\n telemetry,\n trace,\n reasons,\n traceId,\n spanId,\n traceUrl,\n logsUrl,\n suggestions,\n docUrl,\n // The platform's own spelling of the two above. Lifted out for the same\n // reason as the rest: dialect 1 spreads meta flat, so leaving them in would\n // report the remediation copy back as domain context.\n tips,\n docsUrl,\n // `fault` is the envelope's own (\"customer\" vs \"platform\"), not something\n // the platform attached to this failure.\n fault,\n ...rest\n } = record;\n\n const nestedMeta = asRecord(explicitMeta);\n\n // The sentence, in order of how much the server meant it. Dialect 3's own\n // `message` is usually just the code echoed back — server copy never crosses\n // the boundary (ADR-045) — so prose the server deliberately authored under\n // `meta.message` wins outright. Failing that, `message` then `error` are the\n // sentence, but only when they are not simply repeating the discriminant:\n // a value equal to `named` carries no information a caller does not already\n // have, and passing it through would print the code where prose belongs.\n const authored = nestedMeta?.message;\n const sentence =\n typeof authored === \"string\" && authored.length > 0\n ? authored\n : typeof message === \"string\" && message !== named\n ? message\n : typeof error === \"string\" && error !== named\n ? error\n : undefined;\n\n const telemetryRecord = asRecord(telemetry);\n const traceRecord = asRecord(trace);\n\n return {\n code: named,\n message: sentence,\n // Dialect 3 carries meta as its own key; dialect 1 spreads it flat.\n meta: nestedMeta ?? rest,\n traceId:\n typeof traceRecord?.traceId === \"string\"\n ? traceRecord.traceId\n : typeof telemetryRecord?.traceId === \"string\"\n ? telemetryRecord.traceId\n : typeof traceId === \"string\"\n ? traceId\n : undefined,\n traceUrl:\n typeof traceUrl === \"string\"\n ? traceUrl\n : typeof traceRecord?.traceUrl === \"string\"\n ? traceRecord.traceUrl\n : undefined,\n logsUrl:\n typeof logsUrl === \"string\"\n ? logsUrl\n : typeof traceRecord?.logsUrl === \"string\"\n ? traceRecord.logsUrl\n : undefined,\n reasons: asReasons(reasons),\n suggestions: asSuggestions(tips) ?? asSuggestions(suggestions),\n docUrl:\n typeof docsUrl === \"string\"\n ? docsUrl\n : typeof docUrl === \"string\"\n ? docUrl\n : undefined,\n };\n};\n\n/**\n * Statuses where nothing the caller can SEND will change the answer.\n *\n * A machine caller — Langy runs the CLI in a shell — has exactly three moves\n * after a failure: retry unchanged, retry with different arguments, or stop.\n * Everything above tells it what the failure IS; this tells it which move is\n * left, and for these statuses the answer is \"stop\". Not because the request was\n * malformed (a 400/422 names the field to fix) and not because we fell over (a\n * 429/5xx is worth one retry), but because the platform understood the request\n * perfectly and the answer is no: the credential does not carry it (401/403),\n * the plan does not include it (402/403), it does not exist (404), it is gone\n * (410).\n *\n * Emitting this is the difference between an agent reporting a plan limit and an\n * agent quietly re-running a create with different flags until something sticks\n * — which is exactly what happened, and produced a second card for a thing that\n * never existed.\n */\nconst TERMINAL_STATUSES = new Set([401, 402, 403, 404, 410]);\n\n/**\n * True when retrying is pointless — see {@link TERMINAL_STATUSES}.\n *\n * Only ever said of a failure the platform NAMED. An infrastructure failure is\n * ours and transient by default, and a status we read off a proxy's error page\n * is not a verdict the platform reached.\n */\nexport const isTerminalFailure = (error: CliHandledError): boolean =>\n error.isHandled && TERMINAL_STATUSES.has(error.httpStatus);\n\n/** A stable code for a failure the platform did not name itself. */\nconst codeForStatus = (status: number): string => {\n if (status === 401 || status === 403) return \"unauthorized\";\n if (status === 404) return \"not_found\";\n if (status === 429) return \"rate_limited\";\n if (status >= SERVER_ERROR_STATUS) return \"internal_error\";\n if (status > 0) return \"request_failed\";\n return \"network_error\";\n};\n\nconst fallbackMessage = ({\n status,\n body,\n}: {\n status: number;\n body: unknown;\n}): string => {\n if (typeof body === \"string\" && body.trim()) return body.trim().slice(0, 300);\n return status > 0 ? `Request failed with status ${status}` : \"Request failed\";\n};\n\n/**\n * Read an HTTP failure back into a {@link CliHandledError}.\n *\n * A body in the platform's error shape that came back BELOW 500 is a true domain\n * error and keeps its code. A 5xx, or a body that is not the platform's shape at\n * all (a gateway's HTML, a truncated response), is infrastructure: it still\n * yields a usable error, but `isHandled` is false and the code degrades to a\n * status-derived one rather than a fabricated domain code.\n */\nexport const parseHandledError = ({\n status,\n body,\n}: {\n status: number;\n body: unknown;\n}): CliHandledError => {\n const parsed = asErrorBody(body);\n\n if (!parsed) {\n return {\n code: codeForStatus(status),\n kind: codeForStatus(status),\n message: fallbackMessage({ status, body }),\n httpStatus: status,\n meta: {},\n isHandled: false,\n };\n }\n\n return {\n code: parsed.code,\n // Deprecated back-compat alias — see CliHandledError.kind.\n kind: parsed.code,\n message: parsed.message ?? parsed.code,\n httpStatus: status,\n meta: parsed.meta,\n ...(parsed.traceId ? { traceId: parsed.traceId } : {}),\n ...(parsed.traceUrl ? { traceUrl: parsed.traceUrl } : {}),\n ...(parsed.logsUrl ? { logsUrl: parsed.logsUrl } : {}),\n ...(parsed.reasons ? { reasons: parsed.reasons } : {}),\n ...(parsed.suggestions ? { suggestions: parsed.suggestions } : {}),\n ...(parsed.docUrl ? { docUrl: parsed.docUrl } : {}),\n // The platform names its own failures; a 5xx names ours, whatever the body\n // says. Trusting a 500's \"code\" would let an infrastructure outage present\n // itself to the user as though they had done something wrong.\n //\n // With no status to go on, the code decides: the platform only emits a\n // generic code when it fell over, so anything more specific than that is a\n // failure it chose to name — which is exactly what a domain error is.\n isHandled:\n status > 0\n ? status < SERVER_ERROR_STATUS\n : !isGenericCode(parsed.code),\n };\n};\n\n/**\n * The document the CLI prints on stdout when a command fails under\n * `--format json`, and the one the panel reads back.\n *\n * A machine caller — Langy runs the CLI in a shell and parses its stdout — got\n * nothing but prose on the error path before this: the failure was a red line on\n * stderr and an exit code, so an agent could see THAT a command failed and never\n * WHY. It would then guess, and usually guess \"retry\". A `code` it can match on\n * is the difference between retrying a transient failure and stopping dead on a\n * terminal one.\n *\n * `ok: false` is the discriminant. A success document is the bare card object\n * (see `parseCliResult`), so nothing else on stdout carries it.\n */\nexport interface CliErrorDocument {\n ok: false;\n error: CliHandledError & {\n /**\n * Whether retrying — with the same arguments or with different ones — can\n * possibly change the answer. See {@link isTerminalFailure}.\n *\n * Written for the agent, which otherwise has to infer it from the code and\n * gets it wrong in the expensive direction: it re-ran a create that had\n * been refused on a plan limit with a different set of flags, which could\n * never have worked and put a second card in the user's transcript for a\n * resource that was never made. Derived, never authored by a caller.\n */\n terminal: boolean;\n };\n}\n\n/** Build the `--format json` failure document. */\nexport const toCliErrorDocument = (error: CliHandledError): CliErrorDocument => ({\n ok: false,\n error: { ...error, terminal: isTerminalFailure(error) },\n});\n\n/**\n * Read a CLI failure document back, or null when the output is not one.\n *\n * Null-on-miss rather than throw: stdout may hold a card, a human table, or\n * nothing at all, and none of those is an error document.\n */\nexport const readCliErrorDocument = (\n output: unknown,\n): CliHandledError | null => {\n const document =\n typeof output === \"string\" ? safeParseJson(output) : asRecord(output);\n\n const record = asRecord(document);\n if (!record || record.ok !== false) return null;\n\n const error = asRecord(record.error);\n const code =\n typeof error?.code === \"string\"\n ? error.code\n : typeof error?.kind === \"string\"\n ? error.kind\n : null;\n if (!error || code === null) return null;\n\n return {\n code,\n // Deprecated back-compat alias — see CliHandledError.kind.\n kind: code,\n message: typeof error.message === \"string\" ? error.message : code,\n httpStatus: typeof error.httpStatus === \"number\" ? error.httpStatus : 0,\n meta: asRecord(error.meta) ?? {},\n isHandled: error.isHandled === true,\n ...(typeof error.traceId === \"string\" ? { traceId: error.traceId } : {}),\n ...(typeof error.traceUrl === \"string\" ? { traceUrl: error.traceUrl } : {}),\n ...(typeof error.logsUrl === \"string\" ? { logsUrl: error.logsUrl } : {}),\n ...(asReasons(error.reasons) ? { reasons: asReasons(error.reasons) } : {}),\n ...(asSuggestions(error.suggestions)\n ? { suggestions: asSuggestions(error.suggestions) }\n : {}),\n ...(typeof error.docUrl === \"string\" ? { docUrl: error.docUrl } : {}),\n };\n};\n\nconst safeParseJson = (value: string): unknown => {\n const trimmed = value.trim();\n if (!trimmed.startsWith(\"{\")) return null;\n try {\n return JSON.parse(trimmed) as unknown;\n } catch {\n return null;\n }\n};\n\n/**\n * A `LangWatchHandledError` — an error the SDK's transport ALREADY read the wire\n * into. It brands itself with a boolean rather than relying on `instanceof`,\n * which does not survive a bundled CLI meeting a consumer's own copy of the SDK.\n */\nconst asAlreadyReadHandledError = (\n outer: Record<string, unknown> | null,\n): CliHandledError | null => {\n if (!outer || outer.isLangWatchHandledError !== true) return null;\n const code =\n typeof outer.code === \"string\"\n ? outer.code\n : typeof outer.kind === \"string\"\n ? outer.kind\n : null;\n if (code === null) return null;\n\n return {\n code,\n // Deprecated back-compat alias — see CliHandledError.kind.\n kind: code,\n message: typeof outer.message === \"string\" ? outer.message : code,\n httpStatus: typeof outer.httpStatus === \"number\" ? outer.httpStatus : 0,\n meta: asRecord(outer.meta) ?? {},\n isHandled: true,\n ...(typeof outer.traceId === \"string\" ? { traceId: outer.traceId } : {}),\n ...(typeof outer.traceUrl === \"string\" ? { traceUrl: outer.traceUrl } : {}),\n ...(typeof outer.logsUrl === \"string\" ? { logsUrl: outer.logsUrl } : {}),\n ...(asReasons(outer.reasons) ? { reasons: asReasons(outer.reasons) } : {}),\n ...(asSuggestions(outer.suggestions)\n ? { suggestions: asSuggestions(outer.suggestions) }\n : {}),\n ...(typeof outer.docUrl === \"string\" ? { docUrl: outer.docUrl } : {}),\n };\n};\n\n/**\n * The status an error carries, wherever it chose to put it. The SDK's HTTP layer,\n * its service wrappers and `fetch` each spell this differently.\n */\nconst statusOf = (value: Record<string, unknown> | null): number => {\n if (!value) return 0;\n if (typeof value.status === \"number\") return value.status;\n if (typeof value.statusCode === \"number\") return value.statusCode;\n if (typeof value.httpStatus === \"number\") return value.httpStatus;\n\n const response = asRecord(value.response);\n if (response && typeof response.status === \"number\") return response.status;\n\n return 0;\n};\n\n/**\n * The same reading, for an error that was THROWN rather than returned — the shape\n * the SDK's service layer raises.\n *\n * Those wrappers (`TracesApiError` and friends) flatten the API's error body into\n * an English sentence for the console but keep the original alongside it, so the\n * structure is recoverable: unwrap to the innermost cause and read the wire shape\n * off that. Without this the CLI would report every failure as a generic string\n * and the panel would lose the one thing it can act on — the code.\n *\n * Anything unrecognisable becomes a non-domain error carrying its own message,\n * which is the honest answer: we do not know what went wrong, so we do not claim\n * a code we cannot substantiate.\n */\nexport const handledErrorFromThrown = (error: unknown): CliHandledError => {\n const outer = asRecord(error);\n\n // The SDK's HTTP layer may have read this already, into a richer structure than\n // the wire body it came from: the flattened body carries no trace id and no\n // reason chain, so re-deriving from it would THROW AWAY the fields the typed\n // error exists to preserve. Trust the reading that already happened.\n const alreadyRead = asAlreadyReadHandledError(outer);\n if (alreadyRead) return alreadyRead;\n\n // The SDK wraps the API's error body; the body is the thing worth reading.\n const cause =\n asRecord(outer?.originalError) ??\n asRecord(outer?.cause) ??\n asRecord(outer?.body) ??\n outer;\n\n const status = statusOf(cause) || statusOf(outer);\n const parsed = parseHandledError({ status, body: cause });\n\n if (parsed.isHandled) return parsed;\n\n return {\n ...parsed,\n message:\n error instanceof Error && error.message ? error.message : parsed.message,\n };\n};\n","import {\n parseHandledError,\n type CliHandledError,\n type CliHandledErrorReason,\n} from \"@langwatch/langy/cards/handled-error\";\n\n/**\n * A failure the platform NAMED.\n *\n * The API does not merely fail — when it declines a request it says precisely\n * why, as a `HandledError` with a serialisable `kind` (`dataset_not_found`,\n * `validation_error`), the HTTP status it answers with, and a `meta` bag of the\n * context that makes the failure actionable. Until now the SDK collapsed all of\n * that into an English sentence on a generic error, so a caller could read the\n * failure but never react to it: a 404 \"dataset not found\" — a fact you can\n * offer to fix — was indistinguishable from a 500.\n *\n * This is that structure, kept. Narrow with {@link isLangWatchHandledError} (or\n * `instanceof`) and switch on `code`; `body` is the escape hatch to whatever the\n * platform sent that this class did not model.\n *\n * ```ts\n * try {\n * await langwatch.datasets.get(\"nope\");\n * } catch (error) {\n * if (isLangWatchHandledError(error) && error.code === \"dataset_not_found\") {\n * // Actionable: we know WHAT was not found, and can offer the list.\n * console.error(error.meta.id, error.traceId);\n * }\n * throw error;\n * }\n * ```\n *\n * ONLY raised for a failure the platform named. An infrastructure failure — a\n * 5xx, a dead socket, a proxy's HTML error page — still raises the generic\n * service error it always did, because presenting one of those as a domain\n * error would blame the user for our outage.\n */\nexport class LangWatchHandledError extends Error {\n /**\n * The discriminant. A boolean brand rather than `instanceof` alone because a\n * bundled CLI and a consumer's `node_modules` copy of the SDK can hold two\n * different copies of this class, and `instanceof` is false across that seam —\n * the same reason the platform's own error handler tests for `code` rather\n * than class identity.\n */\n readonly isLangWatchHandledError = true as const;\n\n /** The platform's serialisable discriminant, e.g. `dataset_not_found`. */\n readonly code: string;\n /**\n * @deprecated Back-compat alias of `code`, kept while the platform's\n * `DomainError` → `HandledError` rename rolls out. Read `code` in new code.\n */\n readonly kind: string;\n /** The status the platform answered with. */\n readonly httpStatus: number;\n /** The context the platform attached: ids, field errors — whatever makes it actionable. */\n readonly meta: Record<string, unknown>;\n /** The OTel trace to quote at support. Absent unless the route sent one. */\n readonly traceId: string | undefined;\n /** A clickable link to that trace, when the route sent one. */\n readonly traceUrl: string | undefined;\n /** A clickable link to the logs for that trace, when the route sent one. */\n readonly logsUrl: string | undefined;\n /** The failure behind the failure, when the route sent the chain. */\n readonly reasons: CliHandledErrorReason[] | undefined;\n /** What the user can DO about it, when the platform sent next steps. */\n readonly suggestions: string[] | undefined;\n /** The docs page that explains the failure, when the platform sent one. */\n readonly docUrl: string | undefined;\n /** The raw response body, verbatim — the escape hatch for anything unmodelled. */\n readonly body: unknown;\n /** What the SDK was doing, e.g. `get dataset \"abc\"`. */\n readonly operation: string | undefined;\n\n /**\n * Alias of {@link httpStatus}, and the raw body again under the name the\n * per-service `*ApiError` classes use.\n *\n * Not redundancy for its own sake: this class is thrown from the SAME code\n * path that used to throw `TracesApiError` & friends, so anything that reads\n * `.status` or `.originalError` off a caught SDK error — including the CLI's\n * own telemetry reader — keeps working unchanged.\n */\n readonly status: number;\n readonly originalError: unknown;\n\n constructor({\n handled,\n body,\n operation,\n message,\n }: {\n handled: CliHandledError;\n body: unknown;\n operation?: string;\n message: string;\n }) {\n super(message);\n this.name = \"LangWatchHandledError\";\n this.code = handled.code;\n this.kind = handled.code;\n this.httpStatus = handled.httpStatus;\n this.meta = handled.meta;\n this.traceId = handled.traceId;\n this.traceUrl = handled.traceUrl;\n this.logsUrl = handled.logsUrl;\n this.reasons = handled.reasons;\n this.suggestions = handled.suggestions;\n this.docUrl = handled.docUrl;\n this.body = body;\n this.operation = operation;\n this.status = handled.httpStatus;\n this.originalError = body;\n }\n}\n\n/** Narrows any caught value to a {@link LangWatchHandledError}. */\nexport const isLangWatchHandledError = (\n error: unknown,\n): error is LangWatchHandledError =>\n error instanceof LangWatchHandledError ||\n (typeof error === \"object\" &&\n error !== null &&\n (error as { isLangWatchHandledError?: unknown }).isLangWatchHandledError ===\n true);\n\n/**\n * Read a non-2xx response into a {@link LangWatchHandledError}, or `null` when the\n * platform did NOT name the failure.\n *\n * `null` is the important half of the contract: it means \"this was not a domain\n * error\", and every caller answers it by throwing exactly the generic error it\n * threw before. A malformed body, an HTML error page from a proxy, a bare 500 —\n * all take the old path untouched. This is strictly additive.\n */\nexport const handledErrorFrom = ({\n operation,\n body,\n status,\n message,\n}: {\n /** What was being attempted — `GET /api/traces/{id}`, or a service's phrasing. */\n operation?: string;\n /** The parsed error body, as the HTTP client handed it back. */\n body: unknown;\n /** The status the response carried, when it is known. */\n status?: number;\n /**\n * The message the generic path WOULD have produced. Passed by callers that\n * already built one (so nothing regresses); omitted by the transport, which\n * has no operation worth prefixing and lets the platform's own sentence stand.\n */\n message?: string;\n}): LangWatchHandledError | null => {\n const handled = parseHandledError({ status: status ?? 0, body });\n if (!handled.isHandled) return null;\n\n return new LangWatchHandledError({\n handled,\n body,\n operation,\n // The platform wrote its message for a user to read. Use it as-is unless a\n // caller hands us the sentence it had already composed.\n message: message ?? handled.message,\n });\n};\n\nexport class LangWatchApiError extends Error {\n public readonly httpStatus: number;\n public readonly httpStatusText: string;\n public apiError: string | undefined;\n public body: unknown;\n\n constructor(message: string, response: Response) {\n super(message);\n this.httpStatus = response.status;\n this.httpStatusText = response.statusText;\n }\n\n async safeParseBody(response: Response): Promise<void> {\n try {\n if (response.headers.get(\"Content-Type\")?.includes(\"application/json\")) {\n const json = await response.json();\n\n this.body = json;\n\n if (json.error && typeof json.error === \"string\") {\n this.apiError = json.error;\n }\n\n return;\n }\n\n this.body = await response.text();\n } catch {\n this.body = null;\n }\n }\n}\n","/**\n * Error class for template compilation issues\n */\nexport class PromptCompilationError extends Error {\n constructor(\n message: string,\n public readonly template: string,\n public readonly originalError?: any,\n ) {\n super(message);\n this.name = \"PromptCompilationError\";\n }\n}\n","import { type z } from \"zod\";\n\n/**\n * Error class for prompt validation issues\n */\nexport class PromptValidationError extends Error {\n constructor(message: string, public readonly validationErrors: z.ZodError) {\n super(message);\n this.name = \"PromptValidationError\";\n }\n}\n","/**\n * Base error class for the Prompts domain.\n * All prompt-related errors should extend this class.\n */\nexport class PromptsError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"PromptsError\";\n }\n}\n","import { PromptsError } from \"./prompts.error\";\n\n/**\n * Error class for Prompts API operations.\n * Provides context about the failed operation and the original error.\n */\nexport class PromptsApiError extends PromptsError {\n constructor(\n message: string,\n public readonly operation: string,\n public readonly originalError?: unknown,\n ) {\n super(message);\n this.name = \"PromptsApiError\";\n }\n}\n","/**\n * Extracts the most informative, user-facing message from an API error body.\n *\n * Errors from the LangWatch API follow the shape `{ error: string, message?: string }`\n * per `errorSchema` in the server. In production the middleware may return a\n * generic `{ error: \"Internal server error\", message: \"Internal server error\" }`\n * which is useless to a user — this helper at least falls back to stringifying\n * the raw body so no diagnostic information is lost.\n *\n * Priority (first non-generic, non-empty wins):\n * 1. `body.message` (descriptive sentence from the server)\n * 2. `body.error` (error kind — \"NotFoundError\", \"Conflict\", …)\n * 3. Any other string fields on the body object (e.g. `detail`, `reason`)\n * 4. JSON stringification of the entire body\n * 5. `Error#message` if the input is a thrown Error\n * 6. A status-code-derived fallback, if available\n */\nconst GENERIC_MESSAGES = new Set([\n \"\",\n \"internal server error\",\n \"unknown error\",\n \"unknown error occurred\",\n]);\n\nfunction isGeneric(s: string): boolean {\n return GENERIC_MESSAGES.has(s.trim().toLowerCase());\n}\n\nfunction firstMeaningful(...candidates: Array<unknown>): string | undefined {\n for (const c of candidates) {\n if (typeof c === \"string\" && !isGeneric(c)) return c;\n }\n return undefined;\n}\n\nfunction collectAllOwnPropertyNames(value: unknown, seen = new Set<unknown>()): string[] {\n if (!value || typeof value !== \"object\" || seen.has(value)) return [];\n seen.add(value);\n const names = new Set<string>();\n for (const name of Object.getOwnPropertyNames(value)) {\n names.add(name);\n try {\n const child = (value as Record<string, unknown>)[name];\n for (const nested of collectAllOwnPropertyNames(child, seen)) {\n names.add(nested);\n }\n } catch {\n // Ignore getter side effects.\n }\n }\n return Array.from(names);\n}\n\ninterface ZodIssue {\n path?: unknown;\n message?: unknown;\n}\n\n/**\n * Renders a Zod validation error body into a user-readable string. Returns\n * undefined if `body` is not a Zod error shape.\n *\n * Examples:\n * { name: \"ZodError\", issues: [{ path: [\"format\"], message: \"Invalid enum value...\" }] }\n * → \"Validation failed: format — Invalid enum value...\"\n * { name: \"ZodError\", issues: [<issue1>, <issue2>] }\n * → \"Validation failed: a.b — msg1; c — msg2\"\n */\nfunction formatZodIssues(body: Record<string, unknown>): string | undefined {\n const isZod =\n body.name === \"ZodError\" ||\n (Array.isArray(body.issues) && body.issues.length > 0);\n if (!isZod || !Array.isArray(body.issues)) return undefined;\n\n const rendered = (body.issues as ZodIssue[])\n .map((issue) => {\n const pathArr = Array.isArray(issue.path) ? issue.path : [];\n const path = pathArr\n .filter((p) => typeof p === \"string\" || typeof p === \"number\")\n .join(\".\");\n const msg = typeof issue.message === \"string\" ? issue.message : \"\";\n if (path && msg) return `${path} — ${msg}`;\n if (msg) return msg;\n if (path) return path;\n return undefined;\n })\n .filter((s): s is string => typeof s === \"string\" && s.length > 0);\n\n if (rendered.length === 0) return undefined;\n return `Validation failed: ${rendered.join(\"; \")}`;\n}\n\nfunction stringifyBody(body: unknown): string {\n try {\n // Use all own property names (including non-enumerable ones, common on\n // native Error instances and fetch errors) so we preserve every field the\n // server sent, at any nesting depth.\n if (body && typeof body === \"object\") {\n return JSON.stringify(body, collectAllOwnPropertyNames(body));\n }\n return JSON.stringify(body);\n } catch {\n return String(body);\n }\n}\n\nexport interface FormatApiErrorOptions {\n /**\n * HTTP status code from the response, when known. Used as part of the\n * fallback output so that the user has at least some actionable signal.\n */\n status?: number;\n}\n\nexport interface FormatApiErrorMessageParams {\n error: unknown;\n /** Currently only `status` — kept as an object for forward extension. */\n options?: FormatApiErrorOptions;\n}\n\nexport function formatApiErrorMessage({\n error,\n options = {},\n}: FormatApiErrorMessageParams): string {\n if (error == null) {\n return options.status\n ? `Request failed with status ${options.status}`\n : \"Unknown error occurred\";\n }\n\n if (typeof error === \"string\") {\n return isGeneric(error) && options.status\n ? `${error} (status ${options.status})`\n : error;\n }\n\n if (error instanceof Error) {\n // Node's fetch wraps transport failures as `TypeError: fetch failed` with\n // the real reason (ECONNREFUSED, ENOTFOUND, timeout, etc.) on `.cause`.\n // Surface that so the user can tell whether the endpoint is wrong, the\n // server is down, or DNS can't resolve the host.\n const base = error.message || \"Unknown error occurred\";\n const cause = (error as { cause?: unknown }).cause;\n const causeMsg =\n cause instanceof Error\n ? cause.message\n : cause && typeof cause === \"object\" &&\n typeof (cause as { message?: unknown }).message === \"string\"\n ? (cause as { message: string }).message\n : undefined;\n const causeCode =\n cause && typeof cause === \"object\" &&\n typeof (cause as { code?: unknown }).code === \"string\"\n ? (cause as { code: string }).code\n : undefined;\n\n const detail = [causeCode, causeMsg && causeMsg !== base ? causeMsg : undefined]\n .filter((s): s is string => typeof s === \"string\" && s.length > 0)\n .join(\": \");\n const formatted = detail ? `${base} (${detail})` : base;\n\n // Node fetch emits \"TypeError: fetch failed\" with `cause.message =\n // \"unknown scheme\"` when the URL has no/invalid scheme (e.g. the user\n // set LANGWATCH_ENDPOINT=localhost:5570 instead of http://localhost:5570).\n // Add a hint — the raw phrase tells the user nothing actionable.\n const combined = `${base} ${causeMsg ?? \"\"} ${causeCode ?? \"\"}`.toLowerCase();\n if (\n combined.includes(\"unknown scheme\") ||\n combined.includes(\"err_invalid_url\") ||\n combined.includes(\"failed to parse url\")\n ) {\n return `${formatted} — check your LANGWATCH_ENDPOINT (must start with http:// or https://)`;\n }\n return formatted;\n }\n\n if (typeof error === \"object\") {\n const body = error as Record<string, unknown>;\n\n // Zod validation errors: `{ name: \"ZodError\", issues: [{ path, message }] }`.\n // Without this they render as unreadable raw JSON to the user.\n const zod = formatZodIssues(body);\n if (zod) return zod;\n\n // Most specific fields first.\n const fromMessage = typeof body.message === \"string\" ? body.message : undefined;\n const fromError = typeof body.error === \"string\" ? body.error : undefined;\n const fromDetail = typeof body.detail === \"string\" ? body.detail : undefined;\n const fromReason = typeof body.reason === \"string\" ? body.reason : undefined;\n\n // 1. Top-level meaningful fields take priority. If the server gave us a\n // descriptive `message`/`error`/`detail`/`reason`, use that — even if\n // `body.error` is an object with its own (potentially generic) message.\n const meaningful = firstMeaningful(fromMessage, fromError, fromDetail, fromReason);\n if (meaningful) {\n if (\n fromError &&\n fromMessage &&\n fromMessage !== fromError &&\n !isGeneric(fromError) &&\n !isGeneric(fromMessage)\n ) {\n return `${fromError}: ${fromMessage}`;\n }\n return meaningful;\n }\n\n // 2. Nested `body.error` — only used as a fallback when no top-level\n // field carried a useful message. Native Error instances and\n // tRPC-style envelopes both fit here.\n if (body.error && typeof body.error === \"object\") {\n const nested = body.error as Record<string, unknown>;\n\n if (body.error instanceof Error && body.error.message) {\n return body.error.message;\n }\n\n // Zod validation envelopes: `{ success: false, error: { name: \"ZodError\", issues: [...] } }`\n const nestedZod = formatZodIssues(nested);\n if (nestedZod) return nestedZod;\n\n const fromNestedMsg = typeof nested.message === \"string\" ? nested.message : undefined;\n const fromNestedErr = typeof nested.error === \"string\" ? nested.error : undefined;\n const nestedMeaningful = firstMeaningful(fromNestedMsg, fromNestedErr);\n if (nestedMeaningful) {\n return nestedMeaningful;\n }\n\n // Stringify the nested object so identifiers like `{ code, status }`\n // still reach the user.\n const nestedRaw = stringifyBody(nested);\n if (nestedRaw && nestedRaw !== \"{}\") {\n return nestedRaw;\n }\n }\n\n // 3. No meaningful top-level or nested fields — dump the raw JSON so\n // the user at least sees the server payload. Attach status for\n // context.\n const raw = stringifyBody(body);\n\n // Collapse empty / near-empty payloads to a friendlier message — there's\n // nothing for the user to see in `{}` anyway.\n if (!raw || raw === \"{}\" || raw === '\"\"' || raw === \"null\") {\n return options.status\n ? `Request failed with status ${options.status}`\n : \"Unknown error occurred\";\n }\n\n const withStatus = options.status ? `status ${options.status} ${raw}` : raw;\n return `server returned ${withStatus}`;\n }\n\n // Primitive types (number, boolean, bigint, symbol) — coerce safely.\n // We've already handled string, null/undefined, Error, and object above.\n try {\n return String(error as number | boolean | bigint);\n } catch {\n return \"Unknown error occurred\";\n }\n}\n\nexport interface FormatApiErrorForOperationParams {\n operation: string;\n error: unknown;\n options?: FormatApiErrorOptions;\n}\n\n/**\n * Builds a fully-qualified error message for a specific operation, including\n * the operation name and the extracted server-side message.\n */\nexport function formatApiErrorForOperation({\n operation,\n error,\n options = {},\n}: FormatApiErrorForOperationParams): string {\n const message = formatApiErrorMessage({ error, options });\n return `Failed to ${operation}: ${message}`;\n}\n\n/**\n * Attempts to read a status code from common response-shaped wrappers without\n * assuming a particular SDK. Returns undefined if none is found.\n */\nexport function extractStatusFromResponse(value: unknown): number | undefined {\n if (!value || typeof value !== \"object\") return undefined;\n const obj = value as Record<string, unknown>;\n if (typeof obj.status === \"number\") return obj.status;\n if (typeof obj.statusCode === \"number\") return obj.statusCode;\n if (obj.response && typeof obj.response === \"object\") {\n const resp = obj.response as Record<string, unknown>;\n if (typeof resp.status === \"number\") return resp.status;\n }\n return undefined;\n}\n","import { Liquid } from \"liquidjs\";\nimport { PromptTracingDecorator, tracer } from \"./tracing\";\nimport { createTracingProxy } from \"@/client-sdk/tracing/create-tracing-proxy\";\nimport { promptDataSchema } from \"./schema\";\nimport { type TemplateVariables, type PromptData, type CorePromptData, type PromptScope } from \"./types\";\nimport { PromptCompilationError, PromptValidationError } from \"./errors\";\n\n// Re-export types and errors for convenience\nexport type { TemplateVariables, PromptData, CorePromptData, PromptMetadata } from \"./types\";\nexport { PromptCompilationError, PromptValidationError } from \"./errors\";\n\n// Global Liquid instance - shared across all prompts for efficiency\nconst liquid = new Liquid({\n strictFilters: true,\n});\n\n/**\n * The Prompt class provides a standardized interface for working with prompt objects\n * within the SDK, focusing on core functionality needed for template compilation and execution.\n * Keeps only essential fields while maintaining compatibility with tracing and observability.\n */\nexport class Prompt {\n // === Core functionality (required) ===\n public readonly model!: string;\n public readonly messages!: Array<{\n role: \"user\" | \"assistant\" | \"system\";\n content: string;\n }>;\n\n // === Optional core fields ===\n public readonly prompt?: string;\n public readonly temperature?: number;\n public readonly maxTokens?: number;\n public readonly responseFormat?: CorePromptData[\"responseFormat\"];\n\n // === Runtime parameters ===\n public readonly parameters: Record<string, unknown> = {};\n\n // === Optional identification (for tracing) ===\n public readonly id?: string;\n public readonly handle?: string | null;\n public readonly version?: number;\n public readonly versionId?: string;\n public readonly scope?: PromptScope;\n\n constructor(data: PromptData) {\n // Validate input using Zod\n const validationResult = promptDataSchema.strip().safeParse(data);\n\n if (!validationResult.success) {\n throw new PromptValidationError(\n \"Invalid prompt data provided\",\n validationResult.error\n );\n }\n\n // Assign validated data\n Object.assign(this, validationResult.data);\n\n // Set default for prompt if not provided\n this.prompt ??= this.extractSystemPrompt();\n\n // Return a proxy that wraps specific methods for tracing\n return createTracingProxy(this as Prompt, tracer, PromptTracingDecorator);\n }\n\n private extractSystemPrompt(): string {\n return this.messages.find(m => m.role === \"system\")?.content ?? \"\";\n }\n\n /**\n * Compile the prompt template with provided variables (lenient - missing variables become empty)\n * @param variables - Object containing variable values for template compilation\n * @returns CompiledPrompt instance with compiled content\n */\n private _compile(\n variables: TemplateVariables,\n strict: boolean,\n ): CompiledPrompt {\n try {\n // Compile main prompt\n const compiledPrompt = this.prompt\n ? liquid.parseAndRenderSync(this.prompt, variables, {\n strictVariables: strict,\n })\n : \"\";\n\n // Compile messages\n const compiledMessages = (this.messages || []).map((message) => ({\n ...message,\n content: message.content\n ? liquid.parseAndRenderSync(message.content, variables, {\n strictVariables: strict,\n })\n : message.content,\n }));\n\n // Create new prompt data with compiled content\n const compiledData: PromptData = {\n ...this,\n prompt: compiledPrompt,\n messages: compiledMessages,\n };\n\n return new CompiledPrompt(compiledData, this);\n } catch (error) {\n const templateStr = this.prompt ?? JSON.stringify(this.messages);\n throw new PromptCompilationError(\n `Failed to compile prompt template: ${\n error instanceof Error ? error.message : \"Unknown error\"\n }`,\n templateStr,\n error,\n );\n }\n }\n\n compile(variables: TemplateVariables = {}): CompiledPrompt {\n return this._compile(variables, false);\n }\n\n /**\n * Compile with validation - throws error if required variables are missing\n * @param variables - Template variables\n * @returns CompiledPrompt instance with compiled content\n */\n compileStrict(variables: TemplateVariables): CompiledPrompt {\n return this._compile(variables, true);\n }\n}\n\n\n/**\n * Represents a compiled prompt that extends Prompt with reference to the original template\n */\nexport class CompiledPrompt extends Prompt {\n constructor(\n compiledData: PromptData,\n public readonly original: Prompt,\n ) {\n super(compiledData);\n }\n}\n","// TODO: Move these to their own files\nimport { z } from \"zod\";\nimport { PromptScope } from \"../constants\";\n\n/**\n * Zod schema for message objects in prompts\n */\nexport const messageSchema = z.object({\n role: z.enum([\"user\", \"assistant\", \"system\"]),\n content: z.string(),\n});\n\n/**\n * Zod schema for response format configuration\n */\nexport const responseFormatSchema = z.object({\n type: z.literal(\"json_schema\"),\n json_schema: z.object({\n name: z.string(),\n schema: z.record(z.string(), z.unknown()),\n }).nullable(),\n}).optional();\n\n/**\n * Zod schema for core prompt data - the essential fields needed for functionality\n */\nexport const corePromptDataSchema = z.object({\n model: z.string().min(1, \"Model cannot be empty\"),\n messages: z.array(messageSchema).min(1, \"At least one message is required\"),\n prompt: z.string().optional(),\n temperature: z.number().min(0).max(2).optional(),\n maxTokens: z.number().positive().optional(),\n responseFormat: responseFormatSchema,\n});\n\n/**\n * Zod schema for prompt metadata - optional fields for identification and tracing\n */\nexport const promptMetadataSchema = z.object({\n id: z.string().optional(),\n handle: z.string().nullable().optional(),\n version: z.number().min(0).optional(),\n versionId: z.string().optional(),\n scope: z.enum(PromptScope).optional(),\n});\n\n/**\n * Combined schema for complete prompt data\n */\nexport const promptDataSchema = z.object({\n ...corePromptDataSchema.shape,\n ...promptMetadataSchema.shape,\n parameters: z.record(z.string(), z.unknown()).optional(),\n});\n","import { type PromptScope as PromptScopeType } from \"./types\";\n\nexport const PromptScope = {\n ORGANIZATION: \"ORGANIZATION\" as const,\n PROJECT: \"PROJECT\" as const,\n} satisfies Record<string, PromptScopeType>;\n","import { type z } from \"zod\";\nimport type { paths } from \"@/internal/generated/openapi/api-client\";\nimport {\n type corePromptDataSchema,\n type promptMetadataSchema,\n type promptDataSchema\n} from \"./schema\";\n\n/**\n * Type for template variables - supporting common data types\n */\nexport type TemplateVariables = Record<\n string,\n string | number | boolean | object | null\n>;\n\n/**\n * Core data needed for prompt functionality\n */\nexport type CorePromptData = z.infer<typeof corePromptDataSchema>;\n\n/**\n * Optional metadata for identification and tracing\n */\nexport type PromptMetadata = z.infer<typeof promptMetadataSchema>;\n\n/**\n * Combined type for creating prompts\n */\nexport type PromptData = z.infer<typeof promptDataSchema>;\n\n// Extract API types from OpenAPI schema for backwards compatibility\nexport type CreatePromptBody = NonNullable<\n paths[\"/api/prompts\"][\"post\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\nexport type UpdatePromptBody = NonNullable<\n paths[\"/api/prompts/{id}\"][\"put\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\nexport type PromptResponse = NonNullable<\n paths[\"/api/prompts/{id}\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"]\n>;\n\n// Extract the PromptScope type from the API client\nexport type PromptScope = paths[\"/api/prompts\"][\"post\"][\"responses\"][\"200\"][\"content\"][\"application/json\"][\"scope\"];\n\n// Extract tag definition types from the OpenAPI schema\nexport type TagDefinition = NonNullable<\n paths[\"/api/prompts/tags\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"]\n>[number];\n\nexport type CreatedTag = NonNullable<\n paths[\"/api/prompts/tags\"][\"post\"][\"responses\"][\"201\"][\"content\"][\"application/json\"]\n>;\n\n/**\n * Fetch policy for prompt retrieval.\n * Controls how prompts are fetched and cached.\n */\nexport enum FetchPolicy {\n /** Use local file if available, otherwise fetch from API (default) */\n MATERIALIZED_FIRST = \"MATERIALIZED_FIRST\",\n /** Always try API first, fall back to materialized */\n ALWAYS_FETCH = \"ALWAYS_FETCH\",\n /** Fetch every X minutes, use materialized between fetches */\n CACHE_TTL = \"CACHE_TTL\",\n /** Never fetch, use materialized files only */\n MATERIALIZED_ONLY = \"MATERIALIZED_ONLY\",\n}\n\n","import * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as yaml from \"js-yaml\";\nimport chalk from \"chalk\";\nimport type { PromptsConfig, LocalPromptConfig, MaterializedPrompt, PromptsLock } from \"../types\";\nimport { localPromptConfigSchema } from \"../types-prompt\";\nimport { PromptConverter } from \"@/cli/utils/promptConverter\";\nimport { PromptFileNotFoundError } from \"./errors/prompt-not-found.error\";\nimport { formatApiErrorMessage } from \"@/client-sdk/services/_shared/format-api-error\";\n\nexport class FileManager {\n private static readonly PROMPTS_CONFIG_FILE = \"prompts.json\";\n private static readonly PROMPTS_LOCK_FILE = \"prompts-lock.json\";\n private static readonly PROMPTS_DIR = \"prompts\";\n private static readonly MATERIALIZED_DIR = \".materialized\";\n\n private static _projectRoot: string | undefined;\n /**\n * The cwd `_projectRoot` was derived from.\n *\n * The cache MUST be keyed by it. Memoising a cwd-derived path without that key\n * is correct only in a process that serves exactly one command and then dies;\n * in a process that serves many from different directories (the CLI daemon, a\n * test runner, an embedding host), the second caller silently inherits the\n * first caller's project root and reads or writes the wrong prompts.json.\n */\n private static _projectRootCwd: string | undefined;\n\n /** Reset the cached project root. Tests use this to exercise different cwds. */\n static _resetProjectRootCache(): void {\n this._projectRoot = undefined;\n this._projectRootCwd = undefined;\n }\n\n private static cacheProjectRoot(cwd: string, root: string): string {\n this._projectRoot = root;\n this._projectRootCwd = cwd;\n return root;\n }\n\n private static readonly PROJECT_MARKERS = [\n \".git\",\n \"package.json\",\n \"pyproject.toml\",\n ];\n\n private static hasProjectMarker(dir: string): boolean {\n return this.PROJECT_MARKERS.some((m) => fs.existsSync(path.join(dir, m)));\n }\n\n private static findProjectRoot(): string {\n const cwd = process.cwd();\n\n if (this._projectRoot && this._projectRootCwd === cwd) {\n return this._projectRoot;\n }\n\n const fsRoot = path.parse(cwd).root;\n\n // Find the highest ancestor that still looks like part of \"this project\"\n // (has package.json / pyproject.toml / .git). If cwd itself has no marker,\n // we don't walk up at all — prevents grabbing a stray prompts.json from\n // /tmp or other shared scratch dirs.\n let topProjectDir: string | null = null;\n let scan = cwd;\n while (scan !== fsRoot) {\n if (this.hasProjectMarker(scan)) {\n topProjectDir = scan;\n }\n scan = path.dirname(scan);\n }\n\n if (!topProjectDir) {\n return this.cacheProjectRoot(cwd, cwd);\n }\n\n // Walk up from cwd looking for prompts.json, capped at the project boundary.\n let currentDir = cwd;\n while (true) {\n const configPath = path.join(currentDir, this.PROMPTS_CONFIG_FILE);\n if (fs.existsSync(configPath)) {\n return this.cacheProjectRoot(cwd, currentDir);\n }\n if (currentDir === topProjectDir) break;\n currentDir = path.dirname(currentDir);\n }\n\n // No prompts.json anywhere within the project — default to cwd so `init`\n // creates it where the user actually ran the command. This also keeps\n // concurrent test workdirs isolated: each tempdir gets its own prompts.json\n // instead of all pointing at a shared repo-root file.\n return this.cacheProjectRoot(cwd, cwd);\n }\n\n static getPromptsConfigPath(): string {\n return path.join(this.findProjectRoot(), this.PROMPTS_CONFIG_FILE);\n }\n\n static getPromptsLockPath(): string {\n return path.join(this.findProjectRoot(), this.PROMPTS_LOCK_FILE);\n }\n\n static getPromptsDir(): string {\n return path.join(this.findProjectRoot(), this.PROMPTS_DIR);\n }\n\n static getMaterializedDir(): string {\n return path.join(this.getPromptsDir(), this.MATERIALIZED_DIR);\n }\n\n static ensureDirectories(): void {\n const promptsDir = this.getPromptsDir();\n const materializedDir = this.getMaterializedDir();\n\n if (!fs.existsSync(promptsDir)) {\n fs.mkdirSync(promptsDir, { recursive: true });\n }\n\n if (!fs.existsSync(materializedDir)) {\n fs.mkdirSync(materializedDir, { recursive: true });\n }\n }\n\n static loadPromptsConfig(): PromptsConfig {\n const configPath = this.getPromptsConfigPath();\n\n if (!fs.existsSync(configPath)) {\n return { prompts: {} };\n }\n\n try {\n const content = fs.readFileSync(configPath, \"utf-8\");\n return JSON.parse(content) as PromptsConfig;\n } catch (error) {\n throw new Error(`Failed to parse prompts.json: ${formatApiErrorMessage({ error })}`);\n }\n }\n\n static savePromptsConfig(config: PromptsConfig): void {\n const configPath = this.getPromptsConfigPath();\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\");\n }\n\n static initializePromptsConfig(): { created: boolean; path: string } {\n const configPath = this.getPromptsConfigPath();\n const existed = fs.existsSync(configPath);\n\n if (!existed) {\n const emptyConfig: PromptsConfig = { prompts: {} };\n this.savePromptsConfig(emptyConfig);\n return { created: true, path: configPath };\n }\n\n return { created: false, path: configPath };\n }\n\n static loadPromptsLock = (): PromptsLock => {\n const lockPath = this.getPromptsLockPath();\n\n if (!fs.existsSync(lockPath)) {\n return {\n lockfileVersion: 1,\n prompts: {}\n };\n }\n\n try {\n const content = fs.readFileSync(lockPath, \"utf-8\");\n return JSON.parse(content) as PromptsLock;\n } catch (error) {\n throw new Error(`Failed to parse prompts-lock.json: ${formatApiErrorMessage({ error })}`);\n }\n }\n\n static savePromptsLock(lock: PromptsLock): void {\n const lockPath = this.getPromptsLockPath();\n fs.writeFileSync(lockPath, JSON.stringify(lock, null, 2) + \"\\n\");\n }\n\n static initializePromptsLock(): { created: boolean; path: string } {\n const lockPath = this.getPromptsLockPath();\n const existed = fs.existsSync(lockPath);\n\n if (!existed) {\n const emptyLock: PromptsLock = {\n lockfileVersion: 1,\n prompts: {}\n };\n this.savePromptsLock(emptyLock);\n return { created: true, path: lockPath };\n }\n\n return { created: false, path: lockPath };\n }\n\n static loadLocalPrompt = (filePath: string): LocalPromptConfig => {\n const fullPath = path.resolve(filePath);\n\n if (!fs.existsSync(fullPath)) {\n throw new PromptFileNotFoundError(filePath);\n }\n\n try {\n const content = fs.readFileSync(fullPath, \"utf-8\");\n const rawData = yaml.load(content);\n\n // Validate with zod and provide nice error messages\n const result = localPromptConfigSchema.safeParse(rawData);\n\n if (!result.success) {\n // Format zod errors nicely (manually since z.prettifyError might not be available)\n const prettyError = result.error.issues\n .map(issue => `✖ ${issue.message}${issue.path.length > 0 ? `\\n → at ${issue.path.join('.')}` : ''}`)\n .join('\\n');\n\n throw new Error(\n `Invalid prompt configuration in ${chalk.yellow(filePath)}:\\n${prettyError}`\n );\n }\n\n return result.data;\n } catch (error) {\n if (error instanceof Error && error.message.includes(\"Invalid prompt configuration\")) {\n throw error; // Re-throw zod validation errors as-is\n }\n throw new Error(`Failed to parse local prompt file ${filePath}: ${formatApiErrorMessage({ error })}`);\n }\n }\n\n static saveMaterializedPrompt(name: string, prompt: MaterializedPrompt): string {\n const materializedDir = this.getMaterializedDir();\n const parts = name.split(\"/\");\n const fileName = `${parts[parts.length - 1]}.prompt.yaml`;\n\n // Create nested directories if needed\n if (parts.length > 1) {\n const subDir = path.join(materializedDir, ...parts.slice(0, -1));\n if (!fs.existsSync(subDir)) {\n fs.mkdirSync(subDir, { recursive: true });\n }\n }\n\n const filePath = path.join(materializedDir, ...parts.slice(0, -1), fileName);\n\n // Convert to YAML format using the converter\n const yamlContent = PromptConverter.fromMaterializedToYaml(prompt);\n\n const yamlString = yaml.dump(yamlContent, {\n lineWidth: -1,\n noRefs: true,\n sortKeys: false\n });\n\n fs.writeFileSync(filePath, yamlString);\n return filePath;\n }\n\n static getLocalPromptFiles = (): string[] => {\n const promptsDir = this.getPromptsDir();\n const materializedDir = this.getMaterializedDir();\n\n if (!fs.existsSync(promptsDir)) {\n return [];\n }\n\n const files: string[] = [];\n\n const walkDir = (dir: string, relativePath = \"\"): void => {\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n const relativeFilePath = path.join(relativePath, entry.name);\n\n if (entry.isDirectory()) {\n // Skip the .materialized directory\n if (fullPath === materializedDir) {\n continue;\n }\n walkDir(fullPath, relativeFilePath);\n } else if (entry.isFile() && entry.name.endsWith(\".prompt.yaml\")) {\n files.push(path.join(promptsDir, relativeFilePath));\n }\n }\n };\n\n walkDir(promptsDir);\n return files;\n }\n\n static promptNameFromPath(filePath: string): string {\n const promptsDir = this.getPromptsDir();\n const relativePath = path.relative(promptsDir, filePath);\n return relativePath.replace(/\\.prompt\\.yaml$/, \"\");\n }\n\n static cleanupOrphanedMaterializedFiles(currentDependencies: Set<string>): string[] {\n const materializedDir = this.getMaterializedDir();\n\n if (!fs.existsSync(materializedDir)) {\n return [];\n }\n\n const cleaned: string[] = [];\n\n const cleanupDir = (dir: string, relativePath = \"\"): void => {\n const entries = fs.readdirSync(dir, { withFileTypes: true });\n\n for (const entry of entries) {\n const fullPath = path.join(dir, entry.name);\n const relativeFilePath = path.join(relativePath, entry.name);\n\n if (entry.isDirectory()) {\n cleanupDir(fullPath, relativeFilePath);\n\n // Remove empty directories\n try {\n const dirEntries = fs.readdirSync(fullPath);\n if (dirEntries.length === 0) {\n fs.rmdirSync(fullPath);\n }\n } catch {\n // Directory not empty or other error, ignore\n }\n } else if (entry.isFile() && entry.name.endsWith(\".prompt.yaml\")) {\n // Extract prompt name from materialized file path\n const promptName = relativeFilePath.replace(/\\.prompt\\.yaml$/, \"\");\n\n if (!currentDependencies.has(promptName)) {\n fs.unlinkSync(fullPath);\n cleaned.push(promptName);\n }\n }\n }\n };\n\n cleanupDir(materializedDir);\n return cleaned;\n }\n\n static updateLockEntry(lock: PromptsLock, name: string, prompt: MaterializedPrompt, materializedPath: string): void {\n const relativePath = path.relative(this.findProjectRoot(), materializedPath);\n\n lock.prompts[name] = {\n version: prompt.version,\n versionId: prompt.versionId,\n materialized: relativePath,\n };\n }\n\n static removeFromLock(lock: PromptsLock, names: string[]): void {\n for (const name of names) {\n delete lock.prompts[name];\n }\n }\n\n static addToGitignore(entry: string): { added: boolean; existed: boolean } {\n const gitignorePath = path.join(this.findProjectRoot(), \".gitignore\");\n\n // Check if .gitignore exists\n if (!fs.existsSync(gitignorePath)) {\n // Create new .gitignore with the entry\n fs.writeFileSync(gitignorePath, `${entry}\\n`);\n return { added: true, existed: false };\n }\n\n // Read existing .gitignore\n const content = fs.readFileSync(gitignorePath, \"utf-8\");\n const lines = content.split(\"\\n\").map(line => line.trim());\n\n // Check if entry already exists\n if (lines.includes(entry)) {\n return { added: false, existed: true };\n }\n\n // Add entry to .gitignore\n const newContent = content.endsWith(\"\\n\") ? `${content}${entry}\\n` : `${content}\\n${entry}\\n`;\n fs.writeFileSync(gitignorePath, newContent);\n\n return { added: true, existed: false };\n }\n}\n","import { z } from \"zod\";\n\n// Kept OUT of `types.ts` on purpose: `types.ts` is imported by `program.ts`,\n// which is on the always-loaded cold-start path of every CLI invocation, and\n// zod costs ~39ms to load. Only the prompt commands need this schema, and\n// they are lazy-loaded behind dynamic imports, so the cost is paid only when\n// a prompt command actually runs.\nexport const localPromptConfigSchema = z\n .object({\n model: z.string().min(1, \"Model is required\"),\n modelParameters: z\n .object({\n temperature: z.number().optional(),\n max_tokens: z.number().optional(),\n })\n .loose()\n .optional(),\n messages: z\n .array(\n z\n .object({\n role: z.enum([\"system\", \"user\", \"assistant\"]),\n content: z.string().min(1, \"Message content cannot be empty\"),\n })\n .loose(),\n )\n .min(1, \"At least one message is required\"),\n parameters: z.record(z.string(), z.unknown()).optional().default({}),\n })\n .loose();\n\nexport type LocalPromptConfig = z.infer<typeof localPromptConfigSchema>;\n","export class PromptFileNotFoundError extends Error {\n constructor(filePath: string) {\n super(`Local prompt file not found: ${filePath}`);\n this.name = 'PromptFileNotFoundError';\n }\n}\n","import type { LocalPromptConfig, PromptDependency } from \"@/cli/types\";\nimport { FileManager } from \"@/cli/utils/fileManager\";\nimport { type Logger, NoOpLogger } from \"@/logger\";\nimport { type PromptData } from \"./types\";\nimport { PromptFileNotFoundError } from \"@/cli/utils/errors/prompt-not-found.error\";\n\nexport interface LocalPromptsServiceConfig {\n fileManager?: typeof FileManager;\n logger?: Logger;\n}\n\n/**\n * Service for retrieving prompts from local filesystem sources.\n *\n * Searches for prompts in the following priority order:\n * 1. Explicit file mapping in prompts.json config\n * 2. Materialized path from prompts-lock.json\n * 3. Direct file scanning in prompts directory\n */\nexport class LocalPromptsService {\n private readonly fileManager: typeof FileManager;\n private readonly logger: Logger;\n\n constructor(config?: LocalPromptsServiceConfig) {\n this.fileManager = config?.fileManager ?? FileManager;\n this.logger = config?.logger ?? new NoOpLogger();\n }\n\n /**\n * Retrieves a prompt using the configured search strategy.\n * Tries each source in priority order until found or all sources exhausted.\n */\n async get(handleOrId: string): Promise<PromptData | null> {\n try {\n const dependency = await this.getDependencyFromConfig(handleOrId);\n\n // If no dependency is found, it means it's not a local prompt\n if (!dependency) {\n return null;\n }\n\n // Try each source in priority order until found or all sources exhausted\n // We catch errors and return null if any of the sources fail so we\n // can continue to the next source and return null if all sources fail\n const localPromptConfig = (\n (await this.getFromConfig(dependency).catch((e) => {\n if (e instanceof PromptFileNotFoundError) return null;\n throw e;\n })) ??\n (await this.getFromLockFile(handleOrId).catch((e) => {\n if (e instanceof PromptFileNotFoundError) return null;\n throw e;\n })) ??\n (await this.getFromLocalFiles(handleOrId).catch((e) => {\n if (e instanceof PromptFileNotFoundError) return null;\n throw e;\n }))\n );\n\n return localPromptConfig ? this.convertToPromptData({\n ...localPromptConfig,\n handle: handleOrId,\n }) : null;\n } catch (error) {\n this.logger.warn(`Failed to get prompt \"${handleOrId}\": ${error instanceof Error ? error.message : String(error)}`);\n return null;\n }\n }\n\n\n /**\n * Searches for prompt using explicit file mapping in prompts.json.\n * Looks for dependencies with a 'file' property pointing to a specific path.\n */\n private async getFromConfig(dependency: PromptDependency): Promise<LocalPromptConfig | null> {\n if (typeof dependency === 'string' && dependency.startsWith('file:')) {\n return this.fileManager.loadLocalPrompt(dependency.slice(5));\n }\n\n return null;\n }\n\n /**\n * Searches for prompt using materialized path from lock file.\n * Lock file contains resolved paths for prompts that have been synced/materialized.\n */\n private async getFromLockFile(handleOrId: string): Promise<LocalPromptConfig | null> {\n const lock = this.fileManager.loadPromptsLock();\n const lockEntry = lock.prompts[handleOrId];\n\n if (lockEntry?.materialized) {\n return this.fileManager.loadLocalPrompt(lockEntry.materialized);\n }\n\n return null;\n }\n\n /**\n * Searches for prompt by scanning all .prompt.yaml files in prompts directory.\n * Extracts prompt name from file path and matches against the requested handle.\n * This is the fallback method when explicit mappings don't exist.\n */\n private async getFromLocalFiles(handleOrId: string): Promise<LocalPromptConfig | null> {\n const localFiles = this.fileManager.getLocalPromptFiles();\n\n for (const filePath of localFiles) {\n const promptName = this.fileManager.promptNameFromPath(filePath);\n if (promptName === handleOrId) {\n return this.fileManager.loadLocalPrompt(filePath);\n }\n }\n\n return null;\n }\n\n /**\n * Get dependency from config\n */\n private async getDependencyFromConfig(handleOrId: string): Promise<PromptDependency | null> {\n const config = this.fileManager.loadPromptsConfig();\n const dependency = config.prompts[handleOrId];\n\n return dependency ?? null;\n }\n\n /**\n * Converts LocalPromptConfig to PromptData format\n */\n private convertToPromptData(config: LocalPromptConfig & { handle: string; }): PromptData {\n const { modelParameters, ...rest } = config;\n return {\n maxTokens: modelParameters?.max_tokens,\n temperature: modelParameters?.temperature,\n ...rest,\n };\n }\n}\n","import { PromptsApiService, type AssignTagResult } from \"./prompts-api.service\";\nimport { Prompt } from \"./prompt\";\nimport type { CreatePromptBody, UpdatePromptBody, PromptData, TagDefinition, CreatedTag } from \"./types\";\nimport { FetchPolicy } from \"./types\";\nimport { type InternalConfig } from \"@/client-sdk/types\";\nimport { LocalPromptsService } from \"./local-prompts.service\";\nimport { PromptsError } from \"./errors\";\n\n/**\n * Options for fetching a prompt.\n */\nexport interface GetPromptOptions {\n /** Specific version to fetch */\n version?: string;\n /** Tag to fetch (e.g., \"production\", \"staging\", or a custom tag) */\n tag?: string;\n /** Fetch policy to use */\n fetchPolicy?: FetchPolicy;\n /** Cache TTL in minutes (only used with CACHE_TTL policy) */\n cacheTtlMinutes?: number;\n}\n\ninterface CacheEntry {\n data: PromptData;\n timestamp: number;\n}\n\ninterface PromptsFacadeDependencies {\n promptsApiService: PromptsApiService;\n localPromptsService: LocalPromptsService;\n}\n\n/**\n * Facade for prompt operations in the LangWatch SDK.\n * Provides a simplified interface for common prompt management tasks.\n */\nexport class PromptsFacade implements Pick<PromptsApiService, \"sync\" | \"delete\">{\n private readonly promptsApiService: PromptsApiService;\n private readonly localPromptsService: LocalPromptsService;\n private readonly cache = new Map<string, CacheEntry>();\n readonly tags: {\n assign(id: string, params: { tag: string; versionId: string }): Promise<AssignTagResult>;\n list(): Promise<TagDefinition[]>;\n create(params: { name: string }): Promise<CreatedTag>;\n delete(tagName: string): Promise<void>;\n rename(oldName: string, newName: string): Promise<void>;\n };\n\n constructor(config: InternalConfig & PromptsFacadeDependencies) {\n this.promptsApiService = config.promptsApiService ?? new PromptsApiService(config);\n this.localPromptsService = config.localPromptsService ?? new LocalPromptsService();\n this.tags = {\n assign: (id, { tag, versionId }) =>\n this.promptsApiService.assignTag({ id, tag, versionId }),\n list: () => this.promptsApiService.listTags(),\n create: ({ name }) => this.promptsApiService.createTag({ name }),\n delete: (tagName) => this.promptsApiService.deleteTag(tagName),\n rename: (oldName, newName) =>\n this.promptsApiService.renameTag({ tag: oldName, name: newName }),\n };\n }\n\n /**\n * Creates a new prompt.\n * @param data The prompt creation payload.\n * @returns The created Prompt instance.\n * @throws {PromptsError} If the API call fails.\n */\n async create(data: CreatePromptBody): Promise<Prompt> {\n const serverPrompt = await this.promptsApiService.create(data);\n return new Prompt(serverPrompt);\n }\n\n /**\n * Retrieves a prompt by handle or ID.\n *\n * Supports shorthand `handle:tag` syntax — e.g. `get(\"pizza-prompt:production\")`.\n * Shorthand is parsed server-side; the SDK passes the string through as-is.\n *\n * @param handleOrId The prompt's handle, unique identifier, or `handle:tag` shorthand.\n * @param options Optional parameters for the request.\n * @returns The Prompt instance.\n * @throws {PromptsError} If the prompt is not found or the API call fails.\n */\n async get(\n handleOrId: string,\n options?: GetPromptOptions,\n ): Promise<Prompt> {\n const fetchPolicy = options?.fetchPolicy ?? FetchPolicy.MATERIALIZED_FIRST;\n\n switch (fetchPolicy) {\n case FetchPolicy.MATERIALIZED_ONLY:\n return this.getMaterializedOnly(handleOrId);\n\n case FetchPolicy.ALWAYS_FETCH:\n return this.getAlwaysFetch(handleOrId, options);\n\n case FetchPolicy.CACHE_TTL:\n return this.getCacheTtl(handleOrId, options);\n\n case FetchPolicy.MATERIALIZED_FIRST:\n default:\n return this.getMaterializedFirst(handleOrId, options);\n }\n }\n\n private async getMaterializedFirst(\n handleOrId: string,\n options?: GetPromptOptions,\n ): Promise<Prompt> {\n const localPrompt = await this.localPromptsService.get(handleOrId);\n if (localPrompt) {\n return new Prompt(localPrompt);\n }\n const serverPrompt = await this.promptsApiService.get(handleOrId, options);\n return new Prompt(serverPrompt);\n }\n\n private async getAlwaysFetch(\n handleOrId: string,\n options?: GetPromptOptions,\n ): Promise<Prompt> {\n try {\n const serverPrompt = await this.promptsApiService.get(handleOrId, options);\n return new Prompt(serverPrompt);\n } catch {\n const localPrompt = await this.localPromptsService.get(handleOrId);\n if (localPrompt) {\n return new Prompt(localPrompt);\n }\n throw new PromptsError(`Prompt \"${handleOrId}\" not found locally or on server`);\n }\n }\n\n private async getMaterializedOnly(handleOrId: string): Promise<Prompt> {\n const localPrompt = await this.localPromptsService.get(handleOrId);\n if (localPrompt) {\n return new Prompt(localPrompt);\n }\n throw new PromptsError(`Prompt \"${handleOrId}\" not found in materialized files`);\n }\n\n private buildCacheKey(handleOrId: string, options?: GetPromptOptions): string {\n const tagSegment = options?.tag != null ? `::tag:${options.tag}` : '';\n return `${handleOrId}::version:${options?.version ?? ''}${tagSegment}`;\n }\n\n private async getCacheTtl(\n handleOrId: string,\n options?: GetPromptOptions,\n ): Promise<Prompt> {\n const cacheKey = this.buildCacheKey(handleOrId, options);\n const ttlMs = (options?.cacheTtlMinutes ?? 5) * 60 * 1000;\n const cached = this.cache.get(cacheKey);\n const now = Date.now();\n\n if (cached && now - cached.timestamp < ttlMs) {\n return new Prompt(cached.data);\n }\n\n try {\n const serverPrompt = await this.promptsApiService.get(handleOrId, options);\n this.cache.set(cacheKey, { data: serverPrompt, timestamp: now });\n return new Prompt(serverPrompt);\n } catch {\n const localPrompt = await this.localPromptsService.get(handleOrId);\n if (localPrompt) {\n return new Prompt(localPrompt);\n }\n throw new PromptsError(`Prompt \"${handleOrId}\" not found locally or on server`);\n }\n }\n\n /**\n * Retrieves all prompts.\n * @returns Array of Prompt instances.\n * @throws {PromptsError} If the API call fails.\n */\n async getAll(): Promise<Prompt[]> {\n const serverPrompts = await this.promptsApiService.getAll();\n return serverPrompts.map((prompt) => new Prompt(prompt));\n }\n\n /**\n * Updates an existing prompt.\n * @param handleOrId The prompt's handle or unique identifier.\n * @param newData The update payload.\n * @returns The updated Prompt instance.\n * @throws {PromptsError} If the API call fails.\n */\n async update(handleOrId: string, newData: UpdatePromptBody): Promise<Prompt> {\n const serverPrompt = await this.promptsApiService.update(handleOrId, newData);\n return new Prompt(serverPrompt);\n }\n\n get delete() {\n return this.promptsApiService.delete.bind(this.promptsApiService);\n }\n\n /**\n * Delegated method to the prompts API service.\n */\n get sync() {\n return this.promptsApiService.sync.bind(this.promptsApiService);\n }\n}\n","/**\n * Errors for the Dataset API\n */\n\n/**\n * Base error for all dataset operations.\n */\nexport class DatasetError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"DatasetError\";\n }\n}\n\n/**\n * Thrown when a dataset is not found (404).\n */\nexport class DatasetNotFoundError extends DatasetError {\n constructor(slugOrId: string) {\n super(`Dataset not found: ${slugOrId}`);\n this.name = \"DatasetNotFoundError\";\n }\n}\n\n/**\n * Error from the Dataset API with operation context.\n * Aligns with PromptsApiError pattern: includes operation and originalError fields.\n */\nexport class DatasetApiError extends DatasetError {\n readonly status: number;\n readonly operation: string;\n readonly originalError?: unknown;\n\n constructor(message: string, status: number, operation: string, originalError?: unknown) {\n super(message);\n this.name = \"DatasetApiError\";\n this.status = status;\n this.operation = operation;\n this.originalError = originalError;\n }\n}\n\n/**\n * Thrown for client-side validation failures (e.g. empty name, no update fields, empty entries).\n * Distinguished from DatasetApiError which represents server-side errors.\n */\nexport class DatasetValidationError extends DatasetError {\n constructor(message: string) {\n super(message);\n this.name = \"DatasetValidationError\";\n }\n}\n\n/**\n * Thrown when a dataset operation exceeds the plan limit (403).\n * The message includes the upgrade/subscription URL from the server.\n */\nexport class DatasetPlanLimitError extends DatasetError {\n readonly limitType: string;\n readonly current?: number;\n readonly max?: number;\n\n constructor(message: string, originalError?: unknown) {\n super(message);\n this.name = \"DatasetPlanLimitError\";\n\n if (originalError != null && typeof originalError === \"object\") {\n const err = originalError as Record<string, unknown>;\n this.limitType = typeof err.limitType === \"string\" ? err.limitType : \"datasets\";\n this.current = typeof err.current === \"number\" ? err.current : undefined;\n this.max = typeof err.max === \"number\" ? err.max : undefined;\n } else {\n this.limitType = \"datasets\";\n }\n }\n}\n","import { LANGWATCH_SDK_NAME_CLIENT, LANGWATCH_SDK_VERSION } from \"@/internal/constants\";\nimport { getLangWatchTracer } from \"@/observability-sdk/tracer\";\n\nexport const tracer = getLangWatchTracer(`${LANGWATCH_SDK_NAME_CLIENT}.datasets`, LANGWATCH_SDK_VERSION);\n","import { type LangwatchApiClient } from \"@/internal/api/client\";\nimport { isLangWatchHandledError } from \"@/internal/api/errors\";\nimport { type Logger } from \"@/logger\";\nimport {\n type Dataset,\n type DatasetEntry,\n type DatasetMetadata,\n type GetDatasetApiResponse,\n type GetDatasetOptions,\n type ListDatasetsOptions,\n type ListDatasetsApiResponse,\n type ListRecordsOptions,\n type ListRecordsApiResponse,\n type CreateDatasetOptions,\n type UpdateDatasetOptions,\n type CreateFromUploadOptions,\n type CreateFromUploadResponse,\n type BatchCreateRecordsResponse,\n type DeleteRecordsResponse,\n type UploadResponse,\n type DatasetRecordResponse,\n} from \"./types\";\nimport { DatasetApiError, DatasetNotFoundError, DatasetPlanLimitError } from \"./errors\";\nimport { createTracingProxy } from \"@/client-sdk/tracing/create-tracing-proxy\";\nimport { tracer } from \"./tracing\";\nimport { formatApiErrorMessage } from \"@/client-sdk/services/_shared/format-api-error\";\nimport { buildAuthHeaders } from \"@/internal/api/auth\";\n\ntype DatasetServiceConfig = {\n langwatchApiClient: LangwatchApiClient;\n logger: Logger;\n endpoint: string;\n apiKey: string;\n};\n\n/**\n * Service for managing dataset resources via the LangWatch API.\n *\n * Responsibilities:\n * - CRUD operations for datasets\n * - Record management (create, update, delete)\n * - File upload\n * - Error handling with contextual information\n */\nexport class DatasetService {\n private readonly config: DatasetServiceConfig;\n\n constructor(config: DatasetServiceConfig) {\n this.config = config;\n\n /**\n * Wraps the service in a tracing proxy that automatically creates\n * OpenTelemetry spans for all public methods.\n */\n return createTracingProxy(this as DatasetService, tracer);\n }\n\n /**\n * Handles API errors by mapping status codes to appropriate error types.\n * @param operation - Description of the operation being performed\n * @param error - The error object from the API response\n * @param status - The HTTP status code\n * @param slugOrId - The dataset identifier (only passed for operations targeting an existing resource)\n */\n private handleApiError(operation: string, error: unknown, status: number, slugOrId?: string): never {\n if (status === 404 && slugOrId) {\n throw new DatasetNotFoundError(slugOrId);\n }\n\n if (status === 403) {\n const errorMessage = this.extractErrorMessage(error, status);\n throw new DatasetPlanLimitError(errorMessage, error);\n }\n\n const errorMessage = this.extractErrorMessage(error, status);\n\n // NO handled-error throw here, deliberately.\n //\n // Datasets is the one service that already HAS a typed error taxonomy —\n // `DatasetNotFoundError`, `DatasetPlanLimitError`, and a `DatasetApiError`\n // that carries the status — and all three are public API that callers catch\n // by class. Raising a `LangWatchHandledError` in their place would be a\n // breaking change dressed up as an improvement (a 409 would stop being a\n // `DatasetApiError`), so this service keeps its own classes and the\n // transport's throw is folded back into them by `asResponseEnvelope` above.\n //\n // Nothing is lost at the surface that matters: `DatasetApiError` keeps the\n // raw body on `originalError`, so the CLI still reads the platform's `kind`\n // back off it and still prints a typed `--format json` document.\n throw new DatasetApiError(\n `Failed to ${operation}: ${errorMessage}`,\n status,\n operation,\n error,\n );\n }\n\n /**\n * Extracts a human-readable error message from an API error response.\n */\n private extractErrorMessage(error: unknown, status: number): string {\n return formatApiErrorMessage({ error: error, options: { status } });\n }\n\n /**\n * Wrapper for API calls to endpoints not yet in the generated OpenAPI types.\n * Quarantines `as any` casts to a single location.\n */\n private async untypedRequest<M extends 'GET' | 'POST' | 'PATCH' | 'DELETE'>(\n method: M,\n path: string,\n options?: Record<string, unknown>,\n ) {\n return this.asResponseEnvelope(\n (this.config.langwatchApiClient[method] as any)(path, options),\n );\n }\n\n /**\n * Puts a transport-thrown domain error back into the `{ error, response }`\n * envelope this service reads.\n *\n * The HTTP client now THROWS a typed domain error on a named failure, before\n * any service sees the response. Datasets is the one service that must not\n * receive it: it maps failures onto error classes of its own —\n * `DatasetNotFoundError`, `DatasetPlanLimitError`, `DatasetApiError` — and all\n * three are public API that callers catch by class. A typed throw arriving\n * first would silently take their place, which is a breaking change however\n * good the intention.\n *\n * So the throw is caught here and handed back as the envelope it would have\n * been, `unwrapResponse` runs exactly as it always has, and every dataset\n * error class survives untouched. This service is deliberately EXACTLY as it\n * was; the transport change is invisible to it.\n */\n private async asResponseEnvelope(\n request: Promise<{ data?: unknown; error?: unknown; response: { status: number } }>,\n ): Promise<{ data?: unknown; error?: unknown; response: { status: number } }> {\n try {\n return await request;\n } catch (error) {\n if (isLangWatchHandledError(error)) {\n return { error: error.body, response: { status: error.httpStatus } };\n }\n throw error;\n }\n }\n\n /**\n * Unwraps an API response, throwing a mapped error if the response contains an error.\n * Centralizes the repeated `if (error) handleApiError; return data` pattern.\n */\n private unwrapResponse<T>(\n response: { data?: unknown; error?: unknown; response: { status: number } },\n operation: string,\n slugOrId?: string,\n ): T {\n if (response.error) {\n this.handleApiError(operation, response.error, response.response.status, slugOrId);\n }\n return response.data as T;\n }\n\n /**\n * Fetches a dataset by its slug or ID, returning metadata and entries.\n *\n * @param slugOrId - The slug or ID of the dataset\n * @param _options - Optional configuration\n * @returns The dataset with metadata and entries\n */\n async getDataset<T extends Record<string, unknown> = Record<string, unknown>>(\n slugOrId: string,\n _options?: GetDatasetOptions\n ): Promise<Dataset<T>> {\n this.config.logger.debug(`Fetching dataset: ${slugOrId}`);\n\n const response = await this.asResponseEnvelope(\n this.config.langwatchApiClient.GET(\"/api/dataset/{slugOrId}\", {\n params: {\n path: {\n slugOrId,\n },\n },\n }) as Promise<{ data?: unknown; error?: unknown; response: { status: number } }>,\n );\n\n const data = this.unwrapResponse<GetDatasetApiResponse>(\n response,\n `fetch dataset \"${slugOrId}\"`,\n slugOrId,\n );\n\n const entries: DatasetEntry<T>[] = data.data.map((item) => ({\n id: item.id,\n datasetId: item.datasetId,\n projectId: item.projectId,\n entry: item.entry as T,\n createdAt: item.createdAt,\n updatedAt: item.updatedAt,\n }));\n\n this.config.logger.debug(\n `Fetched dataset ${slugOrId} with ${entries.length} entries`\n );\n\n return {\n id: data.id,\n name: data.name,\n slug: data.slug,\n columnTypes: data.columnTypes,\n createdAt: data.createdAt,\n updatedAt: data.updatedAt,\n entries,\n };\n }\n\n /**\n * Lists all datasets for the project, with optional pagination.\n */\n async listDatasets(options?: ListDatasetsOptions): Promise<ListDatasetsApiResponse> {\n this.config.logger.debug(\"Listing datasets\");\n\n const response = await this.untypedRequest('GET', '/api/dataset', {\n params: {\n query: {\n page: options?.page,\n limit: options?.limit,\n },\n },\n });\n\n return this.unwrapResponse<ListDatasetsApiResponse>(\n response,\n \"list datasets\",\n );\n }\n\n /**\n * Creates a new dataset.\n */\n async createDataset(options: CreateDatasetOptions): Promise<DatasetMetadata> {\n this.config.logger.debug(`Creating dataset: ${options.name}`);\n\n const response = await this.untypedRequest('POST', '/api/dataset', {\n body: {\n name: options.name,\n columnTypes: options.columnTypes ?? [],\n },\n });\n\n return this.unwrapResponse<DatasetMetadata>(\n response,\n `create dataset \"${options.name}\"`,\n );\n }\n\n /**\n * Updates a dataset by its slug or ID.\n */\n async updateDataset(slugOrId: string, options: UpdateDatasetOptions): Promise<DatasetMetadata> {\n this.config.logger.debug(`Updating dataset: ${slugOrId}`);\n\n const response = await this.untypedRequest('PATCH', '/api/dataset/{slugOrId}', {\n params: {\n path: { slugOrId },\n },\n body: options,\n });\n\n return this.unwrapResponse<DatasetMetadata>(\n response,\n `update dataset \"${slugOrId}\"`,\n slugOrId,\n );\n }\n\n /**\n * Deletes (archives) a dataset by its slug or ID.\n */\n async deleteDataset(slugOrId: string): Promise<DatasetMetadata> {\n this.config.logger.debug(`Deleting dataset: ${slugOrId}`);\n\n const response = await this.untypedRequest('DELETE', '/api/dataset/{slugOrId}', {\n params: {\n path: { slugOrId },\n },\n });\n\n return this.unwrapResponse<DatasetMetadata>(\n response,\n `delete dataset \"${slugOrId}\"`,\n slugOrId,\n );\n }\n\n /**\n * Creates records in a dataset in batch.\n */\n async createRecords(\n slugOrId: string,\n entries: Record<string, unknown>[],\n ): Promise<BatchCreateRecordsResponse> {\n this.config.logger.debug(`Creating ${entries.length} records in dataset: ${slugOrId}`);\n\n const response = await this.untypedRequest('POST', '/api/dataset/{slugOrId}/records', {\n params: {\n path: { slugOrId },\n },\n body: { entries },\n });\n\n return this.unwrapResponse<BatchCreateRecordsResponse>(\n response,\n `create records in dataset \"${slugOrId}\"`,\n slugOrId,\n );\n }\n\n /**\n * Updates a single record in a dataset.\n */\n async updateRecord(\n slugOrId: string,\n recordId: string,\n entry: Record<string, unknown>,\n ): Promise<DatasetRecordResponse> {\n this.config.logger.debug(`Updating record ${recordId} in dataset: ${slugOrId}`);\n\n const response = await this.untypedRequest('PATCH', '/api/dataset/{slugOrId}/records/{recordId}', {\n params: {\n path: { slugOrId, recordId },\n },\n body: { entry },\n });\n\n return this.unwrapResponse<DatasetRecordResponse>(\n response,\n `update record \"${recordId}\" in dataset \"${slugOrId}\"`,\n slugOrId,\n );\n }\n\n /**\n * Deletes records from a dataset by IDs.\n */\n async deleteRecords(\n slugOrId: string,\n recordIds: string[],\n ): Promise<DeleteRecordsResponse> {\n this.config.logger.debug(`Deleting ${recordIds.length} records from dataset: ${slugOrId}`);\n\n const response = await this.untypedRequest('DELETE', '/api/dataset/{slugOrId}/records', {\n params: {\n path: { slugOrId },\n },\n body: { recordIds },\n });\n\n return this.unwrapResponse<DeleteRecordsResponse>(\n response,\n `delete records from dataset \"${slugOrId}\"`,\n slugOrId,\n );\n }\n\n /**\n * Lists records in a dataset with optional pagination.\n *\n * @param slugOrId - The slug or ID of the dataset\n * @param options - Pagination options (page, limit)\n * @returns Paginated list of records\n */\n async listRecords(\n slugOrId: string,\n options?: ListRecordsOptions,\n ): Promise<ListRecordsApiResponse> {\n this.config.logger.debug(`Listing records for dataset: ${slugOrId}`);\n\n const response = await this.untypedRequest('GET', '/api/dataset/{slugOrId}/records', {\n params: {\n path: { slugOrId },\n query: {\n page: options?.page,\n limit: options?.limit,\n },\n },\n });\n\n return this.unwrapResponse<ListRecordsApiResponse>(\n response,\n `list records in dataset \"${slugOrId}\"`,\n slugOrId,\n );\n }\n\n /**\n * Sends a multipart/form-data request using raw fetch.\n * openapi-fetch hardcodes content-type: application/json, so file uploads\n * must bypass it. This helper centralizes URL building, auth headers,\n * error parsing, and response unwrapping.\n *\n * @param path - The API path (appended to the endpoint)\n * @param formData - The FormData payload\n * @param operation - Human-readable operation name for error messages\n * @param slugOrId - Optional dataset identifier (passed to handleApiError for 404 mapping)\n */\n private async fetchMultipart<T>(\n path: string,\n formData: FormData,\n operation: string,\n slugOrId?: string,\n ): Promise<T> {\n const { endpoint, apiKey } = this.config;\n const url = `${endpoint.replace(/\\/$/, \"\")}${path}`;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: buildAuthHeaders({ apiKey }),\n body: formData,\n });\n\n if (!response.ok) {\n const rawBody = await response.text();\n let errorBody: unknown = rawBody;\n if (rawBody) {\n try {\n errorBody = JSON.parse(rawBody);\n } catch {\n // Keep the plain-text body.\n }\n }\n\n this.handleApiError(operation, errorBody, response.status, slugOrId);\n }\n\n return (await response.json()) as T;\n }\n\n /**\n * Creates a new dataset from a file upload.\n *\n * @param options - The dataset name and file to upload\n * @returns The created dataset metadata with record count\n */\n async createDatasetFromUpload(\n options: CreateFromUploadOptions,\n ): Promise<CreateFromUploadResponse> {\n this.config.logger.debug(`Creating dataset from upload: ${options.name}`);\n\n const formData = new FormData();\n formData.append(\"name\", options.name);\n formData.append(\"file\", options.file);\n\n return this.fetchMultipart<CreateFromUploadResponse>(\n \"/api/dataset/upload\",\n formData,\n `create dataset from upload \"${options.name}\"`,\n );\n }\n\n /**\n * Uploads a file with a strategy for handling existing datasets.\n *\n * @param slugOrId - The slug or ID of the dataset\n * @param file - The file to upload (File or Blob)\n * @param ifExists - Strategy when dataset exists: \"append\" (default), \"replace\", or \"error\"\n * @returns The upload result\n */\n async uploadWithStrategy(\n slugOrId: string,\n file: File | Blob,\n ifExists: \"append\" | \"replace\" | \"error\" = \"append\",\n ): Promise<UploadResponse> {\n switch (ifExists) {\n case \"append\":\n return this._uploadAppend(slugOrId, file);\n case \"replace\":\n return this._uploadReplace(slugOrId, file);\n case \"error\":\n return this._uploadError(slugOrId, file);\n }\n }\n\n /**\n * Converts a CreateFromUploadResponse to the unified UploadResponse shape.\n */\n private toUploadResponse(result: CreateFromUploadResponse): UploadResponse {\n return {\n dataset: {\n id: result.id,\n name: result.name,\n slug: result.slug,\n columnTypes: result.columnTypes,\n createdAt: result.createdAt,\n updatedAt: result.updatedAt,\n },\n recordsCreated: result.recordsCreated,\n datasetId: result.id,\n };\n }\n\n /**\n * Append strategy: try uploading to existing dataset; if not found, create from file.\n */\n private async _uploadAppend(slugOrId: string, file: File | Blob): Promise<UploadResponse> {\n try {\n return await this.uploadFile(slugOrId, file);\n } catch (error) {\n if (error instanceof DatasetNotFoundError) {\n return this.toUploadResponse(await this.createDatasetFromUpload({ name: slugOrId, file }));\n }\n throw error;\n }\n }\n\n /**\n * Replace strategy: if dataset exists, delete all records then upload; if not found, create from file.\n */\n private async _uploadReplace(slugOrId: string, file: File | Blob): Promise<UploadResponse> {\n try {\n await this.getDataset(slugOrId);\n await this._deleteAllRecords(slugOrId);\n return await this.uploadFile(slugOrId, file);\n } catch (error) {\n if (error instanceof DatasetNotFoundError) {\n return this.toUploadResponse(await this.createDatasetFromUpload({ name: slugOrId, file }));\n }\n throw error;\n }\n }\n\n /**\n * Error strategy: if dataset exists, throw 409; if not found, create from file.\n */\n private async _uploadError(slugOrId: string, file: File | Blob): Promise<UploadResponse> {\n let datasetExists = false;\n try {\n await this.getDataset(slugOrId);\n datasetExists = true;\n } catch (error) {\n if (!(error instanceof DatasetNotFoundError)) {\n throw error;\n }\n }\n\n if (datasetExists) {\n throw new DatasetApiError(\n `Dataset already exists: ${slugOrId}`,\n 409,\n \"upload\",\n );\n }\n\n return this.toUploadResponse(await this.createDatasetFromUpload({ name: slugOrId, file }));\n }\n\n /**\n * Deletes all records from a dataset by iterating through pages.\n * Always fetches page 1 since records shift after deletion.\n * Includes a safety valve to prevent infinite loops.\n */\n private async _deleteAllRecords(slugOrId: string): Promise<void> {\n const BATCH_SIZE = 1000;\n const MAX_DELETE_ITERATIONS = 100;\n\n let iteration = 0;\n while (iteration < MAX_DELETE_ITERATIONS) {\n const page = await this.listRecords(slugOrId, { page: 1, limit: BATCH_SIZE });\n if (page.data.length === 0) {\n return;\n }\n\n const ids = page.data.map((record) => record.id);\n await this.deleteRecords(slugOrId, ids);\n iteration++;\n }\n\n throw new DatasetApiError(\n `Failed to delete all records from dataset \"${slugOrId}\": exceeded ${MAX_DELETE_ITERATIONS} iterations`,\n 0,\n `delete all records from dataset \"${slugOrId}\"`,\n );\n }\n\n /**\n * Uploads a file to an existing dataset.\n */\n async uploadFile(\n slugOrId: string,\n file: File | Blob,\n ): Promise<UploadResponse> {\n this.config.logger.debug(`Uploading file to dataset: ${slugOrId}`);\n\n const formData = new FormData();\n formData.append(\"file\", file);\n\n return this.fetchMultipart<UploadResponse>(\n `/api/dataset/${encodeURIComponent(slugOrId)}/upload`,\n formData,\n `upload file to dataset \"${slugOrId}\"`,\n slugOrId,\n );\n }\n}\n","import { type LangwatchApiClient } from \"@/internal/api/client\";\nimport { type Logger } from \"@/logger\";\nimport { DatasetService } from \"./dataset.service\";\nimport { DatasetValidationError } from \"./errors\";\nimport {\n type Dataset,\n type DatasetMetadata,\n type GetDatasetOptions,\n type ListDatasetsOptions,\n type ListDatasetsApiResponse,\n type ListRecordsOptions,\n type ListRecordsApiResponse,\n type CreateDatasetOptions,\n type UpdateDatasetOptions,\n type BatchCreateRecordsResponse,\n type DeleteRecordsResponse,\n type UploadResponse,\n type DatasetRecordResponse,\n} from \"./types\";\n\ntype DatasetsFacadeConfig = {\n langwatchApiClient: LangwatchApiClient;\n logger: Logger;\n endpoint: string;\n apiKey: string;\n};\n\n/**\n * Facade for dataset operations in the LangWatch SDK.\n * Provides a simplified interface for managing datasets, records, and file uploads.\n *\n * @example\n * ```typescript\n * const langwatch = new LangWatch({ apiKey: \"your-api-key\" });\n *\n * // List all datasets\n * const datasets = await langwatch.datasets.list();\n *\n * // Get a dataset by slug or ID\n * const dataset = await langwatch.datasets.get(\"my-dataset\");\n *\n * // Create a new dataset\n * const newDataset = await langwatch.datasets.create({\n * name: \"my-dataset\",\n * columnTypes: [{ name: \"input\", type: \"string\" }],\n * });\n *\n * // Update a dataset\n * const updated = await langwatch.datasets.update(\"my-dataset\", { name: \"new-name\" });\n *\n * // Delete a dataset\n * const archived = await langwatch.datasets.delete(\"my-dataset\");\n *\n * // Create records\n * const records = await langwatch.datasets.createRecords(\"my-dataset\", [\n * { input: \"hello\", output: \"world\" },\n * ]);\n *\n * // Update a record\n * const record = await langwatch.datasets.updateRecord(\"my-dataset\", \"rec-1\", { input: \"updated\" });\n *\n * // Delete records\n * const result = await langwatch.datasets.deleteRecords(\"my-dataset\", [\"rec-1\", \"rec-2\"]);\n *\n * // Upload a file (append to existing or create new)\n * const uploadResult = await langwatch.datasets.upload(\"my-dataset\", file);\n *\n * // Upload with replace strategy (delete all records first)\n * await langwatch.datasets.upload(\"my-dataset\", file, { ifExists: \"replace\" });\n * ```\n */\nexport class DatasetsFacade {\n readonly #datasetService: DatasetService;\n\n constructor(config: DatasetsFacadeConfig) {\n this.#datasetService = new DatasetService(config);\n }\n\n /**\n * Lists all datasets for the project, with optional pagination.\n *\n * @param options - Pagination options (page, limit)\n * @returns Paginated list of datasets with metadata\n */\n list = (options?: ListDatasetsOptions): Promise<ListDatasetsApiResponse> => {\n return this.#datasetService.listDatasets(options);\n };\n\n /**\n * Creates a new dataset.\n *\n * @param options - Dataset creation options (name, columnTypes)\n * @returns The created dataset metadata\n */\n create = (options: CreateDatasetOptions): Promise<DatasetMetadata> => {\n if (!options.name || options.name.trim().length === 0) {\n throw new DatasetValidationError(\"Dataset name must not be empty\");\n }\n return this.#datasetService.createDataset(options);\n };\n\n /**\n * Fetches a dataset by its slug or ID, returning metadata and entries.\n *\n * @param slugOrId - The slug or ID of the dataset to fetch\n * @param options - Optional configuration\n * @returns The dataset with metadata and entries\n *\n * @example\n * ```typescript\n * // Get dataset by slug\n * const dataset = await langwatch.datasets.get(\"product-qa\");\n *\n * // Typed dataset\n * type MyDatasetEntry = { input: string; expected_output: string; };\n * const dataset = await langwatch.datasets.get<MyDatasetEntry>(\"my-dataset\");\n *\n * // Iterate over entries\n * for (const entry of dataset.entries) {\n * console.log(entry.entry.input);\n * }\n * ```\n */\n get = <T extends Record<string, unknown> = Record<string, unknown>>(\n slugOrId: string,\n options?: GetDatasetOptions\n ): Promise<Dataset<T>> => {\n return this.#datasetService.getDataset<T>(slugOrId, options);\n };\n\n /**\n * Updates a dataset by its slug or ID.\n *\n * @param slugOrId - The slug or ID of the dataset to update\n * @param options - Fields to update (name, columnTypes)\n * @returns The updated dataset metadata\n */\n update = (slugOrId: string, options: UpdateDatasetOptions): Promise<DatasetMetadata> => {\n if (options.name == null && options.columnTypes == null) {\n throw new DatasetValidationError(\n \"At least one field (name or columnTypes) must be provided for update\",\n );\n }\n return this.#datasetService.updateDataset(slugOrId, options);\n };\n\n /**\n * Deletes (archives) a dataset by its slug or ID.\n *\n * @param slugOrId - The slug or ID of the dataset to delete\n * @returns The archived dataset metadata\n */\n delete = (slugOrId: string): Promise<DatasetMetadata> => {\n return this.#datasetService.deleteDataset(slugOrId);\n };\n\n /**\n * Creates records in a dataset in batch.\n *\n * @param slugOrId - The slug or ID of the dataset\n * @param entries - Array of record entries to create\n * @returns The created records with IDs\n */\n createRecords = (\n slugOrId: string,\n entries: Record<string, unknown>[],\n ): Promise<BatchCreateRecordsResponse> => {\n if (!entries || entries.length === 0) {\n throw new DatasetValidationError(\"Entries must not be empty\");\n }\n return this.#datasetService.createRecords(slugOrId, entries);\n };\n\n /**\n * Updates a single record in a dataset.\n *\n * @param slugOrId - The slug or ID of the dataset\n * @param recordId - The ID of the record to update\n * @param entry - The updated entry data\n * @returns The updated record\n */\n updateRecord = (\n slugOrId: string,\n recordId: string,\n entry: Record<string, unknown>,\n ): Promise<DatasetRecordResponse> => {\n return this.#datasetService.updateRecord(slugOrId, recordId, entry);\n };\n\n /**\n * Deletes records from a dataset by IDs.\n *\n * @param slugOrId - The slug or ID of the dataset\n * @param recordIds - Array of record IDs to delete\n * @returns Object with the count of deleted records\n */\n deleteRecords = (\n slugOrId: string,\n recordIds: string[],\n ): Promise<DeleteRecordsResponse> => {\n return this.#datasetService.deleteRecords(slugOrId, recordIds);\n };\n\n /**\n * Lists records in a dataset with optional pagination.\n *\n * @param slugOrId - The slug or ID of the dataset\n * @param options - Pagination options (page, limit)\n * @returns Paginated list of records\n *\n * @example\n * ```typescript\n * // List first page of records\n * const result = await langwatch.datasets.listRecords(\"my-dataset\");\n *\n * // With pagination\n * const page2 = await langwatch.datasets.listRecords(\"my-dataset\", { page: 2, limit: 25 });\n * ```\n */\n listRecords = (\n slugOrId: string,\n options?: ListRecordsOptions,\n ): Promise<ListRecordsApiResponse> => {\n return this.#datasetService.listRecords(slugOrId, options);\n };\n\n /**\n * Uploads a file to a dataset with a configurable strategy for handling existing datasets.\n *\n * Strategies:\n * - `\"append\"` (default): Upload to existing dataset; if not found, create a new one.\n * - `\"replace\"`: Delete all existing records, then upload; if not found, create a new one.\n * - `\"error\"`: Throw a 409 error if the dataset already exists; if not found, create a new one.\n *\n * @param slugOrId - The slug or ID of the dataset\n * @param file - The file to upload (File or Blob)\n * @param options - Upload options including the ifExists strategy\n * @returns The upload result\n *\n * @example\n * ```typescript\n * const file = new File([\"input,output\\nhello,world\"], \"data.csv\", { type: \"text/csv\" });\n *\n * // Append to existing or create new\n * await langwatch.datasets.upload(\"my-dataset\", file);\n *\n * // Replace all records\n * await langwatch.datasets.upload(\"my-dataset\", file, { ifExists: \"replace\" });\n *\n * // Fail if dataset already exists\n * await langwatch.datasets.upload(\"my-dataset\", file, { ifExists: \"error\" });\n * ```\n */\n upload = (\n slugOrId: string,\n file: File | Blob,\n options?: {\n ifExists?: \"append\" | \"replace\" | \"error\";\n },\n ): Promise<UploadResponse> => {\n if (!file) {\n throw new DatasetValidationError(\"File must be provided for upload\");\n }\n return this.#datasetService.uploadWithStrategy(\n slugOrId,\n file,\n options?.ifExists ?? \"append\",\n );\n };\n}\n","/**\n * Experiment - Main class for running batch experiments\n *\n * Provides a clean API for running experiments over datasets with:\n * - Automatic tracing per iteration\n * - Parallel execution with concurrency control\n * - Batched result sending\n * - Built-in evaluator support\n * - Multi-target comparison with withTarget() context isolation\n */\n\nimport { AsyncLocalStorage } from \"node:async_hooks\";\nimport { trace, SpanStatusCode, ROOT_CONTEXT } from \"@opentelemetry/api\";\nimport { createLangWatchSpan } from \"@/observability-sdk/span/implementation\";\nimport type { LangWatchSpan } from \"@/observability-sdk/span/types\";\nimport type { LangwatchApiClient } from \"@/internal/api/client\";\nimport type { Logger } from \"@/logger\";\nimport { ensureSetup } from \"@/observability-sdk/setup/node\";\nimport { generateHumanReadableId } from \"./humanReadableId\";\nimport {\n ExperimentInitError,\n TargetMetadataConflictError,\n EvaluatorError,\n} from \"./errors\";\nimport type {\n Batch,\n BatchEntry,\n EvaluationResult,\n TargetInfo,\n TargetMetadata,\n ExperimentInitOptions,\n LogOptions,\n EvaluateOptions,\n RunOptions,\n RunCallback,\n RunContext,\n ExperimentInitResponse,\n LogResultsRequest,\n RunEvaluatorResponse,\n TargetCallback,\n TargetResult,\n TargetExecutionContext,\n TargetContext,\n} from \"./types\";\nimport { printSummary } from \"./printSummary\";\nimport { buildAuthHeaders } from \"@/internal/api/auth\";\n\nconst DEFAULT_CONCURRENCY = 4;\nconst DEBOUNCE_INTERVAL_MS = 1000;\n\n// Slim projections retained across the lifetime of an Experiment for\n// printSummary() — deliberately excludes large fields (inputs, tracebacks,\n// outputs) so running thousands of items doesn't unbound memory.\ntype SummaryEvaluation = Pick<\n EvaluationResult,\n \"name\" | \"evaluator\" | \"status\" | \"passed\" | \"score\" | \"cost\" | \"target_id\"\n>;\ntype SummaryEntry = Pick<BatchEntry, \"duration\" | \"error\" | \"cost\" | \"target_id\">;\n\n/**\n * AsyncLocalStorage for iteration context isolation.\n * This stores the current item and index for each iteration,\n * preventing race conditions in concurrent execution.\n */\ntype IterationContext = {\n index: number;\n item: unknown;\n};\nconst iterationContextStorage = new AsyncLocalStorage<IterationContext>();\n\n/**\n * AsyncLocalStorage for target context isolation.\n * This allows log() calls inside withTarget() to automatically\n * infer the target without explicit specification.\n */\nconst targetContextStorage = new AsyncLocalStorage<TargetExecutionContext>();\n\n/**\n * Experiment session for running batch experiments\n */\nexport class Experiment {\n readonly name: string;\n readonly runId: string;\n readonly experimentSlug: string;\n\n private readonly apiClient: LangwatchApiClient;\n private readonly endpoint: string;\n private readonly apiKey: string;\n private readonly logger: Logger;\n private readonly concurrency: number;\n\n private initialized = false;\n private createdAtMs: number;\n private total = 0;\n private progress = 0;\n\n // Batching state\n private batch: Batch = { dataset: [], evaluations: [], targets: [] };\n private lastSentMs = 0;\n private pendingFlush: Promise<void> | null = null;\n private flushTimeout: ReturnType<typeof setTimeout> | null = null;\n\n // Cumulative record for printSummary() — never cleared, mirrors batch.\n // Store only the fields printSummary() needs, not the full payloads —\n // inputs/tracebacks/outputs can be large and don't belong in retained summary state.\n private cumulativeEvaluations: SummaryEvaluation[] = [];\n private cumulativeEntries: SummaryEntry[] = [];\n private runUrl = \"\";\n\n // Target registry\n private targets = new Map<string, TargetInfo>();\n\n // Current iteration context (for log/evaluate calls)\n private currentTraceId: string | null = null;\n private currentIndex: number | null = null;\n\n // Track whether withTarget() was used in the current iteration\n // If so, we don't create dataset entries in executeItem()\n // Note: This is now checked via iterationContextStorage to be thread-safe\n private iterationUsedWithTarget = new Map<number, boolean>();\n\n // Track whether withTarget() has EVER been used in this evaluation\n // Once set to true, we stop creating iteration-level traces\n private evaluationUsesTargets = false;\n\n private constructor(\n name: string,\n options: {\n apiClient: LangwatchApiClient;\n endpoint: string;\n apiKey: string;\n logger: Logger;\n runId?: string;\n concurrency?: number;\n }\n ) {\n this.name = name;\n this.experimentSlug = name;\n this.runId = options.runId ?? generateHumanReadableId();\n this.apiClient = options.apiClient;\n this.endpoint = options.endpoint;\n this.apiKey = options.apiKey;\n this.logger = options.logger;\n this.concurrency = options.concurrency ?? DEFAULT_CONCURRENCY;\n this.createdAtMs = Date.now();\n }\n\n /**\n * Initialize an evaluation session\n */\n static async init(\n name: string,\n options: {\n apiClient: LangwatchApiClient;\n endpoint: string;\n apiKey: string;\n logger: Logger;\n } & ExperimentInitOptions\n ): Promise<Experiment> {\n // Ensure observability is set up for proper tracing\n ensureSetup();\n\n const experiment = new Experiment(name, options);\n await experiment.initialize();\n return experiment;\n }\n\n /**\n * Initialize the evaluation by creating/getting the experiment\n */\n private async initialize(): Promise<void> {\n if (!this.apiKey) {\n throw new ExperimentInitError(\n \"API key is required. Set LANGWATCH_API_KEY or pass apiKey to LangWatch constructor.\"\n );\n }\n\n try {\n const response = await fetch(`${this.endpoint}/api/experiment/init`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...buildAuthHeaders({ apiKey: this.apiKey }),\n },\n body: JSON.stringify({\n experiment_name: this.name,\n experiment_slug: this.experimentSlug,\n experiment_type: \"BATCH_EVALUATION_V2\",\n }),\n });\n\n if (response.status === 401) {\n throw new ExperimentInitError(\"Invalid API key\");\n }\n\n if (!response.ok) {\n const text = await response.text();\n throw new ExperimentInitError(`Failed to initialize experiment: ${text}`);\n }\n\n const data = (await response.json()) as ExperimentInitResponse;\n (this as { experimentSlug: string }).experimentSlug = data.slug;\n\n const encodedRunId = encodeURIComponent(this.runId);\n this.runUrl = `${this.endpoint.replace(/\\/$/, \"\")}${data.path}?runId=${encodedRunId}`;\n console.log(`Follow results at: ${this.runUrl}`);\n\n this.initialized = true;\n } catch (error) {\n if (error instanceof ExperimentInitError) {\n throw error;\n }\n throw new ExperimentInitError(\n `Failed to initialize evaluation: ${error instanceof Error ? error.message : String(error)}`,\n error instanceof Error ? error : undefined\n );\n }\n }\n\n /**\n * Run evaluation over a dataset with a callback\n *\n * @param dataset - Array of items to evaluate\n * @param callback - Function called for each item with { item, index, span }\n * @param options - Concurrency options\n *\n * @example\n * ```typescript\n * await evaluation.run(dataset, async ({ item, index, span }) => {\n * const response = await myAgent(item.question);\n * evaluation.log('accuracy', { index, score: 0.95 });\n * }, { concurrency: 4 });\n * ```\n */\n async run<T>(\n dataset: T[],\n callback: RunCallback<T>,\n options?: RunOptions\n ): Promise<void> {\n if (!this.initialized) {\n await this.initialize();\n }\n\n const concurrency = options?.concurrency ?? this.concurrency;\n this.total = dataset.length;\n this.progress = 0;\n\n const tracer = trace.getTracer(\"langwatch\");\n\n // Process items with concurrency control\n const executing = new Set<Promise<void>>();\n\n for (let index = 0; index < dataset.length; index++) {\n const item = dataset[index] as T;\n\n const itemPromise = this.executeItem(tracer, item, index, callback);\n\n executing.add(itemPromise);\n void itemPromise.finally(() => executing.delete(itemPromise));\n\n // Wait if we've hit concurrency limit\n if (executing.size >= concurrency) {\n await Promise.race(executing);\n }\n }\n\n // Wait for all remaining items\n await Promise.all(executing);\n\n // Flush OTEL spans so all child spans created inside callbacks are exported\n const provider = trace.getTracerProvider();\n const delegate = \"getDelegate\" in provider && typeof provider.getDelegate === \"function\"\n ? provider.getDelegate()\n : provider;\n if (delegate && \"forceFlush\" in delegate && typeof delegate.forceFlush === \"function\") {\n await delegate.forceFlush();\n }\n\n // Send final batch with finished timestamp\n await this.flush(true);\n }\n\n /**\n * Execute a single item in the dataset\n */\n private async executeItem<T>(\n tracer: ReturnType<typeof trace.getTracer>,\n item: T,\n index: number,\n callback: RunCallback<T>\n ): Promise<void> {\n const startTime = Date.now();\n let error: Error | undefined;\n let capturedTraceId: string | null = null;\n\n // Reset withTarget tracking for this iteration\n this.iterationUsedWithTarget.set(index, false);\n\n // Set up iteration context (thread-safe via AsyncLocalStorage)\n const iterationContext: IterationContext = { index, item };\n\n // If evaluation uses targets, skip creating iteration-level traces\n // Each withTarget() call will create its own independent trace\n if (this.evaluationUsesTargets) {\n await iterationContextStorage.run(iterationContext, async () => {\n this.currentIndex = index;\n\n try {\n // Create a minimal span context for the callback\n const span = {\n setStatus: () => { /* no-op */ },\n recordException: () => { /* no-op */ },\n end: () => { /* no-op */ },\n } as unknown as LangWatchSpan;\n\n const ctx: RunContext<T> = { item, index, span };\n const result = callback(ctx);\n\n if (result && typeof result.then === \"function\") {\n await result;\n }\n } catch (err) {\n error = err instanceof Error ? err : new Error(String(err));\n this.logger.error(`Evaluation error at index ${index}:`, error);\n } finally {\n this.currentIndex = null;\n }\n });\n } else {\n await iterationContextStorage.run(iterationContext, async () => {\n await tracer.startActiveSpan(\n \"evaluation.iteration\",\n {\n attributes: {\n \"langwatch.origin\": \"evaluation\",\n \"evaluation.run_id\": this.runId,\n \"evaluation.index\": index,\n },\n },\n async (otelSpan) => {\n const span = createLangWatchSpan(otelSpan);\n const spanContext = otelSpan.spanContext();\n const traceId = spanContext.traceId;\n\n // Set current context for log/evaluate calls\n this.currentTraceId = traceId;\n this.currentIndex = index;\n capturedTraceId = traceId;\n\n try {\n const ctx: RunContext<T> = { item, index, span };\n const result = callback(ctx);\n\n if (result && typeof result.then === \"function\") {\n await result;\n }\n\n span.setStatus({ code: SpanStatusCode.OK });\n } catch (err) {\n error = err instanceof Error ? err : new Error(String(err));\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: error.message,\n });\n span.recordException(error);\n this.logger.error(`Evaluation error at index ${index}:`, error);\n } finally {\n span.end();\n this.currentTraceId = null;\n this.currentIndex = null;\n }\n }\n );\n });\n }\n\n // Only add a dataset entry if withTarget() was NOT used\n // When withTarget() is used, it creates its own dataset entries per target\n if (!this.iterationUsedWithTarget.get(index)) {\n const duration = Date.now() - startTime;\n const entry: BatchEntry = {\n index,\n entry: this.serializeItem(item),\n duration,\n error: error?.message ?? null,\n trace_id: capturedTraceId ?? this.getTraceIdFromContext(),\n };\n\n this.batch.dataset.push(entry);\n this.cumulativeEntries.push({\n duration: entry.duration,\n error: entry.error,\n cost: entry.cost,\n target_id: entry.target_id,\n });\n }\n\n // Clean up\n this.iterationUsedWithTarget.delete(index);\n\n this.progress++;\n\n // Debounced send\n this.scheduleSend();\n }\n\n /**\n * Log a custom metric result\n *\n * @param metric - Name of the metric\n * @param options - Metric options including index, score, passed, etc.\n *\n * If called inside a withTarget() block, the target and index are automatically\n * inferred from the context and don't need to be specified.\n *\n * @example\n * ```typescript\n * // Explicit target (outside withTarget)\n * evaluation.log('accuracy', { index, score: 0.95, target: 'gpt-4' });\n *\n * // Implicit target (inside withTarget)\n * await evaluation.withTarget('gpt-4', { model: 'openai/gpt-4' }, async () => {\n * evaluation.log('accuracy', { score: 0.95 }); // target and index auto-inferred\n * });\n * ```\n */\n log(metric: string, options: LogOptions): void {\n // Get context from AsyncLocalStorage (if inside withTarget)\n const targetContext = targetContextStorage.getStore();\n\n const {\n data = {},\n score,\n passed,\n label,\n details,\n status = options.error ? \"error\" : \"processed\",\n duration,\n cost,\n error,\n // Use context values as defaults, allow explicit override\n target = targetContext?.targetId,\n metadata,\n index = targetContext?.index ?? options.index,\n } = options;\n\n // Register target if provided (explicit or from context)\n let targetId: string | undefined;\n if (target) {\n targetId = this.registerTarget(target, metadata);\n }\n\n // Use trace ID from context, then current iteration, then OTEL context\n const traceId =\n targetContext?.traceId ?? this.currentTraceId ?? this.getTraceIdFromContext();\n\n const result: EvaluationResult = {\n name: metric,\n evaluator: metric,\n trace_id: traceId,\n status,\n data,\n score: score ?? null,\n passed: passed ?? null,\n details: details ?? (error ? error.message : null),\n index,\n label: label ?? null,\n cost: cost ?? null,\n duration: duration ?? null,\n error_type: error ? error.name : null,\n traceback: error ? [error.stack ?? error.message] : null,\n target_id: targetId ?? null,\n };\n\n this.batch.evaluations.push(result);\n this.cumulativeEvaluations.push({\n name: result.name,\n evaluator: result.evaluator,\n status: result.status,\n passed: result.passed,\n score: result.score,\n cost: result.cost,\n target_id: result.target_id,\n });\n this.scheduleSend();\n }\n\n /**\n * Run a built-in evaluator\n *\n * @param evaluatorSlug - The evaluator identifier (e.g., 'ragas/faithfulness')\n * @param options - Evaluator options including data and settings\n *\n * If called inside a withTarget() block, the target and index are automatically\n * inferred from the context and don't need to be specified.\n *\n * @example\n * ```typescript\n * // Inside withTarget() - target and index auto-inferred\n * await evaluation.withTarget('gpt-4', { model: 'openai/gpt-4' }, async () => {\n * await evaluation.evaluate('ragas/faithfulness', {\n * data: { input, output, contexts },\n * });\n * });\n *\n * // Or explicit index/target\n * await evaluation.evaluate('ragas/faithfulness', {\n * index,\n * data: { input, output, contexts },\n * target: 'gpt-4',\n * });\n * ```\n */\n async evaluate(evaluatorSlug: string, options: EvaluateOptions): Promise<void> {\n // Get context from AsyncLocalStorage (if inside withTarget)\n const targetContext = targetContextStorage.getStore();\n\n const {\n data,\n settings,\n name,\n asGuardrail = false,\n // Use context values as defaults, allow explicit override\n target = targetContext?.targetId,\n metadata,\n index = targetContext?.index ?? options.index,\n } = options;\n\n const startTime = Date.now();\n // Use trace ID from context, then current iteration, then OTEL context\n const traceId =\n targetContext?.traceId ?? this.currentTraceId ?? this.getTraceIdFromContext();\n const spanId = targetContext?.spanId ?? this.getSpanIdFromContext();\n\n try {\n const response = await fetch(\n `${this.endpoint}/api/evaluations/${evaluatorSlug}/evaluate`,\n {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...buildAuthHeaders({ apiKey: this.apiKey }),\n },\n body: JSON.stringify({\n trace_id: traceId ?? null,\n span_id: spanId ?? null,\n name: name ?? evaluatorSlug,\n data,\n settings,\n as_guardrail: asGuardrail,\n }),\n }\n );\n\n if (!response.ok) {\n const text = await response.text();\n throw new EvaluatorError(evaluatorSlug, text);\n }\n\n const result = (await response.json()) as RunEvaluatorResponse;\n const duration = Date.now() - startTime;\n\n // Log the result\n this.log(name ?? evaluatorSlug, {\n index,\n data,\n status: result.status,\n score: result.score ?? undefined,\n passed: result.passed ?? undefined,\n details: result.details ?? undefined,\n label: result.label ?? undefined,\n duration,\n cost: result.cost?.amount,\n target,\n metadata,\n });\n } catch (error) {\n const duration = Date.now() - startTime;\n\n if (error instanceof EvaluatorError) {\n this.log(name ?? evaluatorSlug, {\n index,\n data,\n status: \"error\",\n duration,\n error: error,\n target,\n metadata,\n });\n throw error;\n }\n\n const wrappedError = new EvaluatorError(\n evaluatorSlug,\n error instanceof Error ? error.message : String(error),\n error instanceof Error ? error : undefined\n );\n\n this.log(name ?? evaluatorSlug, {\n index,\n data,\n status: \"error\",\n duration,\n error: wrappedError,\n target,\n metadata,\n });\n\n throw wrappedError;\n }\n }\n\n /**\n * Execute code within a target context with automatic tracing\n *\n * Creates a new span for this target execution and sets up context\n * so that log() calls inside the callback automatically use this target.\n * Duration and output are captured automatically.\n *\n * This creates a dataset entry per target (like Evaluations V3), enabling\n * proper per-target latency and cost tracking.\n *\n * @param targetName - Unique identifier for the target\n * @param metadata - Optional metadata for comparison (e.g., { model: 'gpt-4' })\n * @param callback - Function to execute within the target context\n * @returns The callback result along with captured metrics\n *\n * @example\n * ```typescript\n * await evaluation.run(dataset, async ({ item, index }) => {\n * // Compare GPT-4 and Claude on the same input\n * const [gpt4Result, claudeResult] = await Promise.all([\n * evaluation.withTarget('gpt-4', { model: 'openai/gpt-4' }, async () => {\n * const response = await openai.chat(item.question);\n * evaluation.log('quality', { score: 0.95 }); // target auto-inferred\n * return response;\n * }),\n * evaluation.withTarget('claude-3', { model: 'anthropic/claude-3' }, async () => {\n * const response = await anthropic.messages(item.question);\n * evaluation.log('quality', { score: 0.85 }); // target auto-inferred\n * return response;\n * }),\n * ]);\n * });\n * ```\n */\n async withTarget<R>(\n targetName: string,\n metadata: TargetMetadata | null,\n callback: TargetCallback<R>\n ): Promise<TargetResult<R>>;\n async withTarget<R>(\n targetName: string,\n callback: TargetCallback<R>\n ): Promise<TargetResult<R>>;\n async withTarget<R>(\n targetName: string,\n metadataOrCallback: TargetMetadata | null | TargetCallback<R>,\n maybeCallback?: TargetCallback<R>\n ): Promise<TargetResult<R>> {\n // Handle overloads\n const metadata =\n typeof metadataOrCallback === \"function\" ? null : metadataOrCallback;\n const callback =\n typeof metadataOrCallback === \"function\" ? metadataOrCallback : maybeCallback!;\n\n // On FIRST withTarget() call ever in this evaluation:\n // - Set flag to skip creating iteration-level traces going forward\n if (!this.evaluationUsesTargets) {\n this.evaluationUsesTargets = true;\n }\n\n // Get iteration context (thread-safe via AsyncLocalStorage)\n const iterationContext = iterationContextStorage.getStore();\n const index = iterationContext?.index ?? this.currentIndex ?? 0;\n const currentItem = iterationContext?.item;\n\n // Mark that withTarget() was used - prevents executeItem from creating a dataset entry\n this.iterationUsedWithTarget.set(index, true);\n\n // Register target\n this.registerTarget(targetName, metadata ?? undefined);\n\n const tracer = trace.getTracer(\"langwatch\");\n const startTime = Date.now();\n let result: R | undefined;\n let traceId = \"\";\n let spanId = \"\";\n let callbackError: Error | undefined;\n\n // Create an INDEPENDENT root span using ROOT_CONTEXT\n // This ensures each target gets a unique trace_id, not shared with iteration\n await tracer.startActiveSpan(\n `evaluation.target.${targetName}`,\n {\n attributes: {\n \"langwatch.origin\": \"evaluation\",\n \"evaluation.run_id\": this.runId,\n \"evaluation.target\": targetName,\n \"evaluation.index\": index,\n },\n },\n ROOT_CONTEXT,\n async (otelSpan) => {\n const span = createLangWatchSpan(otelSpan);\n const spanContext = otelSpan.spanContext();\n const rawTraceId = spanContext.traceId;\n spanId = spanContext.spanId;\n\n // Check if this is a no-op trace (all zeros = no tracer configured)\n const isNoOpTrace = rawTraceId === \"00000000000000000000000000000000\";\n traceId = isNoOpTrace ? \"\" : rawTraceId;\n\n // Set up the target execution context\n const executionContext: TargetExecutionContext = {\n targetId: targetName,\n traceId,\n spanId,\n index,\n };\n\n try {\n // Run callback within AsyncLocalStorage context\n result = await targetContextStorage.run(executionContext, async () => {\n const ctx: TargetContext = { span, traceId, spanId };\n const callbackResult = callback(ctx);\n\n if (callbackResult && typeof (callbackResult as Promise<R>).then === \"function\") {\n return await callbackResult;\n }\n return callbackResult as R;\n });\n\n span.setStatus({ code: SpanStatusCode.OK });\n } catch (err) {\n callbackError = err instanceof Error ? err : new Error(String(err));\n span.setStatus({\n code: SpanStatusCode.ERROR,\n message: callbackError.message,\n });\n span.recordException(callbackError);\n throw err;\n } finally {\n span.end();\n }\n }\n );\n\n const duration = Date.now() - startTime;\n\n // Serialize the result as \"predicted\" output (similar to Evaluations V3)\n let predicted: Record<string, unknown> | null = null;\n if (result !== undefined && result !== null) {\n predicted = typeof result === \"object\"\n ? (result as Record<string, unknown>)\n : { output: result };\n }\n\n // Create a dataset entry for this target execution (like Evaluations V3)\n // This captures per-target duration/latency properly\n // Use currentItem from iteration context (thread-safe), NOT shared instance variable\n const entry: BatchEntry = {\n index,\n entry: this.serializeItem(currentItem),\n duration,\n error: callbackError?.message ?? null,\n trace_id: traceId || null, // null if no tracer configured (no-op)\n target_id: targetName,\n predicted,\n };\n\n this.batch.dataset.push(entry);\n this.cumulativeEntries.push({\n duration: entry.duration,\n error: entry.error,\n cost: entry.cost,\n target_id: entry.target_id,\n });\n this.scheduleSend();\n\n return {\n result: result!,\n duration,\n traceId,\n spanId,\n };\n }\n\n /**\n * Register a target for multi-target comparison\n */\n private registerTarget(name: string, metadata?: TargetMetadata): string {\n const existing = this.targets.get(name);\n\n if (existing) {\n // Check for metadata conflict\n if (metadata) {\n const existingMeta = existing.metadata ?? {};\n if (JSON.stringify(existingMeta) !== JSON.stringify(metadata)) {\n throw new TargetMetadataConflictError(name, existingMeta, metadata);\n }\n }\n return name;\n }\n\n // Register new target\n const targetInfo: TargetInfo = {\n id: name,\n name,\n type: \"custom\",\n metadata: metadata ?? null,\n };\n\n this.targets.set(name, targetInfo);\n this.batch.targets.push(targetInfo);\n\n return name;\n }\n\n /**\n * Schedule a debounced send\n */\n private scheduleSend(): void {\n const now = Date.now();\n\n if (now - this.lastSentMs >= DEBOUNCE_INTERVAL_MS) {\n this.sendBatch();\n } else {\n this.flushTimeout ??= setTimeout(() => {\n this.flushTimeout = null;\n this.sendBatch();\n }, DEBOUNCE_INTERVAL_MS - (now - this.lastSentMs));\n }\n }\n\n /**\n * Print a CI-friendly summary and optionally exit with code 1 on failure.\n *\n * Mirrors `ExperimentRunResult.printSummary` for parity — SDK-driven experiments\n * can now fail CI builds the same way platform experiments do.\n *\n * @param exitOnFailure - If true (default), calls `process.exit(1)` when any evaluation failed.\n *\n * @example\n * ```typescript\n * const experiment = await langwatch.experiments.init(\"ci-quality-check\");\n * await experiment.run(dataset, async ({ item, index }) => {\n * const response = await myLLM(item.input);\n * await experiment.evaluate(\"ragas/faithfulness\", { index, data: { input: item.input, output: response } });\n * });\n * experiment.printSummary();\n * ```\n */\n printSummary(exitOnFailure = true): void {\n const evaluators = new Map<\n string,\n { passed: number; failed: number; scoreSum: number; scoreCount: number }\n >();\n let totalPassed = 0;\n let totalFailed = 0;\n let totalCost = 0;\n\n for (const e of this.cumulativeEvaluations) {\n const name = e.name ?? e.evaluator ?? \"unknown\";\n if (!evaluators.has(name)) {\n evaluators.set(name, { passed: 0, failed: 0, scoreSum: 0, scoreCount: 0 });\n }\n const stats = evaluators.get(name)!;\n // Evaluators that crashed come back as status:\"error\" with passed often null;\n // treat them as failures so CI doesn't silently succeed on evaluator crashes.\n if (e.status === \"error\" || e.passed === false) {\n stats.failed += 1;\n totalFailed += 1;\n } else if (e.passed === true) {\n stats.passed += 1;\n totalPassed += 1;\n }\n if (typeof e.score === \"number\") {\n stats.scoreSum += e.score;\n stats.scoreCount += 1;\n }\n if (typeof e.cost === \"number\") {\n totalCost += e.cost;\n }\n }\n\n const targets = new Map<\n string,\n { passed: number; failed: number; latencySum: number; latencyCount: number; cost: number }\n >();\n for (const entry of this.cumulativeEntries) {\n const tid = entry.target_id;\n if (!tid) continue;\n if (!targets.has(tid)) {\n targets.set(tid, { passed: 0, failed: 0, latencySum: 0, latencyCount: 0, cost: 0 });\n }\n const stats = targets.get(tid)!;\n if (typeof entry.duration === \"number\") {\n stats.latencySum += entry.duration;\n stats.latencyCount += 1;\n }\n if (typeof entry.cost === \"number\") {\n stats.cost += entry.cost;\n }\n }\n // Lazily seed target stats from evaluations too — a user can log an\n // evaluation with an explicit target_id without ever going through\n // withTarget(), in which case the per-target entry row may not carry\n // target_id. Without this, such a target would be silently dropped from\n // the per-target summary.\n for (const e of this.cumulativeEvaluations) {\n const tid = e.target_id;\n if (!tid) continue;\n if (!targets.has(tid)) {\n targets.set(tid, { passed: 0, failed: 0, latencySum: 0, latencyCount: 0, cost: 0 });\n }\n const stats = targets.get(tid)!;\n if (e.status === \"error\" || e.passed === false) stats.failed += 1;\n else if (e.passed === true) stats.passed += 1;\n if (typeof e.cost === \"number\") stats.cost += e.cost;\n }\n\n const total = totalPassed + totalFailed;\n const passRate = total > 0 ? (totalPassed / total) * 100 : 0;\n\n // Wall-clock duration from init — summing entry durations over-counts\n // under concurrent withTarget() calls (each target produces its own entry).\n const duration = Math.max(0, Date.now() - this.createdAtMs);\n\n // Count entries whose target/loop execution errored out — distinct from\n // evaluator failures but must also trigger CI exit.\n let failedCells = 0;\n for (const entry of this.cumulativeEntries) {\n if (typeof entry.cost === \"number\") totalCost += entry.cost;\n if (entry.error) failedCells += 1;\n }\n\n const hasFailures = totalFailed > 0 || failedCells > 0;\n\n printSummary({\n runId: this.runId,\n status: hasFailures ? \"failed\" : \"completed\",\n passed: totalPassed,\n failed: totalFailed,\n passRate,\n duration,\n runUrl: this.runUrl,\n summary: {\n runId: this.runId,\n totalCells: this.cumulativeEntries.length || total,\n completedCells: Math.max(0, (this.cumulativeEntries.length || total) - failedCells),\n failedCells,\n duration,\n runUrl: this.runUrl,\n totalPassed,\n totalFailed,\n passRate,\n totalCost,\n targets: Array.from(targets.entries()).map(([targetId, s]) => ({\n targetId,\n name: targetId,\n passed: s.passed,\n failed: s.failed,\n avgLatency: s.latencyCount > 0 ? s.latencySum / s.latencyCount : 0,\n totalCost: s.cost,\n })),\n evaluators: Array.from(evaluators.entries()).map(([name, s]) => ({\n evaluatorId: name,\n name,\n passed: s.passed,\n failed: s.failed,\n passRate: s.passed + s.failed > 0 ? (s.passed / (s.passed + s.failed)) * 100 : 0,\n avgScore: s.scoreCount > 0 ? s.scoreSum / s.scoreCount : undefined,\n })),\n },\n });\n\n if (exitOnFailure && hasFailures) {\n process.exit(1);\n }\n }\n\n /**\n * Send current batch to the API\n */\n private sendBatch(finished = false): void {\n if (\n this.batch.dataset.length === 0 &&\n this.batch.evaluations.length === 0 &&\n this.batch.targets.length === 0 &&\n !finished\n ) {\n return;\n }\n\n const body: LogResultsRequest = {\n experiment_slug: this.experimentSlug,\n name: this.name,\n run_id: this.runId,\n dataset: this.batch.dataset.map((entry) => ({\n index: entry.index,\n entry: entry.entry,\n duration: entry.duration,\n error: entry.error,\n trace_id: entry.trace_id,\n target_id: entry.target_id ?? null,\n cost: entry.cost ?? null,\n // Only include predicted if it's defined (omit entirely when null/undefined)\n ...(entry.predicted !== undefined && entry.predicted !== null\n ? { predicted: entry.predicted }\n : {}),\n })),\n evaluations: this.batch.evaluations.map((e) => ({\n name: e.name,\n evaluator: e.evaluator,\n trace_id: e.trace_id,\n status: e.status,\n inputs: e.data,\n score: e.score,\n passed: e.passed,\n details: e.details,\n index: e.index,\n label: e.label,\n cost: e.cost,\n duration: e.duration,\n target_id: e.target_id,\n })),\n targets: this.batch.targets,\n progress: this.progress,\n total: this.total,\n timestamps: {\n created_at: this.createdAtMs,\n finished_at: finished ? Date.now() : null,\n },\n };\n\n // Fire and forget (with error logging)\n this.pendingFlush = fetch(`${this.endpoint}/api/evaluations/batch/log_results`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...buildAuthHeaders({ apiKey: this.apiKey }),\n },\n body: JSON.stringify(body),\n })\n .then((response) => {\n if (!response.ok) {\n this.logger.error(`Failed to send batch: ${response.status}`);\n }\n })\n .catch((error) => {\n this.logger.error(\"Failed to send batch:\", error);\n });\n\n // Clear batch\n this.batch = { dataset: [], evaluations: [], targets: [] };\n this.lastSentMs = Date.now();\n }\n\n /**\n * Flush all pending data\n */\n private async flush(finished = false): Promise<void> {\n if (this.flushTimeout) {\n clearTimeout(this.flushTimeout);\n this.flushTimeout = null;\n }\n\n this.sendBatch(finished);\n\n if (this.pendingFlush) {\n await this.pendingFlush;\n }\n }\n\n /**\n * Serialize a dataset item for the API\n */\n private serializeItem(item: unknown): unknown {\n if (item === null || item === undefined) {\n return item;\n }\n\n if (typeof item === \"object\") {\n // Handle objects with toJSON method\n if (\"toJSON\" in item && typeof (item as { toJSON: unknown }).toJSON === \"function\") {\n return (item as { toJSON: () => unknown }).toJSON();\n }\n // Return as-is, JSON.stringify will handle it\n return item;\n }\n\n return item;\n }\n\n /**\n * Get trace ID from current OpenTelemetry context\n */\n private getTraceIdFromContext(): string {\n const span = trace.getActiveSpan();\n if (span) {\n return span.spanContext().traceId;\n }\n return \"\";\n }\n\n /**\n * Get span ID from current OpenTelemetry context\n */\n private getSpanIdFromContext(): string | null {\n const span = trace.getActiveSpan();\n if (span) {\n return span.spanContext().spanId;\n }\n return null;\n }\n}\n","/**\n * Human-readable ID generator\n *\n * Generates memorable, human-readable identifiers using adjective-adjective-noun combinations.\n * Similar to Docker container names, Heroku app names, etc.\n */\n\nconst ADJECTIVES = [\n \"swift\", \"bright\", \"calm\", \"eager\", \"bold\", \"keen\", \"warm\", \"cool\", \"wise\", \"fair\",\n \"glad\", \"kind\", \"neat\", \"pure\", \"safe\", \"true\", \"vast\", \"wild\", \"zesty\", \"agile\",\n \"brave\", \"crisp\", \"dense\", \"epic\", \"fresh\", \"grand\", \"happy\", \"ideal\", \"jolly\", \"lively\",\n \"merry\", \"noble\", \"proud\", \"quick\", \"rapid\", \"sharp\", \"smart\", \"solid\", \"sunny\", \"vivid\",\n \"gentle\", \"silent\", \"cosmic\", \"golden\", \"silver\", \"ancient\", \"modern\", \"mighty\", \"humble\",\n];\n\nconst NOUNS = [\n \"fox\", \"owl\", \"bee\", \"elk\", \"hawk\", \"lynx\", \"wolf\", \"bear\", \"deer\", \"dove\",\n \"eagle\", \"finch\", \"heron\", \"koala\", \"lemur\", \"moose\", \"otter\", \"panda\", \"raven\", \"robin\",\n \"seal\", \"swan\", \"tiger\", \"whale\", \"zebra\", \"atlas\", \"bloom\", \"cloud\", \"delta\", \"ember\",\n \"flame\", \"grove\", \"haven\", \"iris\", \"jade\", \"leaf\", \"moon\", \"nova\", \"ocean\", \"peak\",\n \"river\", \"spark\", \"storm\", \"tide\", \"wave\", \"comet\", \"prism\", \"coral\",\n];\n\n/**\n * Generate a human-readable ID with 3 words like \"swift-bright-fox\"\n * Uses adjective-adjective-noun pattern for ~125,000 combinations.\n */\nexport const generateHumanReadableId = (separator = \"-\"): string => {\n // Pick two different adjectives\n const adj1Index = Math.floor(Math.random() * ADJECTIVES.length);\n let adj2Index = Math.floor(Math.random() * ADJECTIVES.length);\n if (adj2Index === adj1Index) {\n adj2Index = (adj2Index + 1) % ADJECTIVES.length;\n }\n\n const adjective1 = ADJECTIVES[adj1Index]!;\n const adjective2 = ADJECTIVES[adj2Index]!;\n const noun = NOUNS[Math.floor(Math.random() * NOUNS.length)]!;\n\n return `${adjective1}${separator}${adjective2}${separator}${noun}`;\n};\n","/**\n * Errors for the Experiments API\n */\n\n/**\n * Base error for experiment-related issues\n */\nexport class ExperimentError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ExperimentError\";\n }\n}\n\n/**\n * Thrown when initialization fails\n */\nexport class ExperimentInitError extends ExperimentError {\n constructor(message: string, public readonly cause?: Error) {\n super(message);\n this.name = \"ExperimentInitError\";\n }\n}\n\n/**\n * Thrown when API calls fail\n */\nexport class ExperimentApiError extends ExperimentError {\n constructor(\n message: string,\n public readonly statusCode?: number,\n public readonly cause?: Error\n ) {\n super(message);\n this.name = \"ExperimentApiError\";\n }\n}\n\n/**\n * Thrown when target metadata conflicts\n */\nexport class TargetMetadataConflictError extends ExperimentError {\n constructor(\n public readonly targetName: string,\n public readonly existingMetadata: Record<string, unknown>,\n public readonly newMetadata: Record<string, unknown>\n ) {\n super(\n `Target '${targetName}' was previously registered with different metadata.\\n` +\n `Original: ${JSON.stringify(existingMetadata)}\\n` +\n `New: ${JSON.stringify(newMetadata)}\\n` +\n `If you want to use different metadata, please use a different target name.`\n );\n this.name = \"TargetMetadataConflictError\";\n }\n}\n\n/**\n * Thrown when an evaluator call fails\n */\nexport class EvaluatorError extends ExperimentError {\n constructor(\n public readonly evaluatorSlug: string,\n message: string,\n public readonly cause?: Error\n ) {\n super(`Evaluator '${evaluatorSlug}' failed: ${message}`);\n this.name = \"EvaluatorError\";\n }\n}\n","import type { ExperimentRunResult } from \"./platformTypes\";\n\n/**\n * Print a CI-friendly summary of experiment results to stdout.\n *\n * Shared between platform runs (`langwatch.experiments.run`) and SDK-driven\n * experiments (`langwatch.experiments.init` → `experiment.printSummary()`).\n */\nexport function printSummary(result: Omit<ExperimentRunResult, \"printSummary\" | \"toString\">): void {\n const { runId, status, passed, failed, passRate, duration, runUrl, summary } = result;\n\n console.log(\"\\n\" + \"═\".repeat(60));\n console.log(\" EXPERIMENT RESULTS\");\n console.log(\"═\".repeat(60));\n console.log(` Run ID: ${runId}`);\n console.log(` Status: ${status.toUpperCase()}`);\n console.log(` Duration: ${(duration / 1000).toFixed(1)}s`);\n console.log(\"─\".repeat(60));\n console.log(` Passed: ${passed}`);\n console.log(` Failed: ${failed}`);\n console.log(` Pass Rate: ${passRate.toFixed(1)}%`);\n if (summary.totalCost) {\n console.log(` Total Cost: $${summary.totalCost.toFixed(4)}`);\n }\n\n if (summary.targets && summary.targets.length > 0) {\n console.log(\"─\".repeat(60));\n console.log(\" TARGETS:\");\n for (const target of summary.targets) {\n console.log(` ${target.name}: ${target.passed} passed, ${target.failed} failed`);\n if (target.avgLatency) {\n console.log(` Avg latency: ${target.avgLatency.toFixed(0)}ms`);\n }\n if (target.totalCost) {\n console.log(` Total cost: $${target.totalCost.toFixed(4)}`);\n }\n }\n }\n\n if (summary.evaluators && summary.evaluators.length > 0) {\n console.log(\"─\".repeat(60));\n console.log(\" EVALUATORS:\");\n for (const evaluator of summary.evaluators) {\n console.log(` ${evaluator.name}: ${evaluator.passRate.toFixed(1)}% pass rate`);\n if (evaluator.avgScore !== undefined) {\n console.log(` Avg score: ${evaluator.avgScore.toFixed(2)}`);\n }\n }\n }\n\n console.log(\"─\".repeat(60));\n console.log(` View details: ${runUrl}`);\n console.log(\"═\".repeat(60) + \"\\n\");\n}\n","import type { paths } from \"@/internal/generated/openapi/api-client\";\nimport {\n createLangWatchApiClient,\n type LangwatchApiClient,\n} from \"@/internal/api/client\";\nimport { type InternalConfig } from \"@/client-sdk/types\";\nimport {\n extractStatusFromResponse,\n formatApiErrorForOperation,\n} from \"@/client-sdk/services/_shared/format-api-error\";\n\nexport interface ExperimentRunStartResponse {\n runId: string;\n status: \"running\";\n total: number;\n runUrl?: string;\n}\n\n/**\n * Optional body for `POST /api/evaluations/v3/{slug}/run`. `data` and\n * `dataset_id` are mutually exclusive on the server (400 if both are sent).\n */\nexport interface ExperimentRunStartRequest {\n data?: Array<Record<string, unknown>>;\n dataset_id?: string;\n parameters?: Record<string, string | number | boolean>;\n row_indices?: number[];\n}\n\n/**\n * Build the snake_case run-start request body from camelCase options.\n *\n * Returns `undefined` when no overrides are provided so the caller can send a\n * body-less request (the server then uses the configured inputs).\n */\nexport const toRunStartRequest = ({\n data,\n datasetId,\n parameters,\n rowIndices,\n}: {\n data?: Array<Record<string, unknown>>;\n datasetId?: string;\n parameters?: Record<string, string | number | boolean>;\n rowIndices?: number[];\n}): ExperimentRunStartRequest | undefined => {\n const body: ExperimentRunStartRequest = {};\n if (data !== undefined) body.data = data;\n if (datasetId !== undefined) body.dataset_id = datasetId;\n if (parameters !== undefined) body.parameters = parameters;\n if (rowIndices !== undefined) body.row_indices = rowIndices;\n return Object.keys(body).length > 0 ? body : undefined;\n};\n\nexport type ExperimentRunStatusResponse =\n paths[\"/api/experiments/runs/{runId}\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\n\n/**\n * Status payload for `GET /api/evaluations/v3/runs/{runId}` (polling).\n *\n * Hand-written because the v3 path is served via a legacy-alias that rewrites\n * to `/api/experiments/...`, so only the legacy path is declared in the\n * generated OpenAPI types. Kept structurally aligned with that legacy schema.\n */\nexport interface ExperimentV3RunStatusResponse {\n runId: string;\n status: \"pending\" | \"running\" | \"completed\" | \"failed\" | \"stopped\";\n /** Number of cells completed */\n progress: number;\n /** Total number of cells */\n total: number;\n /** Unix timestamp when run started */\n startedAt?: number;\n /** Unix timestamp when run finished (completed/failed/stopped only) */\n finishedAt?: number;\n /** Execution summary (present when completed) */\n summary?: {\n runId?: string;\n totalCells?: number;\n completedCells?: number;\n failedCells?: number;\n /** Total execution time in milliseconds */\n duration?: number;\n /** URL to view the run in LangWatch */\n runUrl?: string;\n };\n /** Error message (present when failed) */\n error?: string;\n}\n\n/**\n * Summary entry returned by `GET /api/experiments`. Mirrors\n * `experimentSummarySchema` from the control-plane Hono route. Hand-written\n * because the route is not yet exposed via the generated OpenAPI types.\n */\nexport interface ExperimentSummary {\n id: string;\n slug: string;\n name: string | null;\n type: string;\n workflowId: string | null;\n createdAt: string;\n updatedAt: string;\n runsCount: number;\n lastRunAt: string | null;\n}\n\nexport interface ExperimentListPagination {\n page: number;\n pageSize: number;\n totalHits: number;\n hasMore: boolean;\n}\n\nexport interface ExperimentListResponse {\n experiments: ExperimentSummary[];\n pagination: ExperimentListPagination;\n}\n\n/**\n * Per-run entry returned by `GET /api/experiments/runs?experimentSlug=...`.\n * Mirrors `ExperimentRun` from the control plane.\n */\nexport interface ExperimentRunSummaryEntry {\n experimentId: string;\n runId: string;\n workflowVersion: {\n id: string;\n version: string;\n commitMessage: string;\n author: { name: string | null; image: string | null } | null;\n } | null;\n timestamps: {\n createdAt: number;\n updatedAt: number;\n finishedAt?: number | null;\n stoppedAt?: number | null;\n };\n progress?: number | null;\n total?: number | null;\n summary: {\n datasetCost?: number;\n evaluationsCost?: number;\n datasetAverageCost?: number;\n datasetAverageDuration?: number;\n evaluationsAverageCost?: number;\n evaluationsAverageDuration?: number;\n evaluations: Record<\n string,\n { name: string; averageScore: number | null; averagePassed?: number }\n >;\n };\n}\n\nexport interface ExperimentRunsListResponse {\n experimentId: string;\n experimentSlug: string;\n runs: ExperimentRunSummaryEntry[];\n pagination: ExperimentListPagination;\n}\n\n/**\n * Per-row results for a completed experiment run.\n *\n * Mirrors `ExperimentRunWithItems` from the control plane\n * (`langwatch/src/server/experiments-v3/services/types.ts`). Hand-written\n * because the `/runs/{runId}/results` route is not yet exposed via the\n * generated OpenAPI types.\n */\nexport interface ExperimentRunDatasetEntry {\n index: number;\n targetId?: string | null;\n entry: Record<string, unknown>;\n predicted?: Record<string, unknown>;\n cost?: number | null;\n duration?: number | null;\n error?: string | null;\n traceId?: string | null;\n}\n\nexport interface ExperimentRunEvaluation {\n evaluator: string;\n name?: string | null;\n targetId?: string | null;\n status: \"processed\" | \"skipped\" | \"error\";\n index: number;\n score?: number | null;\n label?: string | null;\n passed?: boolean | null;\n details?: string | null;\n cost?: number | null;\n duration?: number | null;\n inputs?: Record<string, unknown> | null;\n}\n\nexport interface ExperimentRunResultsResponse {\n experimentId: string;\n runId: string;\n projectId: string;\n workflowVersionId?: string | null;\n progress?: number | null;\n total?: number | null;\n dataset: ExperimentRunDatasetEntry[];\n evaluations: ExperimentRunEvaluation[];\n timestamps: {\n createdAt: number;\n updatedAt: number;\n finishedAt?: number | null;\n stoppedAt?: number | null;\n };\n}\n\nexport class ExperimentsApiServiceError extends Error {\n constructor(\n message: string,\n public readonly operation: string,\n public readonly originalError?: unknown,\n ) {\n super(message);\n this.name = \"ExperimentsApiServiceError\";\n }\n}\n\nexport class ExperimentsApiService {\n private readonly apiClient: LangwatchApiClient;\n\n constructor(config?: Pick<InternalConfig, \"langwatchApiClient\">) {\n this.apiClient = config?.langwatchApiClient ?? createLangWatchApiClient();\n }\n\n private handleApiError(operation: string, error: unknown): never {\n const message = formatApiErrorForOperation({ operation: operation, error: error, options: {\n status: extractStatusFromResponse(error),\n } });\n throw new ExperimentsApiServiceError(message, operation, error);\n }\n\n private async getUndeclaredEndpoint<T>({\n path,\n operation,\n }: {\n path: string;\n operation: string;\n }): Promise<T> {\n type UntypedClient = {\n GET: (\n path: string,\n init?: { parseAs?: \"json\" },\n ) => Promise<{ data?: unknown; error?: unknown; response: Response }>;\n };\n\n let result: { data?: unknown; error?: unknown; response: Response };\n try {\n result = await (this.apiClient as unknown as UntypedClient).GET(path, {\n parseAs: \"json\",\n });\n } catch (error) {\n this.handleApiError(operation, error);\n }\n\n if (result.error) this.handleApiError(operation, result.error);\n return result.data as T;\n }\n\n private async postUndeclaredEndpoint<T>({\n path,\n body,\n operation,\n }: {\n path: string;\n body?: unknown;\n operation: string;\n }): Promise<T> {\n type UntypedClient = {\n POST: (\n path: string,\n init?: { body?: unknown; parseAs?: \"json\" },\n ) => Promise<{ data?: unknown; error?: unknown; response: Response }>;\n };\n\n let result: { data?: unknown; error?: unknown; response: Response };\n try {\n result = await (this.apiClient as unknown as UntypedClient).POST(path, {\n ...(body !== undefined ? { body } : {}),\n parseAs: \"json\",\n });\n } catch (error) {\n this.handleApiError(operation, error);\n }\n\n if (result.error) this.handleApiError(operation, result.error);\n return result.data as T;\n }\n\n async startRun(slug: string): Promise<ExperimentRunStartResponse> {\n const { data, error } = await this.apiClient.POST(\n \"/api/experiments/{slug}/run\",\n {\n params: { path: { slug } },\n },\n );\n if (error) this.handleApiError(`start experiment run for \"${slug}\"`, error);\n return data as unknown as ExperimentRunStartResponse;\n }\n\n async getRunStatus(runId: string): Promise<ExperimentRunStatusResponse> {\n const { data, error } = await this.apiClient.GET(\n \"/api/experiments/runs/{runId}\",\n {\n params: { path: { runId } },\n },\n );\n if (error) this.handleApiError(`get run status for \"${runId}\"`, error);\n return data;\n }\n\n /**\n * List experiments for the current project.\n *\n * Hits `GET /api/experiments` through the configured API client transport.\n * The route is not yet declared in generated OpenAPI types, so the path is\n * dispatched through a narrow untyped helper.\n */\n async listExperiments({\n pageSize,\n page,\n }: {\n pageSize?: number;\n page?: number;\n } = {}): Promise<ExperimentListResponse> {\n const search = new URLSearchParams();\n if (pageSize !== undefined) search.set(\"pageSize\", String(pageSize));\n if (page !== undefined) search.set(\"page\", String(page));\n const qs = search.toString();\n return this.getUndeclaredEndpoint<ExperimentListResponse>({\n path: `/api/experiments${qs ? `?${qs}` : \"\"}`,\n operation: \"list experiments\",\n });\n }\n\n /**\n * List experiment runs for an experiment slug.\n *\n * Hits `GET /api/experiments/runs?experimentSlug=...` through the\n * configured API client transport because the route is not yet declared in\n * the generated OpenAPI.\n */\n async listRuns({\n experimentSlug,\n pageSize,\n page,\n }: {\n experimentSlug: string;\n pageSize?: number;\n page?: number;\n }): Promise<ExperimentRunsListResponse> {\n const search = new URLSearchParams();\n search.set(\"experimentSlug\", experimentSlug);\n if (pageSize !== undefined) search.set(\"pageSize\", String(pageSize));\n if (page !== undefined) search.set(\"page\", String(page));\n return this.getUndeclaredEndpoint<ExperimentRunsListResponse>({\n path: `/api/experiments/runs?${search.toString()}`,\n operation: `list runs for experiment \"${experimentSlug}\"`,\n });\n }\n\n /**\n * Fetch per-row results for a completed experiment run.\n *\n * Hits `GET /api/experiments/runs/{runId}/results` through the\n * configured API client transport because the route is not yet declared in\n * the generated OpenAPI `paths`.\n */\n async getRunResults({\n runId,\n experimentSlug,\n }: {\n runId: string;\n experimentSlug?: string;\n }): Promise<ExperimentRunResultsResponse> {\n const search = new URLSearchParams();\n if (experimentSlug) search.set(\"experimentSlug\", experimentSlug);\n const qs = search.toString() ? `?${search.toString()}` : \"\";\n const body = await this.getUndeclaredEndpoint<\n ExperimentRunResultsResponse | null\n >({\n path: `/api/experiments/runs/${encodeURIComponent(runId)}/results${qs}`,\n operation: `get run results for \"${runId}\"`,\n });\n if (body === null) {\n this.handleApiError(`get run results for \"${runId}\"`, {\n response: { status: 404 },\n data: { error: `Run not found: ${runId}` },\n });\n }\n return body;\n }\n\n /**\n * Start a saved Evaluations V3 experiment by slug through the unified\n * evaluations-v3 backend.\n *\n * Hits `POST /api/evaluations/v3/{slug}/run`. The optional body overrides\n * the configured inputs (`data` / `dataset_id` are mutually exclusive on the\n * server). The route accepts a body, but the generated OpenAPI types declare\n * it body-less, so the call is dispatched through a narrow untyped helper.\n */\n async startV3Run({\n slug,\n body,\n }: {\n slug: string;\n body?: ExperimentRunStartRequest;\n }): Promise<ExperimentRunStartResponse> {\n return this.postUndeclaredEndpoint<ExperimentRunStartResponse>({\n path: `/api/evaluations/v3/${encodeURIComponent(slug)}/run`,\n body,\n operation: `start evaluation run for \"${slug}\"`,\n });\n }\n\n /**\n * Poll the status of an Evaluations V3 run.\n *\n * Hits `GET /api/evaluations/v3/runs/{runId}`.\n */\n async getV3RunStatus(runId: string): Promise<ExperimentV3RunStatusResponse> {\n return this.getUndeclaredEndpoint<ExperimentV3RunStatusResponse>({\n path: `/api/evaluations/v3/runs/${encodeURIComponent(runId)}`,\n operation: `get run status for \"${runId}\"`,\n });\n }\n\n /**\n * Fetch per-row results for an Evaluations V3 run.\n *\n * Hits `GET /api/evaluations/v3/runs/{runId}/results`. `experimentSlug` is\n * optional for runs created in the last 24h and required afterwards.\n */\n async getV3RunResults({\n runId,\n experimentSlug,\n }: {\n runId: string;\n experimentSlug?: string;\n }): Promise<ExperimentRunResultsResponse> {\n const search = new URLSearchParams();\n if (experimentSlug) search.set(\"experimentSlug\", experimentSlug);\n const qs = search.toString() ? `?${search.toString()}` : \"\";\n const body = await this.getUndeclaredEndpoint<\n ExperimentRunResultsResponse | null\n >({\n path: `/api/evaluations/v3/runs/${encodeURIComponent(runId)}/results${qs}`,\n operation: `get run results for \"${runId}\"`,\n });\n if (body === null) {\n this.handleApiError(`get run results for \"${runId}\"`, {\n response: { status: 404 },\n data: { error: `Run not found: ${runId}` },\n });\n }\n return body;\n }\n}\n","/**\n * Error classes for platform experiments API (Experiments Workbench)\n */\n\n/**\n * Base error for experiment operations\n */\nexport class ExperimentsError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ExperimentsError\";\n }\n}\n\n/**\n * Error when experiment is not found\n */\nexport class ExperimentNotFoundError extends ExperimentsError {\n constructor(slug: string) {\n super(`Experiment not found: ${slug}`);\n this.name = \"ExperimentNotFoundError\";\n }\n}\n\n/**\n * Error when experiment run times out\n */\nexport class ExperimentTimeoutError extends ExperimentsError {\n readonly runId: string;\n readonly progress: number;\n readonly total: number;\n\n constructor(runId: string, progress: number, total: number) {\n super(`Experiment run timed out: ${runId} (${progress}/${total} completed)`);\n this.name = \"ExperimentTimeoutError\";\n this.runId = runId;\n this.progress = progress;\n this.total = total;\n }\n}\n\n/**\n * Error when experiment run fails\n */\nexport class ExperimentRunFailedError extends ExperimentsError {\n readonly runId: string;\n readonly errorMessage: string;\n\n constructor(runId: string, errorMessage: string) {\n super(`Experiment run failed: ${errorMessage}`);\n this.name = \"ExperimentRunFailedError\";\n this.runId = runId;\n this.errorMessage = errorMessage;\n }\n}\n\n/**\n * Error from the experiments API\n */\nexport class ExperimentsApiError extends ExperimentsError {\n readonly statusCode: number;\n\n constructor(message: string, statusCode: number) {\n super(message);\n this.name = \"ExperimentsApiError\";\n this.statusCode = statusCode;\n }\n}\n","// Experiment runs are stored as a timestamp-driven state in ClickHouse: a run\n// is \"completed\" once finishedAt is set, \"stopped\" once stoppedAt is set, and\n// otherwise still \"running\". A run that stopped emitting updates a while ago\n// without ever finishing is reported as \"interrupted\": the SDK process likely\n// died before sending finished_at/stopped_at.\n\nimport type { ExperimentRunSummary } from \"./platformTypes\";\nimport {\n ExperimentTimeoutError,\n ExperimentRunFailedError,\n} from \"./platformErrors\";\n\nexport const INTERRUPTED_THRESHOLD_MS = 5 * 60 * 1000;\n\nexport type RunStatus = \"completed\" | \"stopped\" | \"running\" | \"interrupted\";\n\nexport interface RunTimestamps {\n createdAt?: number | null;\n updatedAt?: number | null;\n finishedAt?: number | null;\n stoppedAt?: number | null;\n}\n\nexport const deriveRunStatus = (\n timestamps: RunTimestamps,\n now: number = Date.now(),\n): RunStatus => {\n if (timestamps.stoppedAt != null) return \"stopped\";\n if (timestamps.finishedAt != null) return \"completed\";\n if (\n timestamps.updatedAt != null &&\n now - timestamps.updatedAt > INTERRUPTED_THRESHOLD_MS\n ) {\n return \"interrupted\";\n }\n return \"running\";\n};\n\nexport const isTerminalStatus = (status: RunStatus): boolean =>\n status === \"completed\" || status === \"stopped\";\n\nexport const DEFAULT_POLL_INTERVAL = 2000;\nexport const DEFAULT_POLL_TIMEOUT = 600000; // 10 minutes\n\n/**\n * Status payload returned by the polling endpoint\n * (`GET /api/evaluations/v3/runs/{runId}`).\n */\nexport interface PollRunStatus {\n status: string;\n progress: number;\n total: number;\n summary?: ExperimentRunSummary;\n error?: string;\n}\n\nexport interface PollExperimentRunResult {\n status: \"completed\" | \"stopped\";\n summary: ExperimentRunSummary;\n}\n\nconst sleep = (ms: number): Promise<void> =>\n new Promise((resolve) => setTimeout(resolve, ms));\n\n/**\n * Poll a run to completion.\n *\n * Calls `getStatus(runId)` every `pollInterval` ms until the run reports a\n * terminal status, mirroring the python SDK poll loop. Resolves on `completed`\n * or `stopped`, throws `ExperimentRunFailedError` on `failed`, and throws\n * `ExperimentTimeoutError` if `timeout` ms elapse first.\n *\n * The status fetcher is injected so both the experiment and workflow paths can\n * reuse the same loop.\n */\nexport const pollExperimentRun = async ({\n runId,\n getStatus,\n pollInterval = DEFAULT_POLL_INTERVAL,\n timeout = DEFAULT_POLL_TIMEOUT,\n onProgress,\n now = Date.now,\n}: {\n runId: string;\n getStatus: (runId: string) => Promise<PollRunStatus>;\n pollInterval?: number;\n timeout?: number;\n onProgress?: (progress: number, total: number) => void;\n now?: () => number;\n}): Promise<PollExperimentRunResult> => {\n const startTime = now();\n\n while (true) {\n if (now() - startTime > timeout) {\n const finalStatus = await getStatus(runId);\n throw new ExperimentTimeoutError(\n runId,\n finalStatus.progress,\n finalStatus.total,\n );\n }\n\n await sleep(pollInterval);\n\n const status = await getStatus(runId);\n onProgress?.(status.progress, status.total);\n\n if (status.status === \"completed\") {\n return { status: \"completed\", summary: status.summary ?? {} };\n }\n\n if (status.status === \"failed\") {\n throw new ExperimentRunFailedError(runId, status.error ?? \"Unknown error\");\n }\n\n if (status.status === \"stopped\") {\n return {\n status: \"stopped\",\n summary: status.summary ?? {\n runId,\n totalCells: status.total,\n completedCells: status.progress,\n failedCells: 0,\n duration: now() - startTime,\n },\n };\n }\n }\n};\n\n/**\n * Replace the domain of a URL with a new base, preserving path/query/fragment.\n *\n * The platform returns its own (cloud) URL for a run; rebasing it onto the\n * configured endpoint keeps a self-hosted run pointing at the local instance\n * instead of app.langwatch.ai. Returns the original string if either URL is\n * unparseable.\n */\nexport const rebaseUrlToEndpoint = (url: string, newBase: string): string => {\n if (!url) return url;\n try {\n const parsedUrl = new URL(url);\n const parsedNewBase = new URL(newBase);\n return `${parsedNewBase.origin}${parsedUrl.pathname}${parsedUrl.search}${parsedUrl.hash}`;\n } catch {\n return url;\n }\n};\n\n/**\n * Fetch a run's per-row results, retrying through the brief post-completion\n * window where the results endpoint 404s (\"not yet available\") or returns an\n * empty dataset because the ClickHouse projection has not caught up yet.\n *\n * Generic over the result shape: `getResults` performs one fetch and `isEmpty`\n * reports whether it came back without rows. When the run reported rows\n * (`expectsRows`), an empty or failed read is retried up to `maxAttempts` with a\n * fixed `delay`; otherwise the first read is returned. The same loop backs both\n * the experiment and workflow SDK paths and mirrors the python SDK.\n */\nexport const fetchResultsWithRetry = async <T>({\n getResults,\n isEmpty,\n expectsRows,\n delay = DEFAULT_POLL_INTERVAL,\n maxAttempts = 6,\n}: {\n getResults: () => Promise<T>;\n isEmpty: (results: T) => boolean;\n expectsRows: boolean;\n delay?: number;\n maxAttempts?: number;\n}): Promise<T> => {\n let lastError: unknown;\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n const results = await getResults();\n if (expectsRows && isEmpty(results) && attempt < maxAttempts) {\n await sleep(delay);\n continue;\n }\n return results;\n } catch (error) {\n lastError = error;\n // Only the rows-expected path waits out the post-completion projection\n // lag (a 404 / \"not yet available\" right after the run finishes). With no\n // rows expected a thrown error is terminal, so surface it immediately\n // instead of delaying through every attempt.\n if (expectsRows && attempt < maxAttempts) {\n await sleep(delay);\n continue;\n }\n throw error;\n }\n }\n throw lastError;\n};\n","/**\n * Maps the platform `/runs/{runId}/results` response (ExperimentRunWithItems)\n * into per-row results.\n *\n * Mirrors the python SDK's `_build_df_from_platform`: dataset entries become the\n * base rows (one per entry, i.e. one per target in multi-target runs), and\n * evaluations are joined onto those rows on `(index, targetId)`.\n */\n\nimport type { ExperimentRunResultsResponse } from \"./experiments-api.service\";\nimport type { ExperimentRowResult } from \"./platformTypes\";\n\nconst matchesRow = ({\n row,\n index,\n targetId,\n}: {\n row: ExperimentRowResult;\n index: number;\n targetId?: string | null;\n}): boolean => {\n if (row.index !== index) return false;\n // Only constrain on target when the evaluation carries one and the rows are\n // multi-target (rows carry a `target`). Single-target rows have no `target`,\n // so an evaluation targetId should not exclude them.\n if (targetId && row.target !== undefined) {\n return row.target === targetId;\n }\n return true;\n};\n\nexport const mapRunResultsToRows = (\n response: ExperimentRunResultsResponse,\n): ExperimentRowResult[] => {\n const datasetEntries = response.dataset ?? [];\n const evaluations = response.evaluations ?? [];\n\n const rows: ExperimentRowResult[] = datasetEntries.map((entry) => {\n const entryData =\n entry.entry && typeof entry.entry === \"object\" ? entry.entry : {};\n\n const predicted = entry.predicted;\n const output =\n predicted && typeof predicted === \"object\" && \"output\" in predicted\n ? (predicted).output\n : predicted;\n\n const row: ExperimentRowResult = {\n index: entry.index ?? 0,\n input: { ...entryData },\n output,\n traceId: entry.traceId ?? \"\",\n evaluations: {},\n };\n\n if (entry.cost != null) row.cost = entry.cost;\n if (entry.duration != null) row.duration = entry.duration;\n if (entry.error) row.error = entry.error;\n if (entry.targetId) row.target = entry.targetId;\n\n return row;\n });\n\n // Index rows by their dataset index so each evaluation joins against just the\n // rows for that index (one per target) instead of scanning every row, which\n // would be O(evaluations x rows) on large result sets.\n const rowsByIndex = new Map<number, ExperimentRowResult[]>();\n for (const row of rows) {\n const bucket = rowsByIndex.get(row.index);\n if (bucket) bucket.push(row);\n else rowsByIndex.set(row.index, [row]);\n }\n\n for (const evaluation of evaluations) {\n const index = evaluation.index;\n // A null, undefined, or empty name falls through to the evaluator id\n // (matching the python builder); the length check keeps the empty-string\n // case from being collapsed by nullish coalescing.\n const name =\n evaluation.name && evaluation.name.length > 0\n ? evaluation.name\n : evaluation.evaluator;\n if (index == null || !name) continue;\n\n for (const row of rowsByIndex.get(index) ?? []) {\n if (!matchesRow({ row, index, targetId: evaluation.targetId })) continue;\n\n const metric = row.evaluations[name] ?? {};\n if (evaluation.score != null) metric.score = evaluation.score;\n if (evaluation.passed != null) metric.passed = evaluation.passed;\n row.evaluations[name] = metric;\n }\n }\n\n return rows;\n};\n","/**\n * ExperimentsFacade - Entry point for the experiments API\n *\n * Provides:\n * - `init()` method to create experiment sessions (SDK-defined experiments)\n * - `run()` method to execute platform-configured experiments (Experiments Workbench)\n */\n\nimport type { LangwatchApiClient } from \"@/internal/api/client\";\nimport { isLangWatchHandledError } from \"@/internal/api/errors\";\nimport type { Logger } from \"@/logger\";\nimport { Experiment } from \"./experiment\";\nimport {\n ExperimentsApiService,\n toRunStartRequest,\n} from \"./experiments-api.service\";\nimport type { ExperimentInitOptions } from \"./types\";\nimport type {\n ExperimentRunResult,\n RunExperimentOptions,\n RunWithResultsOptions,\n ExperimentRunWithResults,\n ExperimentRunSummary,\n} from \"./platformTypes\";\nimport {\n ExperimentsApiError,\n ExperimentNotFoundError,\n ExperimentTimeoutError,\n ExperimentRunFailedError,\n} from \"./platformErrors\";\nimport {\n pollExperimentRun,\n rebaseUrlToEndpoint,\n fetchResultsWithRetry,\n} from \"./run-status\";\nimport { mapRunResultsToRows } from \"./mapResults\";\nimport { printSummary } from \"./printSummary\";\n\nconst DEFAULT_POLL_INTERVAL = 2000;\nconst DEFAULT_TIMEOUT = 600000; // 10 minutes\n\ntype ExperimentsFacadeConfig = {\n langwatchApiClient: LangwatchApiClient;\n endpoint: string;\n apiKey: string;\n logger: Logger;\n};\n\n/**\n * Facade for creating experiment sessions and running platform-configured experiments\n */\nexport class ExperimentsFacade {\n private readonly config: ExperimentsFacadeConfig;\n private readonly apiService: ExperimentsApiService;\n\n constructor(config: ExperimentsFacadeConfig) {\n this.config = config;\n this.apiService = new ExperimentsApiService({\n langwatchApiClient: config.langwatchApiClient,\n });\n }\n\n /**\n * Initialize a new experiment session (SDK-defined)\n *\n * @param name - Name of the experiment (used as slug)\n * @param options - Optional configuration\n * @returns An initialized Experiment instance\n *\n * @example\n * ```typescript\n * const experiment = await langwatch.experiments.init('my-experiment');\n *\n * await experiment.run(dataset, async ({ item, index }) => {\n * const response = await myAgent(item.question);\n * experiment.log('accuracy', { index, score: 0.95 });\n * });\n * ```\n */\n async init(\n name: string,\n options?: ExperimentInitOptions,\n ): Promise<Experiment> {\n return Experiment.init(name, {\n apiClient: this.config.langwatchApiClient,\n endpoint: this.config.endpoint,\n apiKey: this.config.apiKey,\n logger: this.config.logger,\n ...options,\n });\n }\n\n /**\n * Run a platform-configured experiment (Experiments Workbench)\n *\n * This runs an experiment that was configured in the LangWatch platform.\n * The method automatically prints a summary and exits with code 1 on failure\n * (unless `exitOnFailure: false` is passed).\n *\n * @param slug - The slug of the experiment (found in the experiment URL)\n * @param options - Optional configuration\n * @returns The experiment results including pass rate and summary\n *\n * @example\n * ```typescript\n * import { LangWatch } from \"langwatch\";\n *\n * const langwatch = new LangWatch();\n *\n * const result = await langwatch.experiments.run(\"my-experiment-slug\");\n * result.printSummary();\n * ```\n */\n async run(\n slug: string,\n options?: RunExperimentOptions,\n ): Promise<ExperimentRunResult> {\n this.config.logger.info(`Running platform experiment: ${slug}`);\n const result = await this.runWithPolling(slug, options);\n return result;\n }\n\n /**\n * Run a platform experiment and return per-row structured results.\n *\n * Starts the run through the unified evaluations-v3 backend (optionally\n * overriding the configured inputs via `data` / `datasetId` / `parameters` /\n * `rowIndices`), polls to completion, fetches the per-row results, and maps\n * them to the same row structure as the python SDK's results DataFrame.\n *\n * @param slug - The slug of the experiment (found in the experiment URL)\n * @param options - Optional inputs and polling configuration\n * @returns The run id, results URL, status, summary, and per-row results\n *\n * @example\n * ```typescript\n * const langwatch = new LangWatch();\n * const { rows, runUrl } = await langwatch.experiments.runWithResults(\n * \"my-experiment-slug\",\n * { data: [{ question: \"What is 2 + 2?\" }] },\n * );\n * for (const row of rows) {\n * console.log(row.output, row.evaluations);\n * }\n * ```\n */\n async runWithResults(\n slug: string,\n options: RunWithResultsOptions = {},\n ): Promise<ExperimentRunWithResults> {\n this.config.logger.info(\n `Running platform experiment with results: ${slug}`,\n );\n\n const body = toRunStartRequest({\n data: options.data,\n datasetId: options.datasetId,\n parameters: options.parameters,\n rowIndices: options.rowIndices,\n });\n\n const startResponse = await this.apiService.startV3Run({ slug, body });\n const { runId } = startResponse;\n\n const { status, summary } = await pollExperimentRun({\n runId,\n getStatus: (id) => this.apiService.getV3RunStatus(id),\n pollInterval: options.pollInterval,\n timeout: options.timeout,\n onProgress: options.onProgress,\n });\n\n // ClickHouse can lag right after completion: the results endpoint may 404\n // (\"not yet available\") or return 200 with an empty dataset before the rows\n // materialize. Retry both cases when the run reported rows, mirroring the\n // python SDK, instead of failing or returning an empty result.\n const results = await fetchResultsWithRetry({\n getResults: () =>\n this.apiService.getV3RunResults({ runId, experimentSlug: slug }),\n isEmpty: (r) => (r.dataset?.length ?? 0) === 0,\n expectsRows: (summary.totalCells ?? 0) > 0,\n delay: options.pollInterval ?? DEFAULT_POLL_INTERVAL,\n });\n\n // Always return the URL rebased onto the configured endpoint, so a\n // self-hosted run does not surface a cloud (app.langwatch.ai) link. Both\n // the start response and the summary carry the platform's own URL; whichever\n // is present gets its domain replaced. Mirrors the python SDK.\n const rawRunUrl = startResponse.runUrl ?? summary.runUrl;\n const runUrl = rawRunUrl\n ? rebaseUrlToEndpoint(rawRunUrl, this.config.endpoint)\n : \"\";\n\n return {\n runId,\n runUrl,\n status,\n summary,\n rows: mapRunResultsToRows(results),\n };\n }\n\n /**\n * Run an experiment and wait for completion using polling\n */\n private async runWithPolling(\n slug: string,\n options: RunExperimentOptions = {},\n ): Promise<ExperimentRunResult> {\n const pollInterval = options.pollInterval ?? DEFAULT_POLL_INTERVAL;\n const timeout = options.timeout ?? DEFAULT_TIMEOUT;\n\n // Start the run\n const startResponse = await this.startRun(slug);\n const { runId } = startResponse;\n\n // Use the run URL from API but replace domain with configured endpoint\n const apiRunUrl = startResponse.runUrl ?? \"\";\n const runUrl = apiRunUrl\n ? rebaseUrlToEndpoint(apiRunUrl, this.config.endpoint)\n : \"\";\n\n console.log(`Started experiment run: ${runId}`);\n if (runUrl) {\n console.log(`Follow live: ${runUrl}`);\n }\n\n const total = startResponse.total;\n let lastProgress = 0;\n\n // Print initial progress\n if (total > 0) {\n process.stdout.write(`Progress: 0/${total} (0%)`);\n }\n options.onProgress?.(0, total);\n\n const startTime = Date.now();\n\n // Poll until complete\n while (true) {\n if (Date.now() - startTime > timeout) {\n console.log(); // Newline after progress\n const finalStatus = await this.getRunStatus(runId);\n throw new ExperimentTimeoutError(\n runId,\n finalStatus.progress,\n finalStatus.total,\n );\n }\n\n await this.sleep(pollInterval);\n\n const status = await this.getRunStatus(runId);\n const progress = status.progress;\n\n // Update progress display if changed\n if (progress !== lastProgress && status.total > 0) {\n const percentage = Math.round((progress / status.total) * 100);\n process.stdout.write(\n `\\rProgress: ${progress}/${status.total} (${percentage}%)`,\n );\n lastProgress = progress;\n }\n\n options.onProgress?.(status.progress, status.total);\n\n if (status.status === \"completed\") {\n console.log(); // Newline after progress\n const summary = status.summary ?? {};\n return this.buildResult(runId, \"completed\", summary, runUrl ?? \"\");\n }\n\n if (status.status === \"failed\") {\n console.log(); // Newline after progress\n throw new ExperimentRunFailedError(\n runId,\n status.error ?? \"Unknown error\",\n );\n }\n\n if (status.status === \"stopped\") {\n console.log(); // Newline after progress\n return this.buildResult(\n runId,\n \"stopped\",\n status.summary ?? {\n runId,\n totalCells: status.total,\n completedCells: status.progress,\n failedCells: 0,\n duration: Date.now() - startTime,\n },\n runUrl ?? \"\",\n );\n }\n }\n }\n\n /**\n * Start an experiment run\n */\n private async startRun(\n slug: string,\n ): Promise<{ runId: string; total: number; runUrl?: string }> {\n let response;\n try {\n response = await this.config.langwatchApiClient.POST(\n \"/api/experiments/{slug}/run\",\n {\n params: {\n path: { slug },\n },\n },\n );\n } catch (error) {\n if (isLangWatchHandledError(error)) {\n this.handleStartRunError(slug, error.body, error.httpStatus);\n }\n throw error;\n }\n\n if (response.error) {\n this.handleStartRunError(slug, response.error, response.response.status);\n }\n\n return response.data as { runId: string; total: number; runUrl?: string };\n }\n\n /**\n * Get the status of a run\n */\n private async getRunStatus(runId: string): Promise<{\n status: string;\n progress: number;\n total: number;\n summary?: ExperimentRunSummary;\n error?: string;\n }> {\n let response;\n try {\n response = await this.config.langwatchApiClient.GET(\n \"/api/experiments/runs/{runId}\",\n {\n params: {\n path: { runId },\n },\n },\n );\n } catch (error) {\n if (isLangWatchHandledError(error)) {\n this.handleRunStatusError(runId, error.body, error.httpStatus);\n }\n throw error;\n }\n\n if (response.error) {\n this.handleRunStatusError(\n runId,\n response.error,\n response.response.status,\n );\n }\n\n return response.data as {\n status: string;\n progress: number;\n total: number;\n summary?: ExperimentRunSummary;\n error?: string;\n };\n }\n\n private handleStartRunError(\n slug: string,\n error: unknown,\n status: number,\n ): never {\n if (status === 404) {\n throw new ExperimentNotFoundError(slug);\n }\n\n if (status === 401) {\n throw new ExperimentsApiError(\"Unauthorized - check your API key\", 401);\n }\n\n const errorMessage =\n typeof error === \"object\" &&\n error !== null &&\n \"error\" in error &&\n typeof error.error === \"string\"\n ? error.error\n : `Failed to start experiment: ${slug}`;\n throw new ExperimentsApiError(errorMessage, status);\n }\n\n private handleRunStatusError(\n runId: string,\n error: unknown,\n status: number,\n ): never {\n if (status === 404) {\n throw new ExperimentsApiError(`Run not found: ${runId}`, 404);\n }\n\n if (status === 401) {\n throw new ExperimentsApiError(\"Unauthorized - check your API key\", 401);\n }\n\n const errorMessage =\n typeof error === \"object\" &&\n error !== null &&\n \"error\" in error &&\n typeof error.error === \"string\"\n ? error.error\n : `Failed to get run status: ${runId}`;\n throw new ExperimentsApiError(errorMessage, status);\n }\n\n /**\n * Build the result object from API response\n */\n private buildResult(\n runId: string,\n status: \"completed\" | \"failed\" | \"stopped\",\n summary: ExperimentRunSummary,\n runUrl: string,\n ): ExperimentRunResult {\n const completedCells = summary.completedCells ?? 0;\n const failedCells = summary.failedCells ?? 0;\n const duration = summary.duration ?? 0;\n\n const totalPassed = summary.totalPassed ?? completedCells - failedCells;\n const totalFailed = summary.totalFailed ?? failedCells;\n const passRate =\n summary.passRate ??\n (completedCells > 0 ? (totalPassed / completedCells) * 100 : 0);\n\n const result: ExperimentRunResult = {\n runId,\n status,\n passed: totalPassed,\n failed: totalFailed,\n passRate,\n duration,\n runUrl,\n summary,\n printSummary: (exitOnFailure = true) => {\n printSummary({\n runId,\n status,\n passed: totalPassed,\n failed: totalFailed,\n passRate,\n duration,\n runUrl: summary.runUrl ?? runUrl,\n summary,\n });\n\n if (exitOnFailure && totalFailed > 0) {\n process.exit(1);\n }\n },\n toString: () =>\n `ExperimentRunResult { status: ${status.toUpperCase()}, passed: ${totalPassed}, failed: ${totalFailed}, passRate: ${passRate.toFixed(1)}%, duration: ${(duration / 1000).toFixed(1)}s }`,\n };\n\n // Custom Node.js inspect for console.log\n (result as Record<string | symbol, unknown>)[\n Symbol.for(\"nodejs.util.inspect.custom\")\n ] = () => result.toString();\n\n return result;\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","/**\n * EvaluationsFacade - Entry point for the Evaluations API (Online Evaluations / Guardrails)\n *\n * Provides an API for running evaluators and guardrails in real-time against LLM inputs/outputs.\n *\n * @example\n * ```typescript\n * const langwatch = new LangWatch({ apiKey: \"your-api-key\" });\n *\n * // Run a guardrail\n * const guardrail = await langwatch.evaluations.evaluate(\"presidio/pii_detection\", {\n * data: { input: userInput, output: generatedResponse },\n * name: \"PII Detection\",\n * asGuardrail: true,\n * settings: {},\n * });\n *\n * if (!guardrail.passed) {\n * return \"I'm sorry, I can't do that.\";\n * }\n * ```\n */\n\nimport { trace, SpanStatusCode, context as otelContext } from \"@opentelemetry/api\";\nimport { createLangWatchSpan } from \"@/observability-sdk/span/implementation\";\nimport type {\n EvaluationResult,\n EvaluateOptions,\n EvaluateRequest,\n EvaluateResponse,\n} from \"./types\";\nimport {\n EvaluatorCallError,\n EvaluatorNotFoundError,\n EvaluationsApiError,\n} from \"./errors\";\nimport type { Logger } from \"@/logger\";\nimport { buildAuthHeaders } from \"@/internal/api/auth\";\n\ntype EvaluationsFacadeConfig = {\n endpoint: string;\n apiKey: string;\n logger: Logger;\n};\n\nexport class EvaluationsFacade {\n readonly #endpoint: string;\n readonly #apiKey: string;\n readonly #logger: Logger;\n\n constructor(config: EvaluationsFacadeConfig) {\n this.#endpoint = config.endpoint;\n this.#apiKey = config.apiKey;\n this.#logger = config.logger;\n }\n\n /**\n * Run an evaluator or guardrail against provided data\n *\n * Creates an OpenTelemetry span attached to the current trace context,\n * calls the LangWatch evaluation API, and returns the result.\n *\n * @param slug - The evaluator slug (e.g., \"presidio/pii_detection\", \"langevals/llm_boolean\")\n * @param options - Evaluation options including data, name, settings, and asGuardrail flag\n * @returns The evaluation result with status, passed, score, details, label, and cost\n *\n * @example\n * ```typescript\n * // Run as a guardrail (synchronous evaluation that can block responses)\n * const guardrail = await langwatch.evaluations.evaluate(\"presidio/pii_detection\", {\n * data: { input: userInput, output: generatedResponse },\n * name: \"PII Detection Guardrail\",\n * asGuardrail: true,\n * });\n *\n * if (!guardrail.passed) {\n * console.log(\"PII detected:\", guardrail.details);\n * return \"Sorry, I cannot process that request.\";\n * }\n * ```\n *\n * @example\n * ```typescript\n * // Run as an online evaluation (async scoring for monitoring)\n * const result = await langwatch.evaluations.evaluate(\"langevals/llm_boolean\", {\n * data: { input: question, output: response },\n * name: \"Quality Check\",\n * settings: { prompt: \"Check if the response answers the question.\" },\n * });\n *\n * console.log(\"Score:\", result.score);\n * console.log(\"Details:\", result.details);\n * ```\n */\n evaluate = async (\n slug: string,\n options: EvaluateOptions\n ): Promise<EvaluationResult> => {\n const { data, name, settings, asGuardrail } = options;\n const spanName = name ?? slug;\n const spanType = asGuardrail ? \"guardrail\" : \"evaluation\";\n\n // Get tracer and create a span attached to the current context\n const tracer = trace.getTracer(\"langwatch-evaluations\");\n\n // Get current trace/span IDs from active context\n const activeSpan = trace.getActiveSpan();\n const traceId = activeSpan\n ? activeSpan.spanContext().traceId\n : undefined;\n const parentSpanId = activeSpan\n ? activeSpan.spanContext().spanId\n : undefined;\n\n // Start the evaluation span\n const otelSpan = tracer.startSpan(\n spanName,\n {\n attributes: {\n \"langwatch.span.type\": spanType,\n },\n },\n otelContext.active()\n );\n\n const langwatchSpan = createLangWatchSpan(otelSpan);\n\n // Set span input\n langwatchSpan.setType(spanType);\n langwatchSpan.setInput({\n data,\n ...(settings && { settings }),\n });\n\n try {\n // Build request payload\n const requestBody: EvaluateRequest = {\n trace_id: traceId ?? null,\n span_id: parentSpanId ?? null,\n name: name ?? null,\n data,\n settings,\n as_guardrail: asGuardrail,\n };\n\n // Call the evaluation API\n const url = `${this.#endpoint}/api/evaluations/${slug}/evaluate`;\n\n this.#logger.debug(`Calling evaluation API: ${url}`);\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...buildAuthHeaders({ apiKey: this.#apiKey }),\n },\n body: JSON.stringify(requestBody),\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n\n if (response.status === 404) {\n throw new EvaluatorNotFoundError(slug);\n }\n\n throw new EvaluationsApiError(\n `Evaluation API returned ${response.status}: ${errorText}`,\n response.status\n );\n }\n\n const responseData = (await response.json()) as EvaluateResponse;\n\n // Map response to result\n const result: EvaluationResult = {\n status: responseData.status,\n ...(responseData.passed !== null && responseData.passed !== undefined && { passed: responseData.passed }),\n ...(responseData.score !== null && responseData.score !== undefined && { score: responseData.score }),\n ...(responseData.details !== null && responseData.details !== undefined && { details: responseData.details }),\n ...(responseData.label !== null && responseData.label !== undefined && { label: responseData.label }),\n ...(responseData.cost !== null && responseData.cost !== undefined && { cost: responseData.cost }),\n };\n\n // Update span with output\n langwatchSpan.setOutput({\n type: asGuardrail ? \"guardrail_result\" : \"evaluation_result\",\n value: result,\n });\n\n // Set span status based on result\n if (result.status === \"error\") {\n otelSpan.setStatus({\n code: SpanStatusCode.ERROR,\n message: result.details ?? \"Evaluation failed\",\n });\n } else {\n otelSpan.setStatus({ code: SpanStatusCode.OK });\n }\n\n return result;\n } catch (error) {\n // Handle errors\n const errorResult: EvaluationResult = {\n status: \"error\",\n details: error instanceof Error ? error.message : String(error),\n };\n\n // For guardrails, default to passed=true on error to avoid blocking\n if (asGuardrail) {\n errorResult.passed = true;\n }\n\n // Update span with error\n langwatchSpan.setOutput({\n type: asGuardrail ? \"guardrail_result\" : \"evaluation_result\",\n value: errorResult,\n });\n\n otelSpan.setStatus({\n code: SpanStatusCode.ERROR,\n message: errorResult.details,\n });\n\n if (error instanceof Error) {\n otelSpan.recordException(error);\n }\n\n // Re-throw known errors\n if (\n error instanceof EvaluatorNotFoundError ||\n error instanceof EvaluationsApiError ||\n error instanceof EvaluatorCallError\n ) {\n throw error;\n }\n\n // Wrap unknown errors\n throw new EvaluatorCallError(\n slug,\n error instanceof Error ? error.message : String(error)\n );\n } finally {\n // Always end the span\n otelSpan.end();\n }\n };\n}\n","/**\n * Error classes for the Evaluations API\n */\n\n/**\n * Base error for evaluation operations\n */\nexport class EvaluationError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"EvaluationError\";\n }\n}\n\n/**\n * Error when an evaluator call fails\n */\nexport class EvaluatorCallError extends EvaluationError {\n readonly evaluatorSlug: string;\n readonly statusCode?: number;\n\n constructor(evaluatorSlug: string, message: string, statusCode?: number) {\n super(`Evaluator '${evaluatorSlug}' failed: ${message}`);\n this.name = \"EvaluatorCallError\";\n this.evaluatorSlug = evaluatorSlug;\n this.statusCode = statusCode;\n }\n}\n\n/**\n * Error when evaluator is not found\n */\nexport class EvaluatorNotFoundError extends EvaluationError {\n readonly evaluatorSlug: string;\n\n constructor(evaluatorSlug: string) {\n super(`Evaluator not found: ${evaluatorSlug}`);\n this.name = \"EvaluatorNotFoundError\";\n this.evaluatorSlug = evaluatorSlug;\n }\n}\n\n/**\n * Error from the evaluations API\n */\nexport class EvaluationsApiError extends EvaluationError {\n readonly statusCode: number;\n\n constructor(message: string, statusCode: number) {\n super(message);\n this.name = \"EvaluationsApiError\";\n this.statusCode = statusCode;\n }\n}\n","export class EvaluatorsApiError extends Error {\n constructor(\n message: string,\n public readonly operation: string,\n public readonly originalError?: unknown,\n ) {\n super(message);\n this.name = \"EvaluatorsApiError\";\n }\n}\n","import type {\n CreateEvaluatorBody,\n DeleteEvaluatorResponse,\n EvaluatorResponse,\n UpdateEvaluatorBody,\n} from \"./types\";\nimport {\n createLangWatchApiClient,\n type LangwatchApiClient,\n} from \"@/internal/api/client\";\nimport { type InternalConfig } from \"@/client-sdk/types\";\nimport { EvaluatorsApiError } from \"./errors\";\nimport {\n extractStatusFromResponse,\n formatApiErrorForOperation,\n} from \"@/client-sdk/services/_shared/format-api-error\";\n\n/**\n * Service for retrieving evaluator resources via the LangWatch API.\n *\n * Provides read-only access to project evaluators with computed fields.\n */\nexport class EvaluatorsApiService {\n private readonly apiClient: LangwatchApiClient;\n\n constructor(config?: Pick<InternalConfig, \"langwatchApiClient\">) {\n this.apiClient = config?.langwatchApiClient ?? createLangWatchApiClient();\n }\n\n private handleApiError(operation: string, error: unknown): never {\n const message = formatApiErrorForOperation({ operation: operation, error: error, options: {\n status: extractStatusFromResponse(error),\n } });\n throw new EvaluatorsApiError(message, operation, error);\n }\n\n /**\n * Fetches all evaluators for the project.\n */\n async getAll(): Promise<EvaluatorResponse[]> {\n const { data, error } = await this.apiClient.GET(\"/api/evaluators\");\n if (error) this.handleApiError(\"fetch all evaluators\", error);\n return data;\n }\n\n /**\n * Fetches a single evaluator by its ID or slug.\n */\n async get(idOrSlug: string): Promise<EvaluatorResponse> {\n const { data, error } = await this.apiClient.GET(\n \"/api/evaluators/{idOrSlug}\",\n {\n params: { path: { idOrSlug } },\n },\n );\n if (error)\n this.handleApiError(\n `fetch evaluator with ID or slug \"${idOrSlug}\"`,\n error,\n );\n return data;\n }\n\n /**\n * Creates a new evaluator.\n */\n async create(params: CreateEvaluatorBody): Promise<EvaluatorResponse> {\n const { data, error } = await this.apiClient.POST(\"/api/evaluators\", {\n body: params,\n });\n if (error) this.handleApiError(\"create evaluator\", error);\n return data;\n }\n\n /**\n * Updates an evaluator by its ID.\n */\n async update(id: string, params: UpdateEvaluatorBody): Promise<EvaluatorResponse> {\n const { data, error } = await this.apiClient.PUT(\n \"/api/evaluators/{id}\",\n {\n params: { path: { id } },\n body: params,\n },\n );\n if (error)\n this.handleApiError(`update evaluator with ID \"${id}\"`, error);\n return data;\n }\n\n /**\n * Deletes (archives) an evaluator by its ID.\n */\n async delete(id: string): Promise<DeleteEvaluatorResponse> {\n const { data, error } = await this.apiClient.DELETE(\n \"/api/evaluators/{id}\",\n {\n params: { path: { id } },\n },\n );\n if (error)\n this.handleApiError(`delete evaluator with ID \"${id}\"`, error);\n return data;\n }\n}\n","export class ScenariosApiError extends Error {\n constructor(\n message: string,\n public readonly operation: string,\n public readonly originalError?: unknown,\n ) {\n super(message);\n this.name = \"ScenariosApiError\";\n }\n}\n","import type {\n CreateScenarioBody,\n DeleteScenarioResponse,\n ScenarioResponse,\n UpdateScenarioBody,\n} from \"./types\";\nimport {\n createLangWatchApiClient,\n type LangwatchApiClient,\n} from \"@/internal/api/client\";\nimport { type InternalConfig } from \"@/client-sdk/types\";\nimport { ScenariosApiError } from \"./errors\";\nimport {\n extractStatusFromResponse,\n formatApiErrorForOperation,\n} from \"@/client-sdk/services/_shared/format-api-error\";\n\nexport class ScenariosApiService {\n private readonly apiClient: LangwatchApiClient;\n\n constructor(config?: Pick<InternalConfig, \"langwatchApiClient\">) {\n this.apiClient = config?.langwatchApiClient ?? createLangWatchApiClient();\n }\n\n private handleApiError(operation: string, error: unknown): never {\n const message = formatApiErrorForOperation({ operation: operation, error: error, options: {\n status: extractStatusFromResponse(error),\n } });\n throw new ScenariosApiError(message, operation, error);\n }\n\n async getAll(): Promise<ScenarioResponse[]> {\n const { data, error } = await this.apiClient.GET(\"/api/scenarios\");\n if (error) this.handleApiError(\"fetch all scenarios\", error);\n return data;\n }\n\n async get(id: string): Promise<ScenarioResponse> {\n const { data, error } = await this.apiClient.GET(\"/api/scenarios/{id}\", {\n params: { path: { id } },\n });\n if (error)\n this.handleApiError(`fetch scenario with ID \"${id}\"`, error);\n return data;\n }\n\n async create(params: CreateScenarioBody): Promise<ScenarioResponse> {\n const { data, error } = await this.apiClient.POST(\"/api/scenarios\", {\n body: params,\n });\n if (error) this.handleApiError(\"create scenario\", error);\n return data;\n }\n\n async update(id: string, params: UpdateScenarioBody): Promise<ScenarioResponse> {\n const { data, error } = await this.apiClient.PUT(\"/api/scenarios/{id}\", {\n params: { path: { id } },\n body: params,\n });\n if (error)\n this.handleApiError(`update scenario with ID \"${id}\"`, error);\n return data;\n }\n\n async delete(id: string): Promise<DeleteScenarioResponse> {\n const { data, error } = await this.apiClient.DELETE(\n \"/api/scenarios/{id}\",\n {\n params: { path: { id } },\n },\n );\n if (error)\n this.handleApiError(`delete scenario with ID \"${id}\"`, error);\n return data;\n }\n}\n","import type { paths } from \"@/internal/generated/openapi/api-client\";\nimport {\n createLangWatchApiClient,\n type LangwatchApiClient,\n} from \"@/internal/api/client\";\nimport type { InternalConfig } from \"@/client-sdk/types\";\nimport {\n extractStatusFromResponse,\n formatApiErrorForOperation,\n} from \"@/client-sdk/services/_shared/format-api-error\";\n\nexport type SuiteResponse = NonNullable<\n paths[\"/api/suites\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"]\n>[number] & {\n /** URL to view this suite on the LangWatch platform */\n platformUrl?: string;\n};\n\nexport type CreateSuiteBody = NonNullable<\n paths[\"/api/suites\"][\"post\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\nexport type UpdateSuiteBody = NonNullable<\n paths[\"/api/suites/{id}\"][\"patch\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\nexport type SuiteRunResult =\n paths[\"/api/suites/{id}/run\"][\"post\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\n\nexport interface SuiteTarget {\n type: \"prompt\" | \"http\" | \"code\" | \"workflow\";\n referenceId: string;\n}\n\nexport class SuitesApiError extends Error {\n constructor(\n message: string,\n public readonly operation: string,\n public readonly originalError?: unknown,\n ) {\n super(message);\n this.name = \"SuitesApiError\";\n }\n}\n\nexport class SuitesApiService {\n private readonly apiClient: LangwatchApiClient;\n\n constructor(config?: Pick<InternalConfig, \"langwatchApiClient\">) {\n this.apiClient = config?.langwatchApiClient ?? createLangWatchApiClient();\n }\n\n private handleApiError(operation: string, error: unknown): never {\n const message = formatApiErrorForOperation({ operation: operation, error: error, options: {\n status: extractStatusFromResponse(error),\n } });\n throw new SuitesApiError(message, operation, error);\n }\n\n async getAll(): Promise<SuiteResponse[]> {\n const { data, error } = await this.apiClient.GET(\"/api/suites\");\n if (error) this.handleApiError(\"list suites\", error);\n return data;\n }\n\n async get(id: string): Promise<SuiteResponse> {\n const { data, error } = await this.apiClient.GET(\"/api/suites/{id}\", {\n params: { path: { id } },\n });\n if (error) this.handleApiError(`get suite \"${id}\"`, error);\n return data;\n }\n\n async create(params: CreateSuiteBody): Promise<SuiteResponse> {\n const { data, error } = await this.apiClient.POST(\"/api/suites\", {\n body: params,\n });\n if (error) this.handleApiError(\"create suite\", error);\n return data;\n }\n\n async update(id: string, params: UpdateSuiteBody): Promise<SuiteResponse> {\n const { data, error } = await this.apiClient.PATCH(\"/api/suites/{id}\", {\n params: { path: { id } },\n body: params,\n });\n if (error) this.handleApiError(`update suite \"${id}\"`, error);\n return data;\n }\n\n async duplicate(id: string): Promise<SuiteResponse> {\n const { data, error } = await this.apiClient.POST(\"/api/suites/{id}/duplicate\", {\n params: { path: { id } },\n });\n if (error) this.handleApiError(`duplicate suite \"${id}\"`, error);\n return data;\n }\n\n async run(id: string, idempotencyKey?: string): Promise<SuiteRunResult> {\n const { data, error } = await this.apiClient.POST(\"/api/suites/{id}/run\", {\n params: { path: { id } },\n body: {\n idempotencyKey: idempotencyKey ?? `cli-${Date.now()}-${Math.random().toString(36).slice(2)}`,\n },\n });\n if (error) this.handleApiError(`run suite \"${id}\"`, error);\n return data;\n }\n\n async delete(id: string): Promise<{ id: string; archived: boolean }> {\n const { data, error } = await this.apiClient.DELETE(\"/api/suites/{id}\", {\n params: { path: { id } },\n });\n if (error) this.handleApiError(`delete suite \"${id}\"`, error);\n return data as unknown as { id: string; archived: boolean };\n }\n}\n","import type { paths } from \"@/internal/generated/openapi/api-client\";\nimport {\n createLangWatchApiClient,\n type LangwatchApiClient,\n} from \"@/internal/api/client\";\nimport { type InternalConfig } from \"@/client-sdk/types\";\nimport {\n extractStatusFromResponse,\n formatApiErrorForOperation,\n} from \"@/client-sdk/services/_shared/format-api-error\";\nimport { ExperimentsApiService } from \"@/client-sdk/services/experiments/experiments-api.service\";\nimport {\n pollExperimentRun,\n rebaseUrlToEndpoint,\n fetchResultsWithRetry,\n} from \"@/client-sdk/services/experiments/run-status\";\nimport { mapRunResultsToRows } from \"@/client-sdk/services/experiments/mapResults\";\nimport type {\n RunWithResultsOptions,\n ExperimentRunWithResults,\n} from \"@/client-sdk/services/experiments/platformTypes\";\n\nexport type WorkflowResponse = NonNullable<\n paths[\"/api/workflows\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"]\n>[number];\n\nexport type WorkflowDeleteResponse =\n paths[\"/api/workflows/{id}\"][\"delete\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\n\n/**\n * Body for `POST /api/workflows/{workflowId}/evaluate`. `data` and `dataset_id`\n * are mutually exclusive on the server (400 if both are sent).\n */\ninterface WorkflowEvaluateRequest {\n version_id?: string;\n data?: Array<Record<string, unknown>>;\n dataset_id?: string;\n parameters?: Record<string, string | number | boolean>;\n row_indices?: number[];\n}\n\n/**\n * Response from `POST /api/workflows/{workflowId}/evaluate`. Hand-written\n * because the route is not yet exposed via the generated OpenAPI types.\n */\ninterface WorkflowEvaluateResponse {\n run_id: string;\n run_url: string;\n workflow_version_id: string;\n version: string;\n}\n\nexport class WorkflowsApiError extends Error {\n constructor(\n message: string,\n public readonly operation: string,\n public readonly originalError?: unknown,\n ) {\n super(message);\n this.name = \"WorkflowsApiError\";\n }\n}\n\nexport class WorkflowsApiService {\n private readonly apiClient: LangwatchApiClient;\n private readonly experimentsApiService: ExperimentsApiService;\n private readonly endpoint: string;\n\n constructor(\n config?: Pick<InternalConfig, \"langwatchApiClient\"> & { endpoint?: string },\n ) {\n this.apiClient = config?.langwatchApiClient ?? createLangWatchApiClient();\n this.endpoint =\n config?.endpoint ??\n process.env.LANGWATCH_ENDPOINT ??\n \"https://app.langwatch.ai\";\n this.experimentsApiService = new ExperimentsApiService({\n langwatchApiClient: this.apiClient,\n });\n }\n\n private handleApiError(operation: string, error: unknown): never {\n const message = formatApiErrorForOperation({ operation: operation, error: error, options: {\n status: extractStatusFromResponse(error),\n } });\n throw new WorkflowsApiError(message, operation, error);\n }\n\n private async postUndeclaredEndpoint<T>({\n path,\n body,\n operation,\n }: {\n path: string;\n body?: unknown;\n operation: string;\n }): Promise<T> {\n type UntypedClient = {\n POST: (\n path: string,\n init?: { body?: unknown; parseAs?: \"json\" },\n ) => Promise<{ data?: unknown; error?: unknown; response: Response }>;\n };\n\n let result: { data?: unknown; error?: unknown; response: Response };\n try {\n result = await (this.apiClient as unknown as UntypedClient).POST(path, {\n ...(body !== undefined ? { body } : {}),\n parseAs: \"json\",\n });\n } catch (error) {\n this.handleApiError(operation, error);\n }\n\n if (result.error) this.handleApiError(operation, result.error);\n return result.data as T;\n }\n\n async getAll(): Promise<WorkflowResponse[]> {\n const { data, error } = await this.apiClient.GET(\"/api/workflows\");\n if (error) this.handleApiError(\"list workflows\", error);\n return data;\n }\n\n async get(id: string): Promise<WorkflowResponse> {\n const { data, error } = await this.apiClient.GET(\"/api/workflows/{id}\", {\n params: { path: { id } },\n });\n if (error) this.handleApiError(`get workflow \"${id}\"`, error);\n return data;\n }\n\n async delete(id: string): Promise<WorkflowDeleteResponse> {\n const { data, error } = await this.apiClient.DELETE(\"/api/workflows/{id}\", {\n params: { path: { id } },\n });\n if (error) this.handleApiError(`delete workflow \"${id}\"`, error);\n return data;\n }\n\n /**\n * Run a studio workflow evaluation and return per-row structured results.\n *\n * Starts the evaluation through the unified evaluations-v3 backend\n * (`POST /api/workflows/{workflowId}/evaluate`), polls to completion, fetches\n * the per-row results, and maps them to the same row structure as the python\n * SDK's results DataFrame.\n *\n * @param workflowId - The studio workflow id\n * @param options - Optional inputs, committed version override, and polling\n * configuration. `data` and `datasetId` are mutually\n * exclusive.\n * @returns The run id, results URL, status, summary, and per-row results\n *\n * @example\n * ```typescript\n * const langwatch = new LangWatch();\n * const { rows, runUrl } = await langwatch.workflows.run(\"workflow_123\", {\n * data: [{ question: \"What is 2 + 2?\" }],\n * });\n * ```\n */\n async run(\n workflowId: string,\n options: RunWithResultsOptions & { versionId?: string } = {},\n ): Promise<ExperimentRunWithResults> {\n const body: WorkflowEvaluateRequest = {};\n if (options.versionId !== undefined) body.version_id = options.versionId;\n if (options.data !== undefined) body.data = options.data;\n if (options.datasetId !== undefined) body.dataset_id = options.datasetId;\n if (options.parameters !== undefined) body.parameters = options.parameters;\n if (options.rowIndices !== undefined) body.row_indices = options.rowIndices;\n\n const startResponse = await this.postUndeclaredEndpoint<WorkflowEvaluateResponse>(\n {\n path: `/api/workflows/${encodeURIComponent(workflowId)}/evaluate`,\n body,\n operation: `run workflow evaluation for \"${workflowId}\"`,\n },\n );\n\n const runId = startResponse.run_id;\n\n const { status, summary } = await pollExperimentRun({\n runId,\n getStatus: (id) => this.experimentsApiService.getV3RunStatus(id),\n pollInterval: options.pollInterval,\n timeout: options.timeout,\n onProgress: options.onProgress,\n });\n\n // ClickHouse can lag right after completion: retry the results read through\n // the brief 404 / empty-dataset window when the run reported rows. Mirrors\n // the experiment path and the python SDK.\n const results = await fetchResultsWithRetry({\n getResults: () => this.experimentsApiService.getV3RunResults({ runId }),\n isEmpty: (r) => (r.dataset?.length ?? 0) === 0,\n expectsRows: (summary.totalCells ?? 0) > 0,\n delay: options.pollInterval,\n });\n\n // Rebase the run URL onto the configured endpoint so a self-hosted run does\n // not surface a cloud (app.langwatch.ai) link.\n const rawRunUrl = startResponse.run_url ?? summary.runUrl;\n const runUrl = rawRunUrl ? rebaseUrlToEndpoint(rawRunUrl, this.endpoint) : \"\";\n\n return {\n runId,\n runUrl,\n status,\n summary,\n rows: mapRunResultsToRows(results),\n };\n }\n}\n","import {\n createLangWatchApiClient,\n type LangwatchApiClient,\n} from \"@/internal/api/client\";\nimport { type InternalConfig } from \"@/client-sdk/types\";\nimport {\n extractStatusFromResponse,\n formatApiErrorForOperation,\n} from \"@/client-sdk/services/_shared/format-api-error\";\n\nexport interface AgentResponse {\n id: string;\n name: string;\n type: string;\n config: Record<string, unknown> | null;\n createdAt: string;\n updatedAt: string;\n platformUrl?: string;\n}\n\nexport interface AgentListResponse {\n data: AgentResponse[];\n pagination: {\n page: number;\n limit: number;\n total: number;\n totalPages: number;\n };\n}\n\nexport class AgentsApiError extends Error {\n constructor(\n message: string,\n public readonly operation: string,\n public readonly originalError?: unknown,\n ) {\n super(message);\n this.name = \"AgentsApiError\";\n }\n}\n\nexport class AgentsApiService {\n private readonly apiClient: LangwatchApiClient;\n\n constructor(config?: Pick<InternalConfig, \"langwatchApiClient\">) {\n this.apiClient = config?.langwatchApiClient ?? createLangWatchApiClient();\n }\n\n private handleApiError(operation: string, error: unknown): never {\n const message = formatApiErrorForOperation({ operation: operation, error: error, options: {\n status: extractStatusFromResponse(error),\n } });\n throw new AgentsApiError(message, operation, error);\n }\n\n async list(params?: { page?: number; limit?: number }): Promise<AgentListResponse> {\n const { data, error } = await this.apiClient.GET(\"/api/agents\", {\n params: { query: params },\n });\n if (error) this.handleApiError(\"list agents\", error);\n return data as unknown as AgentListResponse;\n }\n\n async get(id: string): Promise<AgentResponse> {\n const { data, error } = await this.apiClient.GET(\"/api/agents/{id}\", {\n params: { path: { id } },\n });\n if (error) this.handleApiError(`get agent \"${id}\"`, error);\n return data as unknown as AgentResponse;\n }\n\n async create(params: {\n name: string;\n type: string;\n config: Record<string, unknown>;\n workflowId?: string;\n }): Promise<AgentResponse> {\n const { data, error } = await this.apiClient.POST(\"/api/agents\", {\n body: params as never,\n });\n if (error) this.handleApiError(\"create agent\", error);\n return data as unknown as AgentResponse;\n }\n\n async update(id: string, params: {\n name?: string;\n type?: string;\n config?: Record<string, unknown>;\n }): Promise<AgentResponse> {\n const { data, error } = await this.apiClient.PATCH(\"/api/agents/{id}\", {\n params: { path: { id } },\n body: params as never,\n });\n if (error) this.handleApiError(`update agent \"${id}\"`, error);\n return data as unknown as AgentResponse;\n }\n\n async delete(id: string): Promise<{ id: string; name: string }> {\n const { data, error } = await this.apiClient.DELETE(\"/api/agents/{id}\", {\n params: { path: { id } },\n });\n if (error) this.handleApiError(`delete agent \"${id}\"`, error);\n return data as unknown as { id: string; name: string };\n }\n}\n","import type { paths, components } from \"@/internal/generated/openapi/api-client\";\nimport {\n createLangWatchApiClient,\n type LangwatchApiClient,\n} from \"@/internal/api/client\";\nimport { type InternalConfig } from \"@/client-sdk/types\";\nimport {\n extractStatusFromResponse,\n formatApiErrorForOperation,\n} from \"@/client-sdk/services/_shared/format-api-error\";\n\nexport type AnnotationResponse = components[\"schemas\"][\"Annotation\"];\n\nexport type CreateAnnotationBody = NonNullable<\n paths[\"/api/annotations/trace/{id}\"][\"post\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\nexport class AnnotationsApiError extends Error {\n constructor(\n message: string,\n public readonly operation: string,\n public readonly originalError?: unknown,\n ) {\n super(message);\n this.name = \"AnnotationsApiError\";\n }\n}\n\nexport class AnnotationsApiService {\n private readonly apiClient: LangwatchApiClient;\n\n constructor(config?: Pick<InternalConfig, \"langwatchApiClient\">) {\n this.apiClient = config?.langwatchApiClient ?? createLangWatchApiClient();\n }\n\n private handleApiError(operation: string, error: unknown): never {\n const message = formatApiErrorForOperation({ operation: operation, error: error, options: {\n status: extractStatusFromResponse(error),\n } });\n throw new AnnotationsApiError(message, operation, error);\n }\n\n async getAll(): Promise<AnnotationResponse[]> {\n const { data, error } = await this.apiClient.GET(\"/api/annotations\");\n if (error) this.handleApiError(\"fetch all annotations\", error);\n return data;\n }\n\n async get(id: string): Promise<AnnotationResponse> {\n const { data, error } = await this.apiClient.GET(\"/api/annotations/{id}\", {\n params: { path: { id } },\n });\n if (error)\n this.handleApiError(`fetch annotation with ID \"${id}\"`, error);\n return data;\n }\n\n async getByTrace(traceId: string): Promise<AnnotationResponse[]> {\n const { data, error } = await this.apiClient.GET(\n \"/api/annotations/trace/{id}\",\n {\n params: { path: { id: traceId } },\n },\n );\n if (error)\n this.handleApiError(`fetch annotations for trace \"${traceId}\"`, error);\n return data;\n }\n\n async create(traceId: string, params: CreateAnnotationBody): Promise<AnnotationResponse> {\n const { data, error } = await this.apiClient.POST(\n \"/api/annotations/trace/{id}\",\n {\n params: { path: { id: traceId } },\n body: params,\n },\n );\n if (error) this.handleApiError(\"create annotation\", error);\n return data;\n }\n\n async delete(id: string): Promise<{ status?: string; message?: string }> {\n const { data, error } = await this.apiClient.DELETE(\n \"/api/annotations/{id}\",\n {\n params: { path: { id } },\n },\n );\n if (error)\n this.handleApiError(`delete annotation with ID \"${id}\"`, error);\n return data;\n }\n}\n","import {\n createLangWatchApiClient,\n type LangwatchApiClient,\n} from \"@/internal/api/client\";\nimport { type InternalConfig } from \"@/client-sdk/types\";\nimport {\n extractStatusFromResponse,\n formatApiErrorForOperation,\n} from \"@/client-sdk/services/_shared/format-api-error\";\n\nexport interface DashboardSummary {\n id: string;\n name: string;\n order: number;\n graphCount: number;\n createdAt: string;\n updatedAt: string;\n platformUrl?: string;\n}\n\nexport interface DashboardDetail {\n id: string;\n name: string;\n order: number;\n graphs: unknown[];\n createdAt: string;\n updatedAt: string;\n platformUrl?: string;\n}\n\nexport class DashboardsApiError extends Error {\n constructor(\n message: string,\n public readonly operation: string,\n public readonly originalError?: unknown,\n ) {\n super(message);\n this.name = \"DashboardsApiError\";\n }\n}\n\nexport class DashboardsApiService {\n private readonly apiClient: LangwatchApiClient;\n\n constructor(config?: Pick<InternalConfig, \"langwatchApiClient\">) {\n this.apiClient = config?.langwatchApiClient ?? createLangWatchApiClient();\n }\n\n private handleApiError(operation: string, error: unknown): never {\n const message = formatApiErrorForOperation({ operation: operation, error: error, options: {\n status: extractStatusFromResponse(error),\n } });\n throw new DashboardsApiError(message, operation, error);\n }\n\n async list(): Promise<{ data: DashboardSummary[] }> {\n const { data, error } = await this.apiClient.GET(\"/api/dashboards\");\n if (error) this.handleApiError(\"list dashboards\", error);\n return data as unknown as { data: DashboardSummary[] };\n }\n\n async get(id: string): Promise<DashboardDetail> {\n const { data, error } = await this.apiClient.GET(\"/api/dashboards/{id}\", {\n params: { path: { id } },\n });\n if (error) this.handleApiError(`get dashboard \"${id}\"`, error);\n return data as unknown as DashboardDetail;\n }\n\n async create(params: { name: string }): Promise<DashboardDetail> {\n const { data, error } = await this.apiClient.POST(\"/api/dashboards\", {\n body: params,\n });\n if (error) this.handleApiError(\"create dashboard\", error);\n return data as unknown as DashboardDetail;\n }\n\n async rename(id: string, params: { name: string }): Promise<DashboardDetail> {\n const { data, error } = await this.apiClient.PATCH(\"/api/dashboards/{id}\", {\n params: { path: { id } },\n body: params,\n });\n if (error) this.handleApiError(`rename dashboard \"${id}\"`, error);\n return data as unknown as DashboardDetail;\n }\n\n async delete(id: string): Promise<{ id: string; name: string }> {\n const { data, error } = await this.apiClient.DELETE(\"/api/dashboards/{id}\", {\n params: { path: { id } },\n });\n if (error) this.handleApiError(`delete dashboard \"${id}\"`, error);\n return data as unknown as { id: string; name: string };\n }\n}\n","import type { paths } from \"@/internal/generated/openapi/api-client\";\nimport {\n createLangWatchApiClient,\n type LangwatchApiClient,\n} from \"@/internal/api/client\";\nimport { type InternalConfig } from \"@/client-sdk/types\";\nimport {\n extractStatusFromResponse,\n formatApiErrorForOperation,\n} from \"@/client-sdk/services/_shared/format-api-error\";\n\nexport type ModelProvidersListResponse =\n paths[\"/api/model-providers\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\n\nexport type UpdateModelProviderBody = NonNullable<\n paths[\"/api/model-providers/{provider}\"][\"put\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\nexport class ModelProvidersApiError extends Error {\n constructor(\n message: string,\n public readonly operation: string,\n public readonly originalError?: unknown,\n ) {\n super(message);\n this.name = \"ModelProvidersApiError\";\n }\n}\n\nexport class ModelProvidersApiService {\n private readonly apiClient: LangwatchApiClient;\n\n constructor(config?: Pick<InternalConfig, \"langwatchApiClient\">) {\n this.apiClient = config?.langwatchApiClient ?? createLangWatchApiClient();\n }\n\n private handleApiError(operation: string, error: unknown): never {\n const message = formatApiErrorForOperation({ operation: operation, error: error, options: {\n status: extractStatusFromResponse(error),\n } });\n throw new ModelProvidersApiError(message, operation, error);\n }\n\n async list(): Promise<ModelProvidersListResponse> {\n const { data, error } = await this.apiClient.GET(\"/api/model-providers\");\n if (error) this.handleApiError(\"list model providers\", error);\n return data;\n }\n\n async set(provider: string, params: UpdateModelProviderBody): Promise<ModelProvidersListResponse> {\n const { data, error } = await this.apiClient.PUT(\n \"/api/model-providers/{provider}\",\n {\n params: { path: { provider } },\n body: params,\n },\n );\n if (error)\n this.handleApiError(`set model provider \"${provider}\"`, error);\n return data;\n }\n}\n","import type { paths } from \"@/internal/generated/openapi/api-client\";\nimport {\n createLangWatchApiClient,\n type LangwatchApiClient,\n} from \"@/internal/api/client\";\nimport { type InternalConfig } from \"@/client-sdk/types\";\nimport {\n extractStatusFromResponse,\n formatApiErrorForOperation,\n} from \"@/client-sdk/services/_shared/format-api-error\";\n\nexport type AnalyticsTimeseriesBody = NonNullable<\n paths[\"/api/analytics/timeseries\"][\"post\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\nexport type AnalyticsTimeseriesResponse =\n paths[\"/api/analytics/timeseries\"][\"post\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\n\nexport class AnalyticsApiError extends Error {\n constructor(\n message: string,\n public readonly operation: string,\n public readonly originalError?: unknown,\n ) {\n super(message);\n this.name = \"AnalyticsApiError\";\n }\n}\n\nexport class AnalyticsApiService {\n private readonly apiClient: LangwatchApiClient;\n\n constructor(config?: Pick<InternalConfig, \"langwatchApiClient\">) {\n this.apiClient = config?.langwatchApiClient ?? createLangWatchApiClient();\n }\n\n private handleApiError(operation: string, error: unknown): never {\n const message = formatApiErrorForOperation({ operation: operation, error: error, options: {\n status: extractStatusFromResponse(error),\n } });\n throw new AnalyticsApiError(message, operation, error);\n }\n\n async timeseries(params: AnalyticsTimeseriesBody): Promise<AnalyticsTimeseriesResponse> {\n const { data, error } = await this.apiClient.POST(\n \"/api/analytics/timeseries\",\n { body: params },\n );\n if (error) this.handleApiError(\"query analytics\", error);\n return data;\n }\n}\n","import type { paths } from \"@/internal/generated/openapi/api-client\";\nimport {\n createLangWatchApiClient,\n type LangwatchApiClient,\n} from \"@/internal/api/client\";\nimport type { InternalConfig } from \"@/client-sdk/types\";\nimport {\n extractStatusFromResponse,\n formatApiErrorForOperation,\n} from \"@/client-sdk/services/_shared/format-api-error\";\n\nexport type TriggerResponse = NonNullable<\n paths[\"/api/triggers\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"]\n>[number];\n\nexport type CreateTriggerBody = NonNullable<\n paths[\"/api/triggers\"][\"post\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\nexport type UpdateTriggerBody = NonNullable<\n paths[\"/api/triggers/{id}\"][\"patch\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\nexport type TriggerDeleteResponse =\n paths[\"/api/triggers/{id}\"][\"delete\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\n\nexport class TriggersApiError extends Error {\n constructor(\n message: string,\n public readonly operation: string,\n public readonly originalError?: unknown,\n ) {\n super(message);\n this.name = \"TriggersApiError\";\n }\n}\n\nexport class TriggersApiService {\n private readonly apiClient: LangwatchApiClient;\n\n constructor(config?: Pick<InternalConfig, \"langwatchApiClient\">) {\n this.apiClient = config?.langwatchApiClient ?? createLangWatchApiClient();\n }\n\n private handleApiError(operation: string, error: unknown): never {\n const message = formatApiErrorForOperation({ operation: operation, error: error, options: {\n status: extractStatusFromResponse(error),\n } });\n throw new TriggersApiError(message, operation, error);\n }\n\n async getAll(): Promise<TriggerResponse[]> {\n const { data, error } = await this.apiClient.GET(\"/api/triggers\");\n if (error) this.handleApiError(\"list triggers\", error);\n return data;\n }\n\n async get(id: string): Promise<TriggerResponse> {\n const { data, error } = await this.apiClient.GET(\"/api/triggers/{id}\", {\n params: { path: { id } },\n });\n if (error) this.handleApiError(`get trigger \"${id}\"`, error);\n return data;\n }\n\n async create(params: CreateTriggerBody): Promise<TriggerResponse> {\n const { data, error } = await this.apiClient.POST(\"/api/triggers\", {\n body: params,\n });\n if (error) this.handleApiError(\"create trigger\", error);\n return data;\n }\n\n async update(id: string, params: UpdateTriggerBody): Promise<TriggerResponse> {\n const { data, error } = await this.apiClient.PATCH(\"/api/triggers/{id}\", {\n params: { path: { id } },\n body: params,\n });\n if (error) this.handleApiError(`update trigger \"${id}\"`, error);\n return data;\n }\n\n async delete(id: string): Promise<TriggerDeleteResponse> {\n const { data, error } = await this.apiClient.DELETE(\"/api/triggers/{id}\", {\n params: { path: { id } },\n });\n if (error) this.handleApiError(`delete trigger \"${id}\"`, error);\n return data;\n }\n}\n","import type { paths } from \"@/internal/generated/openapi/api-client\";\nimport {\n createLangWatchApiClient,\n type LangwatchApiClient,\n} from \"@/internal/api/client\";\nimport type { InternalConfig } from \"@/client-sdk/types\";\nimport {\n extractStatusFromResponse,\n formatApiErrorForOperation,\n} from \"@/client-sdk/services/_shared/format-api-error\";\n\nexport type GraphResponse = NonNullable<\n paths[\"/api/graphs\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"]\n>[number];\n\nexport type CreateGraphBody = NonNullable<\n paths[\"/api/graphs\"][\"post\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\nexport type UpdateGraphBody = NonNullable<\n paths[\"/api/graphs/{id}\"][\"patch\"][\"requestBody\"]\n>[\"content\"][\"application/json\"];\n\nexport type GraphDeleteResponse =\n paths[\"/api/graphs/{id}\"][\"delete\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\n\nexport class GraphsApiError extends Error {\n constructor(\n message: string,\n public readonly operation: string,\n public readonly originalError?: unknown,\n ) {\n super(message);\n this.name = \"GraphsApiError\";\n }\n}\n\nexport class GraphsApiService {\n private readonly apiClient: LangwatchApiClient;\n\n constructor(config?: Pick<InternalConfig, \"langwatchApiClient\">) {\n this.apiClient = config?.langwatchApiClient ?? createLangWatchApiClient();\n }\n\n private handleApiError(operation: string, error: unknown): never {\n const message = formatApiErrorForOperation({ operation: operation, error: error, options: {\n status: extractStatusFromResponse(error),\n } });\n throw new GraphsApiError(message, operation, error);\n }\n\n async getAll(dashboardId?: string): Promise<GraphResponse[]> {\n const { data, error } = await this.apiClient.GET(\"/api/graphs\", {\n params: { query: { dashboardId } },\n });\n if (error) this.handleApiError(\"list graphs\", error);\n return data;\n }\n\n async get(id: string): Promise<GraphResponse> {\n const { data, error } = await this.apiClient.GET(\"/api/graphs/{id}\", {\n params: { path: { id } },\n });\n if (error) this.handleApiError(`get graph \"${id}\"`, error);\n return data;\n }\n\n async create(params: CreateGraphBody): Promise<GraphResponse> {\n const { data, error } = await this.apiClient.POST(\"/api/graphs\", {\n body: params,\n });\n if (error) this.handleApiError(\"create graph\", error);\n return data;\n }\n\n async update(id: string, params: UpdateGraphBody): Promise<GraphResponse> {\n const { data, error } = await this.apiClient.PATCH(\"/api/graphs/{id}\", {\n params: { path: { id } },\n body: params,\n });\n if (error) this.handleApiError(`update graph \"${id}\"`, error);\n return data;\n }\n\n async delete(id: string): Promise<GraphDeleteResponse> {\n const { data, error } = await this.apiClient.DELETE(\"/api/graphs/{id}\", {\n params: { path: { id } },\n });\n if (error) this.handleApiError(`delete graph \"${id}\"`, error);\n return data;\n }\n}\n","import type { paths } from \"@/internal/generated/openapi/api-client\";\nimport {\n createLangWatchApiClient,\n type LangwatchApiClient,\n} from \"@/internal/api/client\";\nimport type { InternalConfig } from \"@/client-sdk/types\";\nimport {\n extractStatusFromResponse,\n formatApiErrorForOperation,\n} from \"@/client-sdk/services/_shared/format-api-error\";\n\nexport type SimulationRunsListResponse =\n paths[\"/api/simulation-runs\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\n\nexport type SimulationRunResponse =\n paths[\"/api/simulation-runs/{scenarioRunId}\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\n\nexport type SimulationRunsBatchesListResponse =\n paths[\"/api/simulation-runs/batches/list\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"];\n\nexport type SimulationRunsListParams = NonNullable<\n paths[\"/api/simulation-runs\"][\"get\"][\"parameters\"][\"query\"]\n>;\n\nexport type SimulationRunsBatchesListParams =\n paths[\"/api/simulation-runs/batches/list\"][\"get\"][\"parameters\"][\"query\"];\n\nexport class SimulationRunsApiError extends Error {\n constructor(\n message: string,\n public readonly operation: string,\n public readonly originalError?: unknown,\n ) {\n super(message);\n this.name = \"SimulationRunsApiError\";\n }\n}\n\nexport class SimulationRunsApiService {\n private readonly apiClient: LangwatchApiClient;\n\n constructor(config?: Pick<InternalConfig, \"langwatchApiClient\">) {\n this.apiClient = config?.langwatchApiClient ?? createLangWatchApiClient();\n }\n\n private handleApiError(operation: string, error: unknown): never {\n const message = formatApiErrorForOperation({ operation: operation, error: error, options: {\n status: extractStatusFromResponse(error),\n } });\n throw new SimulationRunsApiError(message, operation, error);\n }\n\n async getAll(params?: SimulationRunsListParams): Promise<SimulationRunsListResponse> {\n const { data, error } = await this.apiClient.GET(\"/api/simulation-runs\", {\n params: { query: params },\n });\n if (error) this.handleApiError(\"list simulation runs\", error);\n return data;\n }\n\n async get(scenarioRunId: string): Promise<SimulationRunResponse> {\n const { data, error } = await this.apiClient.GET(\n \"/api/simulation-runs/{scenarioRunId}\",\n {\n params: { path: { scenarioRunId } },\n },\n );\n if (error)\n this.handleApiError(`get simulation run \"${scenarioRunId}\"`, error);\n return data;\n }\n\n async listBatches(\n params: SimulationRunsBatchesListParams,\n ): Promise<SimulationRunsBatchesListResponse> {\n const { data, error } = await this.apiClient.GET(\n \"/api/simulation-runs/batches/list\",\n {\n params: { query: params },\n },\n );\n if (error) this.handleApiError(\"list simulation run batches\", error);\n return data;\n }\n}\n","/**\n * The one place the SDK decides \"did the platform NAME this failure?\".\n *\n * Every `*-api.service.ts` funnels its non-2xx responses through a private\n * `handleApiError`, which builds an English sentence and throws that service's\n * own error class. This slots in immediately before the throw: if the body is a\n * domain error, it raises the typed one instead; if it is anything else, it\n * returns and the service throws exactly what it always threw.\n *\n * That ordering is the whole design. Domain errors become typed; everything else\n * — a 5xx, a proxy's HTML, a truncated body, a dead socket — keeps its existing\n * behaviour byte for byte, including the message, because the sentence the\n * generic path already built is handed in and reused rather than rebuilt.\n */\nimport {\n handledErrorFrom,\n type LangWatchHandledError,\n} from \"@/internal/api/errors\";\nimport { extractStatusFromResponse } from \"./format-api-error\";\n\nexport interface ThrowIfHandledErrorParams {\n /** What was being attempted, e.g. `get trace \"abc\"`. */\n operation: string;\n /** The error body the HTTP client handed back. */\n error: unknown;\n /** The response it came on, when the service kept hold of it. */\n response?: Response;\n /** The status, when the service resolved it already. */\n status?: number;\n /** The sentence the generic path built — reused verbatim so nothing regresses. */\n message: string;\n}\n\n/**\n * Throws a {@link LangWatchHandledError} when the platform named the failure.\n * Returns — deliberately, so the caller throws its own error — when it did not.\n */\nexport function throwIfHandledError({\n operation,\n error,\n response,\n status,\n message,\n}: ThrowIfHandledErrorParams): void {\n const resolved =\n status ?? response?.status ?? extractStatusFromResponse(error);\n\n const handledError: LangWatchHandledError | null = handledErrorFrom({\n operation,\n body: error,\n status: resolved,\n message,\n });\n\n if (handledError) throw handledError;\n}\n","import { DEFAULT_ENDPOINT } from \"@/internal/constants\";\nimport { buildAuthHeaders } from \"@/internal/api/auth\";\nimport { formatApiErrorMessage } from \"@/client-sdk/services/_shared/format-api-error\";\nimport { throwIfHandledError } from \"@/client-sdk/services/_shared/throw-handled-error\";\n\nexport interface MonitorResponse {\n id: string;\n name: string;\n slug: string;\n checkType: string;\n enabled: boolean;\n executionMode: string;\n sample: number;\n level: string;\n evaluatorId: string | null;\n preconditions: unknown[];\n parameters: Record<string, unknown>;\n mappings: Record<string, unknown>;\n threadIdleTimeout: number | null;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface CreateMonitorBody {\n name: string;\n checkType: string;\n executionMode?: string;\n sample?: number;\n level?: string;\n preconditions?: unknown[];\n parameters?: Record<string, unknown>;\n mappings?: Record<string, unknown>;\n}\n\nexport interface UpdateMonitorBody {\n name?: string;\n enabled?: boolean;\n executionMode?: string;\n sample?: number;\n preconditions?: unknown[];\n parameters?: Record<string, unknown>;\n mappings?: Record<string, unknown>;\n}\n\nexport interface MonitorDeleteResponse {\n id: string;\n deleted: boolean;\n}\n\nexport class MonitorsApiError extends Error {\n constructor(\n message: string,\n public readonly operation: string,\n public readonly originalError?: unknown,\n ) {\n super(message);\n this.name = \"MonitorsApiError\";\n }\n}\n\nexport class MonitorsApiService {\n private readonly apiKey: string;\n private readonly endpoint: string;\n\n constructor(config?: { apiKey?: string; endpoint?: string }) {\n this.apiKey = config?.apiKey ?? process.env.LANGWATCH_API_KEY ?? \"\";\n this.endpoint = config?.endpoint ?? process.env.LANGWATCH_ENDPOINT ?? DEFAULT_ENDPOINT;\n }\n\n private async request<T>(path: string, options?: RequestInit): Promise<T> {\n const response = await fetch(`${this.endpoint}${path}`, {\n ...options,\n headers: {\n ...buildAuthHeaders({ apiKey: this.apiKey }),\n \"Content-Type\": \"application/json\",\n ...options?.headers,\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n let parsed: unknown = errorText;\n try {\n parsed = JSON.parse(errorText);\n } catch {\n // leave as raw text\n }\n const message = formatApiErrorMessage({ error: parsed, options: { status: response.status } });\n throwIfHandledError({\n operation: options?.method ?? \"GET\",\n error: parsed,\n status: response.status,\n message: `HTTP ${response.status}: ${message}`,\n });\n throw new MonitorsApiError(\n `HTTP ${response.status}: ${message}`,\n options?.method ?? \"GET\",\n parsed,\n );\n }\n\n return response.json() as Promise<T>;\n }\n\n async getAll(): Promise<MonitorResponse[]> {\n return this.request<MonitorResponse[]>(\"/api/monitors\");\n }\n\n async get(id: string): Promise<MonitorResponse> {\n return this.request<MonitorResponse>(`/api/monitors/${encodeURIComponent(id)}`);\n }\n\n async create(body: CreateMonitorBody): Promise<MonitorResponse> {\n return this.request<MonitorResponse>(\"/api/monitors\", {\n method: \"POST\",\n body: JSON.stringify(body),\n });\n }\n\n async update(id: string, body: UpdateMonitorBody): Promise<MonitorResponse> {\n return this.request<MonitorResponse>(`/api/monitors/${encodeURIComponent(id)}`, {\n method: \"PATCH\",\n body: JSON.stringify(body),\n });\n }\n\n async toggle(id: string, enabled: boolean): Promise<MonitorResponse> {\n return this.request<MonitorResponse>(`/api/monitors/${encodeURIComponent(id)}/toggle`, {\n method: \"POST\",\n body: JSON.stringify({ enabled }),\n });\n }\n\n async delete(id: string): Promise<MonitorDeleteResponse> {\n return this.request<MonitorDeleteResponse>(`/api/monitors/${encodeURIComponent(id)}`, {\n method: \"DELETE\",\n });\n }\n}\n","import { DEFAULT_ENDPOINT } from \"@/internal/constants\";\nimport { buildAuthHeaders } from \"@/internal/api/auth\";\nimport { formatApiErrorMessage } from \"@/client-sdk/services/_shared/format-api-error\";\nimport { throwIfHandledError } from \"@/client-sdk/services/_shared/throw-handled-error\";\n\nexport interface SecretResponse {\n id: string;\n projectId: string;\n name: string;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface SecretDeleteResponse {\n id: string;\n deleted: boolean;\n}\n\nexport class SecretsApiError extends Error {\n constructor(\n message: string,\n public readonly operation: string,\n public readonly originalError?: unknown,\n ) {\n super(message);\n this.name = \"SecretsApiError\";\n }\n}\n\nexport class SecretsApiService {\n private readonly apiKey: string;\n private readonly endpoint: string;\n\n constructor(config?: { apiKey?: string; endpoint?: string }) {\n this.apiKey = config?.apiKey ?? process.env.LANGWATCH_API_KEY ?? \"\";\n this.endpoint = config?.endpoint ?? process.env.LANGWATCH_ENDPOINT ?? DEFAULT_ENDPOINT;\n }\n\n private async request<T>(path: string, options?: RequestInit): Promise<T> {\n const response = await fetch(`${this.endpoint}${path}`, {\n ...options,\n headers: {\n ...buildAuthHeaders({ apiKey: this.apiKey }),\n \"Content-Type\": \"application/json\",\n ...options?.headers,\n },\n });\n\n if (!response.ok) {\n const errorText = await response.text();\n let parsed: unknown = errorText;\n try {\n parsed = JSON.parse(errorText);\n } catch {\n // leave as raw text\n }\n const message = formatApiErrorMessage({ error: parsed, options: { status: response.status } });\n throwIfHandledError({\n operation: options?.method ?? \"GET\",\n error: parsed,\n status: response.status,\n message: `HTTP ${response.status}: ${message}`,\n });\n throw new SecretsApiError(\n `HTTP ${response.status}: ${message}`,\n options?.method ?? \"GET\",\n parsed,\n );\n }\n\n return response.json() as Promise<T>;\n }\n\n async getAll(): Promise<SecretResponse[]> {\n return this.request<SecretResponse[]>(\"/api/secrets\");\n }\n\n async get(id: string): Promise<SecretResponse> {\n return this.request<SecretResponse>(`/api/secrets/${encodeURIComponent(id)}`);\n }\n\n async create(body: { name: string; value: string }): Promise<SecretResponse> {\n return this.request<SecretResponse>(\"/api/secrets\", {\n method: \"POST\",\n body: JSON.stringify(body),\n });\n }\n\n async update(id: string, body: { value: string }): Promise<SecretResponse> {\n return this.request<SecretResponse>(`/api/secrets/${encodeURIComponent(id)}`, {\n method: \"PUT\",\n body: JSON.stringify(body),\n });\n }\n\n async delete(id: string): Promise<SecretDeleteResponse> {\n return this.request<SecretDeleteResponse>(`/api/secrets/${encodeURIComponent(id)}`, {\n method: \"DELETE\",\n });\n }\n}\n","import type { paths } from \"@/internal/generated/openapi/api-client\";\n\nexport interface GetTraceParams {\n includeSpans?: boolean;\n}\n\nexport type GetTraceResponse = NonNullable<\n paths[\"/api/trace/{id}\"][\"get\"][\"responses\"][\"200\"][\"content\"][\"application/json\"]\n>;\n\n/**\n * Custom error class for Traces API operations.\n * Provides context about the failed operation and the original error.\n */\nexport class TracesError extends Error {\n constructor(\n message: string,\n public readonly operation: string,\n public readonly originalError?: any,\n ) {\n super(message);\n this.name = \"TracesError\";\n }\n}\n","import { LANGWATCH_SDK_NAME_CLIENT, LANGWATCH_SDK_VERSION } from \"@/internal/constants\";\nimport { getLangWatchTracer } from \"@/observability-sdk/tracer\";\n\nexport const tracer = getLangWatchTracer(`${LANGWATCH_SDK_NAME_CLIENT}.traces`, LANGWATCH_SDK_VERSION);\n","import { createTracingProxy } from \"@/client-sdk/tracing/create-tracing-proxy\";\nimport { type InternalConfig } from \"@/client-sdk/types\";\nimport { type GetTraceParams, TracesError, type GetTraceResponse } from \"./types\";\nimport { tracer } from \"./tracing\";\n\n/**\n * Service for managing trace resources via the Langwatch API.\n * Constructor creates a proxy that wraps the service and traces all methods.\n *\n * Responsibilities:\n * - Retrieving trace data\n * - Error handling with contextual information\n *\n * All methods return trace response objects directly.\n */\nexport class TracesService {\n private config: InternalConfig;\n\n constructor(config: InternalConfig) {\n this.config = config;\n\n /**\n * Wraps the service in a tracing proxy via the decorator.\n */\n return createTracingProxy(\n this as TracesService,\n tracer,\n );\n }\n\n /**\n * Handles API errors by throwing a TracesError with operation context.\n * @param operation Description of the operation being performed.\n * @param error The error object returned from the API client.\n * @throws {TracesError}\n */\n private handleApiError(operation: string, error: any): never {\n const errorMessage =\n typeof error === \"string\"\n ? error\n : error?.error ?? error?.message ?? \"Unknown error occurred\";\n const message = `Failed to ${operation}: ${errorMessage}`;\n\n throw new TracesError(\n message,\n operation,\n error,\n );\n }\n\n /**\n * Retrieves a trace by its ID.\n * @param traceId The trace's unique identifier.\n * @param params Optional parameters for the request.\n * @returns The trace response object.\n * @throws {TracesError} If the API call fails.\n */\n async get(\n traceId: string,\n params?: GetTraceParams,\n ): Promise<GetTraceResponse> {\n const { data, error } = await this.config.langwatchApiClient.GET(\"/api/trace/{id}\", {\n params: {\n path: {\n id: traceId,\n },\n },\n query: params,\n });\n\n if (error) {\n this.handleApiError(\"get trace\", error);\n }\n\n return data;\n }\n}\n","import { type InternalConfig } from \"../../types\";\nimport { TracesService } from \"./service\";\nimport { type GetTraceParams, type GetTraceResponse } from \"./types\";\n\nexport class TracesFacade {\n readonly #service: TracesService;\n\n constructor(config: InternalConfig) {\n this.#service = new TracesService(config);\n }\n\n async get(traceId: string, params?: GetTraceParams): Promise<GetTraceResponse> {\n return this.#service.get(traceId, params);\n }\n}\n","import { PromptsFacade, PromptsApiService } from \"./services/prompts\";\nexport { FetchPolicy, type GetPromptOptions } from \"./services/prompts\";\nexport type {\n Dataset,\n DatasetEntry,\n DatasetMetadata,\n DatasetColumnType,\n DatasetListItem,\n Pagination,\n PaginatedResponse,\n GetDatasetOptions,\n ListDatasetsOptions,\n ListDatasetsApiResponse,\n ListRecordsOptions,\n ListRecordsApiResponse,\n CreateDatasetOptions,\n UpdateDatasetOptions,\n CreateFromUploadResponse,\n BatchCreateRecordsResponse,\n DeleteRecordsResponse,\n UploadResponse,\n DatasetRecordResponse,\n} from \"./services/datasets\";\nexport { DatasetError, DatasetNotFoundError, DatasetApiError, DatasetValidationError, DatasetPlanLimitError } from \"./services/datasets\";\nexport type {\n ExperimentRunResult,\n RunExperimentOptions,\n RunWithResultsOptions,\n ExperimentRowResult,\n ExperimentRunWithResults,\n} from \"./services/experiments\";\nexport {\n ExperimentsError,\n ExperimentNotFoundError,\n ExperimentTimeoutError,\n ExperimentRunFailedError,\n ExperimentsApiError,\n} from \"./services/experiments\";\nexport type { EvaluationResult, EvaluateOptions, EvaluationStatus, EvaluationCost } from \"./services/evaluations\";\nexport {\n EvaluationError,\n EvaluatorCallError,\n EvaluatorNotFoundError,\n EvaluationsApiError,\n} from \"./services/evaluations\";\nexport { EvaluatorsApiService, EvaluatorsApiError } from \"./services/evaluators\";\nexport { ScenariosApiService, ScenariosApiError } from \"./services/scenarios\";\nexport { SuitesApiService, SuitesApiError } from \"./services/suites\";\nexport { WorkflowsApiService, WorkflowsApiError } from \"./services/workflows/workflows-api.service\";\nexport { AgentsApiService, AgentsApiError } from \"./services/agents/agents-api.service\";\nexport { AnnotationsApiService, AnnotationsApiError } from \"./services/annotations/annotations-api.service\";\nexport { DashboardsApiService, DashboardsApiError } from \"./services/dashboards/dashboards-api.service\";\nexport { ModelProvidersApiService, ModelProvidersApiError } from \"./services/model-providers/model-providers-api.service\";\nexport { AnalyticsApiService, AnalyticsApiError } from \"./services/analytics/analytics-api.service\";\nexport { TriggersApiService, TriggersApiError } from \"./services/triggers\";\nexport { GraphsApiService, GraphsApiError } from \"./services/graphs\";\nexport { SimulationRunsApiService, SimulationRunsApiError } from \"./services/simulation-runs\";\nexport { TracesApiService, TracesApiError } from \"./services/traces/traces-api.service\";\nexport { MonitorsApiService, MonitorsApiError } from \"./services/monitors\";\nexport { SecretsApiService, SecretsApiError } from \"./services/secrets\";\nimport { LocalPromptsService } from \"./services/prompts/local-prompts.service\";\nimport { ExperimentsFacade } from \"./services/experiments\";\nimport { DatasetsFacade } from \"./services/datasets\";\nimport { EvaluationsFacade } from \"./services/evaluations\";\nimport { EvaluatorsApiService } from \"./services/evaluators\";\nimport { ScenariosApiService } from \"./services/scenarios\";\nimport { SuitesApiService } from \"./services/suites\";\nimport { WorkflowsApiService } from \"./services/workflows/workflows-api.service\";\nimport { AgentsApiService } from \"./services/agents/agents-api.service\";\nimport { AnnotationsApiService } from \"./services/annotations/annotations-api.service\";\nimport { DashboardsApiService } from \"./services/dashboards/dashboards-api.service\";\nimport { ModelProvidersApiService } from \"./services/model-providers/model-providers-api.service\";\nimport { AnalyticsApiService } from \"./services/analytics/analytics-api.service\";\nimport { TriggersApiService } from \"./services/triggers\";\nimport { GraphsApiService } from \"./services/graphs\";\nimport { SimulationRunsApiService } from \"./services/simulation-runs\";\nimport { MonitorsApiService } from \"./services/monitors\";\nimport { SecretsApiService } from \"./services/secrets\";\nimport { type InternalConfig } from \"./types\";\nimport { createLangWatchApiClient, type LangwatchApiClient } from \"../internal/api/client\";\nimport { type Logger, NoOpLogger } from \"../logger\";\nimport { TracesFacade } from \"./services/traces/facade\";\nimport { DEFAULT_ENDPOINT } from \"@/internal/constants\";\n\nexport interface LangWatchConstructorOptions {\n apiKey?: string;\n endpoint?: string;\n options?: {\n logger?: Logger;\n };\n}\n\nexport class LangWatch {\n private readonly config: InternalConfig & { endpoint: string; apiKey: string };\n\n readonly prompts: PromptsFacade;\n readonly traces: TracesFacade;\n readonly datasets: DatasetsFacade;\n\n /**\n * Run experiments on LangWatch platform or via SDK.\n *\n * Platform experiments (CI/CD):\n * ```typescript\n * const result = await langwatch.experiments.run(\"my-experiment-slug\");\n * result.printSummary();\n * ```\n *\n * SDK-defined experiments:\n * ```typescript\n * const experiment = await langwatch.experiments.init(\"my-experiment\");\n * // ... run evaluators using experiment.evaluate()\n * ```\n */\n readonly experiments: ExperimentsFacade;\n\n /**\n * Run evaluators and guardrails in real-time (Online Evaluations).\n *\n * @example\n * ```typescript\n * const guardrail = await langwatch.evaluations.evaluate(\"presidio/pii_detection\", {\n * data: { input: userInput, output: generatedResponse },\n * name: \"PII Detection\",\n * asGuardrail: true,\n * });\n *\n * if (!guardrail.passed) {\n * return \"I'm sorry, I can't do that.\";\n * }\n * ```\n */\n readonly evaluations: EvaluationsFacade;\n\n readonly evaluators: EvaluatorsApiService;\n readonly scenarios: ScenariosApiService;\n readonly suites: SuitesApiService;\n readonly workflows: WorkflowsApiService;\n readonly agents: AgentsApiService;\n readonly annotations: AnnotationsApiService;\n readonly dashboards: DashboardsApiService;\n readonly modelProviders: ModelProvidersApiService;\n readonly analytics: AnalyticsApiService;\n readonly triggers: TriggersApiService;\n readonly graphs: GraphsApiService;\n readonly simulationRuns: SimulationRunsApiService;\n readonly monitors: MonitorsApiService;\n readonly secrets: SecretsApiService;\n\n constructor(options: LangWatchConstructorOptions = {}) {\n const apiKey = options.apiKey ?? process.env.LANGWATCH_API_KEY ?? \"\";\n const endpoint = options.endpoint ?? process.env.LANGWATCH_ENDPOINT ?? DEFAULT_ENDPOINT;\n\n this.config = this.#createInternalConfig({\n apiKey,\n endpoint,\n options: options.options,\n });\n\n this.prompts = new PromptsFacade({\n promptsApiService: new PromptsApiService(this.config),\n localPromptsService: new LocalPromptsService(),\n ...this.config,\n });\n this.traces = new TracesFacade(this.config);\n\n this.experiments = new ExperimentsFacade({\n langwatchApiClient: this.config.langwatchApiClient,\n endpoint: this.config.endpoint,\n apiKey: this.config.apiKey,\n logger: this.config.logger,\n });\n\n this.datasets = new DatasetsFacade({\n langwatchApiClient: this.config.langwatchApiClient,\n logger: this.config.logger,\n endpoint: this.config.endpoint,\n apiKey: this.config.apiKey,\n });\n\n this.evaluations = new EvaluationsFacade({\n endpoint: this.config.endpoint,\n apiKey: this.config.apiKey,\n logger: this.config.logger,\n });\n\n this.evaluators = new EvaluatorsApiService(this.config);\n this.scenarios = new ScenariosApiService(this.config);\n this.suites = new SuitesApiService(this.config);\n this.workflows = new WorkflowsApiService(this.config);\n this.agents = new AgentsApiService(this.config);\n this.annotations = new AnnotationsApiService(this.config);\n this.dashboards = new DashboardsApiService(this.config);\n this.modelProviders = new ModelProvidersApiService(this.config);\n this.analytics = new AnalyticsApiService(this.config);\n this.triggers = new TriggersApiService(this.config);\n this.graphs = new GraphsApiService(this.config);\n this.simulationRuns = new SimulationRunsApiService(this.config);\n this.monitors = new MonitorsApiService({ apiKey, endpoint });\n this.secrets = new SecretsApiService({ apiKey, endpoint });\n }\n\n get apiClient(): LangwatchApiClient {\n return this.config.langwatchApiClient;\n }\n\n #createInternalConfig({\n apiKey,\n endpoint,\n options,\n }: {\n apiKey: string;\n endpoint: string;\n options?: LangWatchConstructorOptions[\"options\"];\n }): InternalConfig & { endpoint: string; apiKey: string } {\n return {\n logger: options?.logger ?? new NoOpLogger(),\n langwatchApiClient: createLangWatchApiClient(apiKey, endpoint),\n endpoint,\n apiKey,\n };\n }\n}\n","import { ConsoleLogger, NoOpLogger } from \"./logger\";\n\nexport {\n getLangWatchTracer,\n getLangWatchLogger,\n attributes,\n} from \"./observability-sdk\";\n\nexport {\n FilterableBatchSpanProcessor,\n type SpanProcessingExcludeRule,\n} from \"./observability-sdk/processors\";\nexport { LangWatchExporter } from \"./observability-sdk/exporters\";\nexport { LangWatch, FetchPolicy, type GetPromptOptions } from \"./client-sdk\";\n\n/**\n * Typed API failures.\n *\n * When the platform DECLINES a request it says why, in a structure: a `code`\n * you can switch on, the `meta` that makes it actionable, and the trace id to\n * quote at support. Narrow with `isLangWatchHandledError` and match the `code`\n * rather than the message — the message is written for humans and may change;\n * the code is the contract.\n *\n * ```ts\n * try {\n * await langwatch.prompts.get(\"nope\");\n * } catch (error) {\n * if (isLangWatchHandledError(error) && error.code === \"prompt_not_found\") {\n * // ...\n * }\n * throw error;\n * }\n * ```\n *\n * Failures the platform did NOT name — a 5xx, a dead socket, a proxy's HTML —\n * still arrive as the generic errors they always did. A domain error means the\n * platform understood you and said no; anything else means it fell over, and\n * the two must not look alike.\n */\nexport {\n LangWatchHandledError,\n isLangWatchHandledError,\n LangWatchApiError,\n} from \"./internal/api/errors\";\nexport type {\n CliHandledError as LangWatchHandledErrorShape,\n CliHandledErrorReason as LangWatchHandledErrorReason,\n} from \"@langwatch/langy/cards/handled-error\";\n\n// Experiments API exports\nexport {\n Experiment,\n ExperimentsFacade,\n type EvaluationStatus as ExperimentEvaluationStatus,\n type TargetType,\n type TargetMetadata,\n type TargetInfo,\n type EvaluationResult as ExperimentEvaluationResult,\n type ExperimentInitOptions,\n type LogOptions,\n type EvaluateOptions as ExperimentEvaluateOptions,\n type RunOptions,\n type RunCallback,\n type RunContext,\n type RunWithResultsOptions,\n type ExperimentRowResult,\n type ExperimentRunWithResults,\n ExperimentError,\n ExperimentInitError,\n ExperimentApiError,\n TargetMetadataConflictError,\n EvaluatorError,\n} from \"./client-sdk/services/experiments\";\n\n// Evaluators API exports\nexport {\n EvaluatorsApiService,\n type EvaluatorResponse,\n type EvaluatorField,\n type CreateEvaluatorBody,\n EvaluatorsApiError,\n} from \"./client-sdk/services/evaluators\";\n\n// Dataset API exports\nexport {\n DatasetsFacade,\n DatasetError,\n DatasetNotFoundError,\n DatasetApiError,\n DatasetValidationError,\n DatasetPlanLimitError,\n type Dataset,\n type DatasetEntry,\n type DatasetMetadata,\n type DatasetColumnType,\n type DatasetListItem,\n type Pagination,\n type PaginatedResponse,\n type GetDatasetOptions,\n type ListDatasetsOptions,\n type ListDatasetsApiResponse,\n type ListRecordsOptions,\n type ListRecordsApiResponse,\n type CreateDatasetOptions,\n type UpdateDatasetOptions,\n type CreateFromUploadResponse,\n type BatchCreateRecordsResponse,\n type DeleteRecordsResponse,\n type UploadResponse,\n type DatasetRecordResponse,\n} from \"./client-sdk/services/datasets\";\n\n// Evaluations API exports (Online Evaluations / Guardrails)\nexport {\n EvaluationsFacade,\n type EvaluationResult,\n type EvaluateOptions,\n type EvaluationStatus,\n type EvaluationCost,\n EvaluationError,\n EvaluatorCallError,\n EvaluatorNotFoundError,\n EvaluationsApiError,\n} from \"./client-sdk/services/evaluations\";\n\nexport const logger = {\n ConsoleLogger,\n NoOpLogger,\n};\n"]}