@langwatch/mcp-server 2.1.0 → 3.0.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 (428) hide show
  1. package/.gitignore +7 -0
  2. package/.npmignore +41 -0
  3. package/CHANGELOG.md +218 -201
  4. package/CONTRIBUTING.md +10 -0
  5. package/README.md +70 -68
  6. package/dist/add-dashboard-widget-55UI6H22.js +44 -0
  7. package/dist/add-dashboard-widget-MJHIC3CC.js +45 -0
  8. package/dist/{archive-project-W3IKI7UL.js → archive-project-K5UD7A6X.js} +4 -4
  9. package/dist/archive-project-L4PAKT34.js +19 -0
  10. package/dist/{archive-run-plan-474OKHHU.js → archive-run-plan-5HSQG2HX.js} +4 -4
  11. package/dist/archive-run-plan-AOKNYQIO.js +15 -0
  12. package/dist/archive-scenario-2CWJW2VD.js +19 -0
  13. package/dist/{archive-scenario-V5UNYK26.js → archive-scenario-5IJQESHH.js} +4 -4
  14. package/dist/{archive-test-suite-O7FLDMXK.js → archive-test-suite-OPB7NFI7.js} +4 -4
  15. package/dist/archive-test-suite-ZC3TN6VH.js +15 -0
  16. package/dist/assign-prompt-tag-6DDE6ZZ5.js +23 -0
  17. package/dist/{assign-prompt-tag-Q46WRB6P.js → assign-prompt-tag-D7O23MJM.js} +8 -4
  18. package/dist/chunk-3YLN3ATJ.js +241 -0
  19. package/dist/{chunk-EYXMLE5X.js → chunk-4RX3G62A.js} +56 -47
  20. package/dist/{chunk-UF6XIGYR.js → chunk-6YZUOD34.js} +2 -5
  21. package/dist/{chunk-WVI5CJ6S.js → chunk-7AQLPVFL.js} +2 -2
  22. package/dist/chunk-7CZQDZ2K.js +319 -0
  23. package/dist/{chunk-RVAE2MEA.js → chunk-7GETGE6B.js} +7 -7
  24. package/dist/{chunk-OJLYYJWI.js → chunk-AASW2TO2.js} +7 -10
  25. package/dist/{chunk-QAMP3CGR.js → chunk-B4RFWIUP.js} +4 -4
  26. package/dist/{chunk-ZXKLPC2E.js → chunk-BIIKE3EI.js} +1 -1
  27. package/dist/{chunk-G4ZAZTZW.js → chunk-D2HS73VI.js} +7 -10
  28. package/dist/{chunk-37SMPMQS.js → chunk-DMM3JQ42.js} +7 -2
  29. package/dist/{chunk-WT4PO4A3.js → chunk-DULFP3MK.js} +10 -7
  30. package/dist/chunk-EYPJBL7P.js +516 -0
  31. package/dist/{chunk-NUFPTHKU.js → chunk-FOKVY3BK.js} +1 -1
  32. package/dist/chunk-GA5JUSPT.js +64 -0
  33. package/dist/{chunk-UJPXFA26.js → chunk-HHMNZAPD.js} +101 -74
  34. package/dist/chunk-HLQJXUR6.js +67 -0
  35. package/dist/{chunk-JTQJRNFJ.js → chunk-KILVK3FS.js} +4 -4
  36. package/dist/chunk-MOCU5XWF.js +79 -0
  37. package/dist/chunk-O2WGVCED.js +41 -0
  38. package/dist/{chunk-HV4DWKBI.js → chunk-O7EMWEVJ.js} +2 -4
  39. package/dist/{chunk-UFOYFYI7.js → chunk-QXLMHLRC.js} +6 -9
  40. package/dist/{chunk-QRO35SOM.js → chunk-R5YJIYPF.js} +981 -747
  41. package/dist/{chunk-JR6DJZOU.js → chunk-RABYBFX5.js} +4 -10
  42. package/dist/{chunk-SR6QPRIE.js → chunk-RFC2SBEX.js} +7 -13
  43. package/dist/chunk-SHSVN3SE.js +21 -0
  44. package/dist/{chunk-CKNAH5TG.js → chunk-U24EACC4.js} +3 -10
  45. package/dist/{chunk-56OGTS24.js → chunk-VOUGDY2O.js} +4 -11
  46. package/dist/chunk-WCKZDOGF.js +31 -0
  47. package/dist/chunk-XQYH52SI.js +129 -0
  48. package/dist/{chunk-7E4FZIYJ.js → chunk-XUIJYNRJ.js} +1 -1
  49. package/dist/{chunk-6DJDEXET.js → chunk-YCIUEZVK.js} +6 -12
  50. package/dist/config-2WQGMAEN.js +16 -0
  51. package/dist/config.cjs +109 -0
  52. package/dist/config.js +5 -4
  53. package/dist/{create-agent-JFJ2K6X3.js → create-agent-6JNLMYQD.js} +4 -4
  54. package/dist/create-agent-IRZOU4R5.js +23 -0
  55. package/dist/create-analytics-report-N4L4V5QL.js +19 -0
  56. package/dist/create-analytics-report-QEHXG7FU.js +18 -0
  57. package/dist/{create-annotation-EUXXQ6NS.js → create-annotation-CCEGIZ67.js} +10 -5
  58. package/dist/create-annotation-DTHCMWHB.js +29 -0
  59. package/dist/{create-api-key-BGBB76JX.js → create-api-key-JKM2DSZO.js} +5 -7
  60. package/dist/create-api-key-JPEUIXGM.js +24 -0
  61. package/dist/create-dataset-DJNXYJ5B.js +22 -0
  62. package/dist/{create-dataset-FD5VAXU4.js → create-dataset-WON4SOTC.js} +6 -6
  63. package/dist/create-dataset-records-TMEOTLTO.js +20 -0
  64. package/dist/{create-dataset-records-WQUXXOHI.js → create-dataset-records-UJBW3C7C.js} +5 -7
  65. package/dist/create-evaluator-N5AEHI4K.js +27 -0
  66. package/dist/{create-evaluator-6NV33Z52.js → create-evaluator-XYNY2YFY.js} +4 -4
  67. package/dist/create-mcp-server.cjs +9712 -0
  68. package/dist/create-mcp-server.js +2757 -10
  69. package/dist/{create-project-ZQ7TFIO2.js → create-project-EY4XZ7TH.js} +4 -4
  70. package/dist/create-project-YL345T5L.js +44 -0
  71. package/dist/{create-prompt-BS6QRCUU.js → create-prompt-JZQNQ7I3.js} +5 -7
  72. package/dist/create-prompt-ZUMQHHX7.js +37 -0
  73. package/dist/create-prompt-tag-CJ5FZ436.js +17 -0
  74. package/dist/{create-prompt-tag-FCQ5ELSQ.js → create-prompt-tag-JFP2Q3PO.js} +3 -3
  75. package/dist/create-scenario-CQU2SSFB.js +33 -0
  76. package/dist/{create-scenario-DRPTPXU3.js → create-scenario-S6OWWKJO.js} +5 -5
  77. package/dist/create-test-suite-OLGCAGJA.js +36 -0
  78. package/dist/{create-test-suite-ZIZCCFJ4.js → create-test-suite-Y7P2RI4L.js} +6 -6
  79. package/dist/create-trigger-4CNBTISJ.js +48 -0
  80. package/dist/create-trigger-RQ653WYF.js +49 -0
  81. package/dist/dashboards-BA7M6CMO.js +90 -0
  82. package/dist/dashboards-U663GUIB.js +91 -0
  83. package/dist/{delete-agent-SA4JMUZF.js → delete-agent-J2Q4DRZ2.js} +4 -4
  84. package/dist/delete-agent-ZAU4LTXB.js +18 -0
  85. package/dist/delete-analytics-report-QK6X7P4S.js +19 -0
  86. package/dist/delete-analytics-report-YUYLDHLL.js +18 -0
  87. package/dist/delete-annotation-7X4NYXXM.js +17 -0
  88. package/dist/{delete-annotation-X3KKK7QY.js → delete-annotation-KJOCDLV3.js} +4 -4
  89. package/dist/{delete-dataset-W6EZ44HY.js → delete-dataset-NXP7ZPPV.js} +5 -7
  90. package/dist/delete-dataset-RUTZBBVD.js +18 -0
  91. package/dist/{delete-dataset-records-7CNOTALB.js → delete-dataset-records-4Z7DZCDW.js} +5 -7
  92. package/dist/delete-dataset-records-75UAR5IS.js +19 -0
  93. package/dist/delete-evaluator-E3CUNGTQ.js +16 -0
  94. package/dist/delete-evaluator-RI4GALGX.js +15 -0
  95. package/dist/delete-prompt-tag-LE3WJPKS.js +17 -0
  96. package/dist/{delete-prompt-tag-QB3OCZUV.js → delete-prompt-tag-S4KBZTNG.js} +3 -3
  97. package/dist/delete-workflow-4CZFIQCQ.js +17 -0
  98. package/dist/{delete-workflow-NG2VXYYM.js → delete-workflow-PWQPDW6H.js} +4 -4
  99. package/dist/discover-evaluator-schema-UHWA5HVL.js +120 -0
  100. package/dist/discover-evaluator-schema-XKCLLCB3.js +118 -0
  101. package/dist/discover-scenario-schema-NOJY6S7E.js +137 -0
  102. package/dist/{discover-scenario-schema-W7KBXA4J.js → discover-scenario-schema-OOFIQKOG.js} +37 -17
  103. package/dist/discover-schema-7WHIIATI.js +442 -0
  104. package/dist/{discover-schema-L6QDPON3.js → discover-schema-J2ANOBKO.js} +181 -186
  105. package/dist/get-agent-5T3CXQOR.js +69 -0
  106. package/dist/{get-agent-7THF7HCU.js → get-agent-ZKYQJUQ7.js} +15 -11
  107. package/dist/get-analytics-4MPEK4KV.js +79 -0
  108. package/dist/get-analytics-ZLI3A4F5.js +80 -0
  109. package/dist/get-analytics-report-JCKYMA2S.js +29 -0
  110. package/dist/get-analytics-report-SKIP2JWH.js +30 -0
  111. package/dist/get-dataset-APGZBYMH.js +64 -0
  112. package/dist/get-dataset-LWXDVMVE.js +63 -0
  113. package/dist/get-evaluator-3A7BJBAB.js +47 -0
  114. package/dist/{get-evaluator-RZ44UIN6.js → get-evaluator-IWNJINRY.js} +4 -4
  115. package/dist/get-project-EQVB4LEL.js +26 -0
  116. package/dist/{get-project-QSQEAB33.js → get-project-RK6AJTEP.js} +4 -4
  117. package/dist/{get-prompt-GVKXF5NL.js → get-prompt-TLG2T2DS.js} +53 -58
  118. package/dist/get-prompt-ZER557X3.js +94 -0
  119. package/dist/get-run-plan-5X7DDJRN.js +58 -0
  120. package/dist/{get-run-plan-NY7J5GRE.js → get-run-plan-PEHRO5M3.js} +7 -9
  121. package/dist/{get-scenario-Q3LLQE4T.js → get-scenario-375W5D6I.js} +5 -5
  122. package/dist/get-scenario-UQX45ZZO.js +37 -0
  123. package/dist/{get-simulation-run-WINEYDMK.js → get-simulation-run-2NBXJADG.js} +26 -22
  124. package/dist/get-simulation-run-QZTLGL7W.js +69 -0
  125. package/dist/{get-test-suite-4HKA7OKS.js → get-test-suite-GVIBDG7K.js} +5 -5
  126. package/dist/get-test-suite-OODIR3RI.js +48 -0
  127. package/dist/{get-trace-RCUV7N4O.js → get-trace-AGCHVPJK.js} +11 -13
  128. package/dist/get-trace-KJLYAZRC.js +45 -0
  129. package/dist/get-workflow-3TV2YYC5.js +25 -0
  130. package/dist/{get-workflow-EEOC7Y45.js → get-workflow-7LZSVPP2.js} +4 -4
  131. package/dist/{http-security-EU3CHTY7.js → http-security-DNLBNQZL.js} +2 -2
  132. package/dist/{http-server-WCDUARTH.js → http-server-7CCN3EHJ.js} +4249 -325
  133. package/dist/index.js +59595 -38027
  134. package/dist/langwatch-api-analytics-reports-6CF6KUET.js +17 -0
  135. package/dist/langwatch-api-analytics-reports-RPFB5AO5.js +18 -0
  136. package/dist/{langwatch-api-annotations-6DHVZWUK.js → langwatch-api-annotations-H4AI4TKG.js} +4 -4
  137. package/dist/langwatch-api-annotations-QSJNUQQS.js +17 -0
  138. package/dist/langwatch-api-monitors-ENHLOL3S.js +47 -0
  139. package/dist/{langwatch-api-monitors-6ISFJ7WX.js → langwatch-api-monitors-OHSGADTH.js} +11 -16
  140. package/dist/langwatch-api-secrets-AGW6UUMD.js +55 -0
  141. package/dist/langwatch-api-secrets-CLTS766Q.js +56 -0
  142. package/dist/langwatch-api-triggers-G5UWFNN2.js +22 -0
  143. package/dist/langwatch-api-triggers-QMR7KEXW.js +23 -0
  144. package/dist/langwatch-api-workflows-HKTBIKKY.js +15 -0
  145. package/dist/{langwatch-api-workflows-6UJL5U4Z.js → langwatch-api-workflows-OMROZH2O.js} +4 -4
  146. package/dist/{list-agents-AMVDQPQL.js → list-agents-BYWDNAHT.js} +4 -4
  147. package/dist/list-agents-MG24MHZE.js +42 -0
  148. package/dist/list-analytics-reports-G3EPWGSQ.js +32 -0
  149. package/dist/list-analytics-reports-PPWIFRES.js +33 -0
  150. package/dist/list-annotations-QCLGEK5A.js +38 -0
  151. package/dist/{list-annotations-6PR5NLIC.js → list-annotations-Y4EUBJHG.js} +10 -5
  152. package/dist/list-api-keys-DAVOBPFK.js +42 -0
  153. package/dist/{list-api-keys-GVPNBIHQ.js → list-api-keys-JMW5WRXX.js} +10 -5
  154. package/dist/list-dashboards-2P3VJFRS.js +29 -0
  155. package/dist/list-dashboards-MW5O3MKH.js +30 -0
  156. package/dist/list-dataset-records-KEHT7G6Q.js +43 -0
  157. package/dist/{list-dataset-records-O67HZ35Y.js → list-dataset-records-KMLLMZAZ.js} +14 -10
  158. package/dist/{list-datasets-WXZL6UMP.js → list-datasets-P3JK2ZHS.js} +9 -13
  159. package/dist/list-datasets-Z7OOE4KI.js +56 -0
  160. package/dist/{list-evaluators-PAX72WCN.js → list-evaluators-7RRESBOU.js} +5 -7
  161. package/dist/list-evaluators-VATJVOHR.js +32 -0
  162. package/dist/{list-model-providers-VVLZMLCX.js → list-model-providers-OXDRPUCJ.js} +4 -4
  163. package/dist/list-model-providers-VXQJWDXU.js +35 -0
  164. package/dist/{list-projects-AQVI6SUK.js → list-projects-HUVK7L3W.js} +5 -7
  165. package/dist/list-projects-X72ZXVY5.js +40 -0
  166. package/dist/{list-prompt-tags-WZFBJOHG.js → list-prompt-tags-3I3LWFIR.js} +3 -3
  167. package/dist/list-prompt-tags-DRHUH2ND.js +23 -0
  168. package/dist/list-prompts-6DX3QECJ.js +30 -0
  169. package/dist/{list-prompts-BQOHRHYT.js → list-prompts-PS423RU3.js} +4 -6
  170. package/dist/list-run-plans-5SXPOV3X.js +45 -0
  171. package/dist/{list-run-plans-UBAU2DGH.js → list-run-plans-6VNHINPY.js} +5 -5
  172. package/dist/list-scenarios-EQWCW7Q4.js +45 -0
  173. package/dist/{list-scenarios-MS4IUIVM.js → list-scenarios-GKNH3YND.js} +13 -11
  174. package/dist/{list-simulation-runs-D6YF4ZOU.js → list-simulation-runs-KHY7KALI.js} +12 -8
  175. package/dist/list-simulation-runs-PUDK32C2.js +53 -0
  176. package/dist/list-test-suites-7H2DRILK.js +34 -0
  177. package/dist/{list-test-suites-L7R2O6DR.js → list-test-suites-GY56LGLY.js} +4 -4
  178. package/dist/list-trigger-fires-7RZUP54Y.js +19 -0
  179. package/dist/list-trigger-fires-OZUF65LI.js +20 -0
  180. package/dist/list-triggers-BGUCUXTJ.js +45 -0
  181. package/dist/list-triggers-XC5KMX4C.js +46 -0
  182. package/dist/list-workflows-55NYC3PC.js +33 -0
  183. package/dist/{list-workflows-6MV4XJHF.js → list-workflows-HV7FUWZA.js} +5 -7
  184. package/dist/{rename-prompt-tag-K5LQ4CY6.js → rename-prompt-tag-2I7Z5FCY.js} +3 -3
  185. package/dist/rename-prompt-tag-SZYTOWDX.js +18 -0
  186. package/dist/{rename-test-suite-NTYHAO5X.js → rename-test-suite-27AYY33K.js} +4 -4
  187. package/dist/rename-test-suite-CLIEPZDO.js +20 -0
  188. package/dist/report-issue-5HSL7CNB.js +924 -0
  189. package/dist/{report-issue-RHZZ33IS.js → report-issue-N7ND5TM6.js} +107 -67
  190. package/dist/{rerun-run-plan-MUDWJBE4.js → rerun-run-plan-O3VUZ6CG.js} +5 -5
  191. package/dist/rerun-run-plan-OJTVVGJI.js +21 -0
  192. package/dist/{revoke-api-key-6LAZ3QZZ.js → revoke-api-key-BU6BKGCG.js} +4 -4
  193. package/dist/revoke-api-key-NZNCFOIR.js +15 -0
  194. package/dist/run-agent-244O4Y5M.js +75 -0
  195. package/dist/run-agent-HPCGZGYW.js +74 -0
  196. package/dist/run-plan-2ZPGGZ4H.js +38 -0
  197. package/dist/{run-plan-T4ZYOZGA.js → run-plan-KSXUYQT3.js} +7 -7
  198. package/dist/run-query-4LMOQ5UW.js +47 -0
  199. package/dist/run-query-BQUHIUC2.js +46 -0
  200. package/dist/{run-test-suite-L4MZ7G4D.js → run-test-suite-P3WLVPXC.js} +6 -6
  201. package/dist/run-test-suite-UEOMCON6.js +25 -0
  202. package/dist/run-workflow-EFZ6HG5B.js +36 -0
  203. package/dist/{run-workflow-DFIS23AP.js → run-workflow-I4IHEN54.js} +4 -4
  204. package/dist/search-traces-6IR7PR4L.js +170 -0
  205. package/dist/search-traces-BYML2NQ4.js +171 -0
  206. package/dist/set-model-provider-RBNGWFVI.js +33 -0
  207. package/dist/{set-model-provider-XRNMFOVR.js → set-model-provider-SHEVKWRC.js} +4 -4
  208. package/dist/{update-agent-DUWNYBNA.js → update-agent-PTKTM2B5.js} +4 -4
  209. package/dist/update-agent-ZPXWRMS2.js +20 -0
  210. package/dist/update-dashboard-widget-HKCBXH7X.js +62 -0
  211. package/dist/update-dashboard-widget-IP2TTQ5G.js +63 -0
  212. package/dist/update-dataset-GHIN6JR3.js +22 -0
  213. package/dist/{update-dataset-YSOMDCOB.js → update-dataset-IRVMY5PF.js} +6 -6
  214. package/dist/update-dataset-record-6VI7K2CL.js +19 -0
  215. package/dist/{update-dataset-record-DEA2ITYR.js → update-dataset-record-Z3L7ACNF.js} +4 -4
  216. package/dist/update-evaluator-5NLNE6VY.js +24 -0
  217. package/dist/{update-evaluator-NH7Q5GWV.js → update-evaluator-FEH7H6NS.js} +4 -4
  218. package/dist/update-project-75H3LDQT.js +24 -0
  219. package/dist/{update-project-Q26FBSYH.js → update-project-QPR3QX55.js} +4 -4
  220. package/dist/update-prompt-BCDFTNLK.js +140 -0
  221. package/dist/{update-prompt-ZQQ2C3KU.js → update-prompt-NPRXYSWA.js} +27 -29
  222. package/dist/update-scenario-BNOMDCMV.js +34 -0
  223. package/dist/{update-scenario-WUX34JAR.js → update-scenario-EM5XGMB7.js} +5 -5
  224. package/package.json +35 -39
  225. package/pyproject.toml +23 -8
  226. package/src/config.d.ts +6 -0
  227. package/src/config.ts +22 -29
  228. package/src/create-mcp-server.ts +887 -634
  229. package/src/documentation-fetch.ts +21 -20
  230. package/src/http-security.ts +166 -135
  231. package/src/http-server.ts +189 -224
  232. package/src/index.ts +14 -16
  233. package/src/langwatch-api-agents.ts +18 -21
  234. package/src/langwatch-api-analytics-reports.ts +62 -0
  235. package/src/langwatch-api-annotations.ts +11 -12
  236. package/src/langwatch-api-api-keys.ts +8 -9
  237. package/src/langwatch-api-dashboard-widgets.ts +47 -0
  238. package/src/langwatch-api-dashboards.ts +109 -24
  239. package/src/langwatch-api-datasets.ts +98 -32
  240. package/src/langwatch-api-evaluators.ts +13 -19
  241. package/src/langwatch-api-model-providers.ts +4 -4
  242. package/src/langwatch-api-monitors.ts +14 -18
  243. package/src/langwatch-api-projects.ts +10 -9
  244. package/src/langwatch-api-query.ts +114 -0
  245. package/src/langwatch-api-run-plans.ts +12 -29
  246. package/src/langwatch-api-scenarios.ts +9 -11
  247. package/src/langwatch-api-secrets.ts +31 -24
  248. package/src/langwatch-api-simulation-runs.ts +6 -8
  249. package/src/langwatch-api-test-suites.ts +14 -33
  250. package/src/langwatch-api-triggers.ts +96 -34
  251. package/src/langwatch-api-workflows.ts +9 -9
  252. package/src/langwatch-api.ts +118 -124
  253. package/src/public-http-request.ts +21 -12
  254. package/src/schemas/analytics-metrics.ts +3 -15
  255. package/src/schemas/create-dataset.ts +3 -4
  256. package/src/schemas/run-plan.ts +13 -29
  257. package/src/schemas/suite-fields.ts +6 -23
  258. package/src/schemas/triggers.ts +365 -0
  259. package/src/schemas/widget-sources.ts +33 -0
  260. package/src/tools/add-dashboard-widget.ts +51 -0
  261. package/src/tools/archive-project.ts +2 -4
  262. package/src/tools/archive-run-plan.ts +2 -4
  263. package/src/tools/archive-scenario.ts +2 -4
  264. package/src/tools/archive-test-suite.ts +2 -4
  265. package/src/tools/assign-prompt-tag.ts +6 -2
  266. package/src/tools/create-agent.ts +1 -1
  267. package/src/tools/create-analytics-report.ts +7 -0
  268. package/src/tools/create-annotation.ts +7 -2
  269. package/src/tools/create-api-key.ts +4 -6
  270. package/src/tools/create-dataset-records.ts +4 -8
  271. package/src/tools/create-dataset.ts +5 -7
  272. package/src/tools/create-evaluator.ts +3 -5
  273. package/src/tools/create-project.ts +2 -2
  274. package/src/tools/create-prompt-tag.ts +2 -4
  275. package/src/tools/create-prompt.ts +9 -18
  276. package/src/tools/create-scenario.ts +5 -7
  277. package/src/tools/create-test-suite.ts +4 -9
  278. package/src/tools/create-trigger.ts +55 -0
  279. package/src/tools/dashboard-widget-queries.ts +45 -0
  280. package/src/tools/dashboards.ts +104 -0
  281. package/src/tools/delete-agent.ts +1 -1
  282. package/src/tools/delete-analytics-report.ts +7 -0
  283. package/src/tools/delete-annotation.ts +1 -1
  284. package/src/tools/delete-dataset-records.ts +4 -8
  285. package/src/tools/delete-dataset.ts +3 -7
  286. package/src/tools/delete-evaluator.ts +4 -6
  287. package/src/tools/delete-prompt-tag.ts +2 -4
  288. package/src/tools/delete-workflow.ts +1 -1
  289. package/src/tools/discover-evaluator-schema.ts +34 -25
  290. package/src/tools/discover-scenario-schema.ts +41 -21
  291. package/src/tools/discover-schema.ts +149 -27
  292. package/src/tools/experiment-run-status.ts +2 -8
  293. package/src/tools/format-dataset-mutation.ts +5 -10
  294. package/src/tools/format-run-plan.ts +7 -21
  295. package/src/tools/format-scenario.ts +2 -4
  296. package/src/tools/format-suite-details.ts +6 -12
  297. package/src/tools/get-agent.ts +15 -6
  298. package/src/tools/get-analytics-report.ts +23 -0
  299. package/src/tools/get-analytics.ts +52 -46
  300. package/src/tools/get-dataset.ts +34 -16
  301. package/src/tools/get-evaluator.ts +4 -11
  302. package/src/tools/get-experiment-results.ts +219 -186
  303. package/src/tools/get-project.ts +2 -4
  304. package/src/tools/get-prompt.ts +63 -84
  305. package/src/tools/get-run-plan.ts +4 -6
  306. package/src/tools/get-scenario.ts +4 -6
  307. package/src/tools/get-simulation-run.ts +27 -24
  308. package/src/tools/get-test-suite.ts +2 -5
  309. package/src/tools/get-trace.ts +16 -17
  310. package/src/tools/get-workflow.ts +1 -1
  311. package/src/tools/list-agents.ts +1 -1
  312. package/src/tools/list-analytics-reports.ts +27 -0
  313. package/src/tools/list-annotations.ts +8 -5
  314. package/src/tools/list-api-keys.ts +7 -2
  315. package/src/tools/list-dashboards.ts +20 -21
  316. package/src/tools/list-dataset-records.ts +8 -6
  317. package/src/tools/list-datasets.ts +12 -23
  318. package/src/tools/list-evaluators.ts +4 -8
  319. package/src/tools/list-experiment-runs.ts +5 -9
  320. package/src/tools/list-experiments.ts +5 -11
  321. package/src/tools/list-model-providers.ts +3 -5
  322. package/src/tools/list-projects.ts +2 -4
  323. package/src/tools/list-prompt-tags.ts +3 -3
  324. package/src/tools/list-prompts.ts +4 -8
  325. package/src/tools/list-run-plans.ts +2 -2
  326. package/src/tools/list-scenarios.ts +14 -15
  327. package/src/tools/list-simulation-runs.ts +8 -4
  328. package/src/tools/list-test-suites.ts +1 -1
  329. package/src/tools/list-trigger-fires.ts +17 -0
  330. package/src/tools/list-triggers.ts +39 -0
  331. package/src/tools/list-workflows.ts +2 -4
  332. package/src/tools/rename-prompt-tag.ts +1 -1
  333. package/src/tools/rename-test-suite.ts +2 -5
  334. package/src/tools/report-issue.ts +7 -9
  335. package/src/tools/rerun-run-plan.ts +2 -5
  336. package/src/tools/revoke-api-key.ts +2 -4
  337. package/src/tools/run-agent.ts +29 -26
  338. package/src/tools/run-experiment.ts +37 -34
  339. package/src/tools/run-plan.ts +4 -7
  340. package/src/tools/run-query.ts +47 -0
  341. package/src/tools/run-test-suite.ts +4 -7
  342. package/src/tools/run-workflow.ts +2 -5
  343. package/src/tools/search-traces.ts +161 -47
  344. package/src/tools/set-model-provider.ts +4 -6
  345. package/src/tools/test-agent.ts +2 -2
  346. package/src/tools/update-agent.ts +1 -1
  347. package/src/tools/update-dashboard-widget.ts +86 -0
  348. package/src/tools/update-dataset-record.ts +1 -1
  349. package/src/tools/update-dataset.ts +5 -7
  350. package/src/tools/update-evaluator.ts +3 -5
  351. package/src/tools/update-project.ts +1 -1
  352. package/src/tools/update-prompt.ts +44 -59
  353. package/src/tools/update-scenario.ts +5 -7
  354. package/src/tools/update-test-suite.ts +6 -11
  355. package/src/utils/date-parsing.ts +1 -1
  356. package/src/utils/escape-markdown.ts +3 -8
  357. package/src/utils/format-evaluations.ts +6 -6
  358. package/src/utils/markdown-table.ts +58 -0
  359. package/src/utils/trace-id-shape.ts +20 -0
  360. package/tsconfig.app.json +24 -0
  361. package/tsconfig.json +14 -12
  362. package/uv.lock +667 -341
  363. package/vitest.integration.config.js +10 -0
  364. package/vitest.scenario.config.js +9 -0
  365. package/.eslintrc.cjs +0 -36
  366. package/dist/chunk-AN4OUA4D.js +0 -86
  367. package/dist/chunk-GELJ2MQR.js +0 -226
  368. package/dist/chunk-K37ZNPXK.js +0 -24
  369. package/dist/chunk-S4GVX36W.js +0 -39
  370. package/dist/config.d.ts +0 -17
  371. package/dist/create-dashboard-Z76AIPLS.js +0 -19
  372. package/dist/create-mcp-server.d.ts +0 -10
  373. package/dist/delete-dashboard-LYMRPF27.js +0 -19
  374. package/dist/delete-evaluator-RKYC4TNB.js +0 -16
  375. package/dist/discover-evaluator-schema-ESSHQGPY.js +0 -1912
  376. package/dist/get-analytics-R6AZD3AW.js +0 -73
  377. package/dist/get-dashboard-P4WWVHFU.js +0 -30
  378. package/dist/get-dataset-AKTYSQDI.js +0 -49
  379. package/dist/index.d.ts +0 -2
  380. package/dist/langwatch-api-dashboards-2KJL2M42.js +0 -18
  381. package/dist/langwatch-api-secrets-OEBD6GBU.js +0 -41
  382. package/dist/langwatch-api-triggers-5E6DDGX6.js +0 -31
  383. package/dist/list-dashboards-Z3BZKDGF.js +0 -33
  384. package/dist/run-agent-CAGWGTYT.js +0 -72
  385. package/dist/search-traces-4XTJYXIK.js +0 -79
  386. package/src/__tests__/agent-tools.unit.test.ts +0 -257
  387. package/src/__tests__/all-tools.integration.test.ts +0 -1872
  388. package/src/__tests__/config.unit.test.ts +0 -202
  389. package/src/__tests__/datasets.integration.test.ts +0 -620
  390. package/src/__tests__/datasets.unit.test.ts +0 -244
  391. package/src/__tests__/date-parsing.unit.test.ts +0 -78
  392. package/src/__tests__/discover-evaluator-schema.unit.test.ts +0 -89
  393. package/src/__tests__/discover-schema.unit.test.ts +0 -118
  394. package/src/__tests__/docker.integration.test.ts +0 -318
  395. package/src/__tests__/documentation-fetch-security.integration.test.ts +0 -182
  396. package/src/__tests__/evaluator-tools.unit.test.ts +0 -262
  397. package/src/__tests__/experiment-list-tools.unit.test.ts +0 -157
  398. package/src/__tests__/experiment-status.unit.test.ts +0 -194
  399. package/src/__tests__/feature-map-tool-drift.unit.test.ts +0 -93
  400. package/src/__tests__/get-experiment-results.unit.test.ts +0 -313
  401. package/src/__tests__/http-security-origin.unit.test.ts +0 -97
  402. package/src/__tests__/http-security-sessions.unit.test.ts +0 -209
  403. package/src/__tests__/http-security-verifier.unit.test.ts +0 -248
  404. package/src/__tests__/http-server-allocation.integration.test.ts +0 -279
  405. package/src/__tests__/http-server-origin.integration.test.ts +0 -169
  406. package/src/__tests__/http-server-session-auth.integration.test.ts +0 -341
  407. package/src/__tests__/http-transport.integration.test.ts +0 -395
  408. package/src/__tests__/integration.integration.test.ts +0 -284
  409. package/src/__tests__/langwatch-api.unit.test.ts +0 -661
  410. package/src/__tests__/model-provider-tools.unit.test.ts +0 -190
  411. package/src/__tests__/project-api-key-tools.unit.test.ts +0 -451
  412. package/src/__tests__/prompt-response-types.unit.test.ts +0 -51
  413. package/src/__tests__/prompts.integration.test.ts +0 -736
  414. package/src/__tests__/public-http-request-security.integration.test.ts +0 -118
  415. package/src/__tests__/report-issue.integration.test.ts +0 -147
  416. package/src/__tests__/run-plan-tools.unit.test.ts +0 -565
  417. package/src/__tests__/scenario-tools.integration.test.ts +0 -286
  418. package/src/__tests__/scenario-tools.unit.test.ts +0 -207
  419. package/src/__tests__/schemas.unit.test.ts +0 -85
  420. package/src/__tests__/simulation-run-tools.unit.test.ts +0 -116
  421. package/src/__tests__/support/http-server-harness.ts +0 -138
  422. package/src/__tests__/test-suite-tools.unit.test.ts +0 -615
  423. package/src/__tests__/tools.integration.test.ts +0 -896
  424. package/src/schemas/filter-fields.ts +0 -119
  425. package/src/schemas/index.ts +0 -9
  426. package/src/tools/create-dashboard.ts +0 -7
  427. package/src/tools/delete-dashboard.ts +0 -7
  428. package/src/tools/get-dashboard.ts +0 -22
@@ -1,661 +0,0 @@
1
- import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
2
- import { initConfig } from "../config.js";
3
-
4
- const TEST_ENDPOINT = "https://test.langwatch.ai";
5
- const TEST_API_KEY = "test-key";
6
-
7
- describe("langwatch-api", () => {
8
- let mockFetch: ReturnType<typeof vi.fn>;
9
-
10
- beforeEach(() => {
11
- initConfig({ apiKey: TEST_API_KEY, endpoint: TEST_ENDPOINT });
12
- mockFetch = vi.fn();
13
- vi.stubGlobal("fetch", mockFetch);
14
- });
15
-
16
- afterEach(() => {
17
- vi.unstubAllGlobals();
18
- });
19
-
20
- function mockJsonResponse(data: unknown, status = 200) {
21
- mockFetch.mockResolvedValueOnce({
22
- ok: status >= 200 && status < 300,
23
- status,
24
- text: async () => JSON.stringify(data),
25
- json: async () => data,
26
- });
27
- }
28
-
29
- function mockErrorResponse(status: number, body: string) {
30
- mockFetch.mockResolvedValueOnce({
31
- ok: false,
32
- status,
33
- text: async () => body,
34
- });
35
- }
36
-
37
- function mock204Response() {
38
- mockFetch.mockResolvedValueOnce({
39
- ok: true,
40
- status: 204,
41
- text: async () => "",
42
- json: async () => { throw new Error("No content"); },
43
- });
44
- }
45
-
46
- describe("searchTraces()", () => {
47
- it("sends POST to /api/traces/search with format digest by default", async () => {
48
- const { searchTraces } = await import("../langwatch-api.js");
49
- const responseData = { traces: [] };
50
- mockJsonResponse(responseData);
51
-
52
- const result = await searchTraces({
53
- startDate: 1000,
54
- endDate: 2000,
55
- query: "hello",
56
- });
57
-
58
- const [calledUrl, calledOptions] = mockFetch.mock.calls[0]!;
59
- expect(calledUrl).toBe(`${TEST_ENDPOINT}/api/traces/search`);
60
- expect(calledOptions.method).toBe("POST");
61
- expect(calledOptions.headers["X-Auth-Token"]).toBe(TEST_API_KEY);
62
- expect(calledOptions.headers["Content-Type"]).toBe("application/json");
63
-
64
- const parsedBody = JSON.parse(calledOptions.body as string);
65
- expect(parsedBody).toEqual({
66
- query: "hello",
67
- startDate: 1000,
68
- endDate: 2000,
69
- format: "digest",
70
- });
71
- expect(result).toEqual(responseData);
72
- });
73
-
74
- it("sends format json when specified", async () => {
75
- const { searchTraces } = await import("../langwatch-api.js");
76
- mockJsonResponse({ traces: [] });
77
-
78
- await searchTraces({
79
- startDate: 1000,
80
- endDate: 2000,
81
- format: "json",
82
- });
83
-
84
- const parsedBody = JSON.parse(mockFetch.mock.calls[0]![1]!.body as string);
85
- expect(parsedBody.format).toBe("json");
86
- });
87
-
88
- describe("when response is not OK", () => {
89
- it("throws a descriptive error with status code and body", async () => {
90
- const { searchTraces } = await import("../langwatch-api.js");
91
- mockErrorResponse(401, "Unauthorized");
92
-
93
- await expect(
94
- searchTraces({ startDate: 1000, endDate: 2000 })
95
- ).rejects.toThrow("401");
96
- });
97
- });
98
- });
99
-
100
- describe("getTraceById()", () => {
101
- it("sends GET to /api/traces/{id}?format=digest by default", async () => {
102
- const { getTraceById } = await import("../langwatch-api.js");
103
- const responseData = { trace: { id: "abc" } };
104
- mockJsonResponse(responseData);
105
-
106
- const result = await getTraceById("abc");
107
-
108
- expect(mockFetch).toHaveBeenCalledWith(
109
- `${TEST_ENDPOINT}/api/traces/abc?format=digest`,
110
- expect.objectContaining({
111
- method: "GET",
112
- headers: expect.objectContaining({
113
- "X-Auth-Token": TEST_API_KEY,
114
- }),
115
- })
116
- );
117
- expect(result).toEqual(responseData);
118
- });
119
-
120
- it("sends format=json when specified", async () => {
121
- const { getTraceById } = await import("../langwatch-api.js");
122
- mockJsonResponse({});
123
-
124
- await getTraceById("abc", "json");
125
-
126
- expect(mockFetch).toHaveBeenCalledWith(
127
- `${TEST_ENDPOINT}/api/traces/abc?format=json`,
128
- expect.anything()
129
- );
130
- });
131
-
132
- it("does not include Content-Type for GET requests", async () => {
133
- const { getTraceById } = await import("../langwatch-api.js");
134
- mockJsonResponse({});
135
-
136
- await getTraceById("abc");
137
-
138
- const callHeaders = mockFetch.mock.calls[0]![1]!.headers as Record<
139
- string,
140
- string
141
- >;
142
- expect(callHeaders["Content-Type"]).toBeUndefined();
143
- });
144
- });
145
-
146
- describe("getAnalyticsTimeseries()", () => {
147
- it("sends POST to /api/analytics/timeseries", async () => {
148
- const { getAnalyticsTimeseries } = await import("../langwatch-api.js");
149
- const params = {
150
- series: [{ metric: "performance.completion_time", aggregation: "avg" }],
151
- startDate: 1000,
152
- endDate: 2000,
153
- };
154
- const responseData = { data: [] };
155
- mockJsonResponse(responseData);
156
-
157
- const result = await getAnalyticsTimeseries(params);
158
-
159
- expect(mockFetch).toHaveBeenCalledWith(
160
- `${TEST_ENDPOINT}/api/analytics/timeseries`,
161
- expect.objectContaining({
162
- method: "POST",
163
- headers: expect.objectContaining({
164
- "X-Auth-Token": TEST_API_KEY,
165
- "Content-Type": "application/json",
166
- }),
167
- body: JSON.stringify(params),
168
- })
169
- );
170
- expect(result).toEqual(responseData);
171
- });
172
- });
173
-
174
- describe("listPrompts()", () => {
175
- it("sends GET to /api/prompts", async () => {
176
- const { listPrompts } = await import("../langwatch-api.js");
177
- const responseData = [{ id: "1", name: "test" }];
178
- mockJsonResponse(responseData);
179
-
180
- const result = await listPrompts();
181
-
182
- expect(mockFetch).toHaveBeenCalledWith(
183
- `${TEST_ENDPOINT}/api/prompts`,
184
- expect.objectContaining({
185
- method: "GET",
186
- headers: expect.objectContaining({
187
- "X-Auth-Token": TEST_API_KEY,
188
- }),
189
- })
190
- );
191
- expect(result).toEqual(responseData);
192
- });
193
- });
194
-
195
- describe("getPrompt()", () => {
196
- it("sends GET to /api/prompts/{id} with encoded ID", async () => {
197
- const { getPrompt } = await import("../langwatch-api.js");
198
- const responseData = { id: "1", name: "test" };
199
- mockJsonResponse(responseData);
200
-
201
- const result = await getPrompt("my prompt/v1");
202
-
203
- expect(mockFetch).toHaveBeenCalledWith(
204
- `${TEST_ENDPOINT}/api/prompts/${encodeURIComponent("my prompt/v1")}`,
205
- expect.objectContaining({
206
- method: "GET",
207
- headers: expect.objectContaining({
208
- "X-Auth-Token": TEST_API_KEY,
209
- }),
210
- })
211
- );
212
- expect(result).toEqual(responseData);
213
- });
214
- });
215
-
216
- describe("createPrompt()", () => {
217
- it("sends POST to /api/prompts with body", async () => {
218
- const { createPrompt } = await import("../langwatch-api.js");
219
- const data = {
220
- handle: "test-prompt",
221
- messages: [{ role: "system", content: "You are helpful." }],
222
- model: "openai/gpt-4o",
223
- };
224
- const responseData = { id: "new-id", ...data };
225
- mockJsonResponse(responseData);
226
-
227
- const result = await createPrompt(data);
228
-
229
- expect(mockFetch).toHaveBeenCalledWith(
230
- `${TEST_ENDPOINT}/api/prompts`,
231
- expect.objectContaining({
232
- method: "POST",
233
- headers: expect.objectContaining({
234
- "X-Auth-Token": TEST_API_KEY,
235
- "Content-Type": "application/json",
236
- }),
237
- body: JSON.stringify(data),
238
- })
239
- );
240
- expect(result).toEqual(responseData);
241
- });
242
- });
243
-
244
- describe("updatePrompt()", () => {
245
- it("sends PUT to /api/prompts/{id} with body", async () => {
246
- const { updatePrompt } = await import("../langwatch-api.js");
247
- const data = {
248
- messages: [{ role: "system", content: "Updated" }],
249
- commitMessage: "update system prompt",
250
- };
251
- const responseData = { id: "p1", ...data };
252
- mockJsonResponse(responseData);
253
-
254
- const result = await updatePrompt("p1", data);
255
-
256
- expect(mockFetch).toHaveBeenCalledWith(
257
- `${TEST_ENDPOINT}/api/prompts/${encodeURIComponent("p1")}`,
258
- expect.objectContaining({
259
- method: "PUT",
260
- headers: expect.objectContaining({
261
- "X-Auth-Token": TEST_API_KEY,
262
- "Content-Type": "application/json",
263
- }),
264
- body: JSON.stringify(data),
265
- })
266
- );
267
- expect(result).toEqual(responseData);
268
- });
269
- });
270
-
271
- describe("getPrompt() with tag options", () => {
272
- describe("when called with tag option", () => {
273
- it("appends tag query parameter", async () => {
274
- const { getPrompt } = await import("../langwatch-api.js");
275
- mockJsonResponse({ id: "1" });
276
-
277
- await getPrompt("pizza-prompt", { tag: "production" });
278
-
279
- expect(mockFetch).toHaveBeenCalledWith(
280
- `${TEST_ENDPOINT}/api/prompts/${encodeURIComponent("pizza-prompt")}?tag=production`,
281
- expect.objectContaining({ method: "GET" })
282
- );
283
- });
284
- });
285
-
286
- describe("when called with version option", () => {
287
- it("appends version query parameter", async () => {
288
- const { getPrompt } = await import("../langwatch-api.js");
289
- mockJsonResponse({ id: "1" });
290
-
291
- await getPrompt("pizza-prompt", { version: 2 });
292
-
293
- expect(mockFetch).toHaveBeenCalledWith(
294
- `${TEST_ENDPOINT}/api/prompts/${encodeURIComponent("pizza-prompt")}?version=2`,
295
- expect.objectContaining({ method: "GET" })
296
- );
297
- });
298
- });
299
-
300
- describe("when called with no options", () => {
301
- it("sends no query string", async () => {
302
- const { getPrompt } = await import("../langwatch-api.js");
303
- mockJsonResponse({ id: "1" });
304
-
305
- await getPrompt("pizza-prompt");
306
-
307
- expect(mockFetch).toHaveBeenCalledWith(
308
- `${TEST_ENDPOINT}/api/prompts/${encodeURIComponent("pizza-prompt")}`,
309
- expect.objectContaining({ method: "GET" })
310
- );
311
- });
312
- });
313
- });
314
-
315
- describe("createPrompt() with tags", () => {
316
- describe("when called with tags", () => {
317
- it("includes tags in the request body", async () => {
318
- const { createPrompt } = await import("../langwatch-api.js");
319
- const data = {
320
- handle: "test",
321
- messages: [{ role: "system", content: "hi" }],
322
- model: "openai/gpt-5-mini",
323
- tags: ["production", "staging"],
324
- };
325
- mockJsonResponse({ id: "new" });
326
-
327
- await createPrompt(data);
328
-
329
- const body = JSON.parse(mockFetch.mock.calls[0]![1]!.body as string);
330
- expect(body.tags).toEqual(["production", "staging"]);
331
- });
332
- });
333
- });
334
-
335
- describe("updatePrompt() with tags", () => {
336
- describe("when called with tags", () => {
337
- it("includes tags in the request body", async () => {
338
- const { updatePrompt } = await import("../langwatch-api.js");
339
- mockJsonResponse({ id: "p1" });
340
-
341
- await updatePrompt("p1", {
342
- commitMessage: "tag it",
343
- tags: ["production"],
344
- });
345
-
346
- const body = JSON.parse(mockFetch.mock.calls[0]![1]!.body as string);
347
- expect(body.tags).toEqual(["production"]);
348
- });
349
- });
350
- });
351
-
352
- describe("assignPromptTag()", () => {
353
- it("sends PUT to /api/prompts/{id}/tags/{tag} with versionId", async () => {
354
- const { assignPromptTag } = await import("../langwatch-api.js");
355
- mockJsonResponse({ success: true });
356
-
357
- await assignPromptTag({ idOrHandle: "pizza-prompt", tag: "production", versionId: "v123" });
358
-
359
- const [url, opts] = mockFetch.mock.calls[0]!;
360
- expect(url).toBe(`${TEST_ENDPOINT}/api/prompts/pizza-prompt/tags/production`);
361
- expect(opts.method).toBe("PUT");
362
- expect(JSON.parse(opts.body as string)).toEqual({ versionId: "v123" });
363
- });
364
- });
365
-
366
- describe("listPromptTags()", () => {
367
- it("sends GET to /api/prompts/tags", async () => {
368
- const { listPromptTags } = await import("../langwatch-api.js");
369
- const tags = [{ id: "1", name: "production" }];
370
- mockJsonResponse(tags);
371
-
372
- const result = await listPromptTags();
373
-
374
- expect(mockFetch).toHaveBeenCalledWith(
375
- `${TEST_ENDPOINT}/api/prompts/tags`,
376
- expect.objectContaining({ method: "GET" })
377
- );
378
- expect(result).toEqual(tags);
379
- });
380
- });
381
-
382
- describe("createPromptTag()", () => {
383
- it("sends POST to /api/prompts/tags with name", async () => {
384
- const { createPromptTag } = await import("../langwatch-api.js");
385
- mockJsonResponse({ id: "t1", name: "canary" });
386
-
387
- await createPromptTag("canary");
388
-
389
- const [url, opts] = mockFetch.mock.calls[0]!;
390
- expect(url).toBe(`${TEST_ENDPOINT}/api/prompts/tags`);
391
- expect(opts.method).toBe("POST");
392
- expect(JSON.parse(opts.body as string)).toEqual({ name: "canary" });
393
- });
394
- });
395
-
396
- describe("renamePromptTag()", () => {
397
- it("sends PUT to /api/prompts/tags/{tag} with new name", async () => {
398
- const { renamePromptTag } = await import("../langwatch-api.js");
399
- mockJsonResponse({ id: "t1", name: "preview" });
400
-
401
- await renamePromptTag({ tag: "canary", name: "preview" });
402
-
403
- const [url, opts] = mockFetch.mock.calls[0]!;
404
- expect(url).toBe(`${TEST_ENDPOINT}/api/prompts/tags/canary`);
405
- expect(opts.method).toBe("PUT");
406
- expect(JSON.parse(opts.body as string)).toEqual({ name: "preview" });
407
- });
408
- });
409
-
410
- describe("deletePromptTag()", () => {
411
- it("sends DELETE to /api/prompts/tags/{tag}", async () => {
412
- const { deletePromptTag } = await import("../langwatch-api.js");
413
- mock204Response();
414
-
415
- const result = await deletePromptTag("canary");
416
-
417
- const [url, opts] = mockFetch.mock.calls[0]!;
418
- expect(url).toBe(`${TEST_ENDPOINT}/api/prompts/tags/canary`);
419
- expect(opts.method).toBe("DELETE");
420
- expect(result).toBeNull();
421
- });
422
- });
423
-
424
- describe("makeRequest()", () => {
425
- describe("when response is 204 No Content", () => {
426
- it("returns null without calling json()", async () => {
427
- const { listPromptTags } = await import("../langwatch-api.js");
428
- mock204Response();
429
-
430
- const result = await listPromptTags();
431
- expect(result).toBeNull();
432
- });
433
- });
434
- });
435
-
436
- describe("when the API returns an error", () => {
437
- it("includes the status code in the error message", async () => {
438
- const { searchTraces } = await import("../langwatch-api.js");
439
- mockErrorResponse(500, "Internal Server Error");
440
-
441
- await expect(
442
- searchTraces({ startDate: 1000, endDate: 2000 })
443
- ).rejects.toThrow("500");
444
- });
445
-
446
- it("includes the response body in the error message", async () => {
447
- const { searchTraces } = await import("../langwatch-api.js");
448
- mockErrorResponse(403, "Forbidden: invalid API key");
449
-
450
- await expect(
451
- searchTraces({ startDate: 1000, endDate: 2000 })
452
- ).rejects.toThrow("Forbidden: invalid API key");
453
- });
454
- });
455
-
456
- describe("when the API returns a handled-error JSON body", () => {
457
- const handledErrorBody = {
458
- error: "invalid_filter",
459
- message: "Filter 'llm.model' is not supported",
460
- tips: ["Use 'metadata.model' instead", "See the filter reference"],
461
- docsUrl: "https://docs.langwatch.ai/api/filters",
462
- fault: "customer",
463
- };
464
-
465
- it("parses code, tips, docsUrl and fault into LangWatchApiError fields", async () => {
466
- const { searchTraces, LangWatchApiError } = await import(
467
- "../langwatch-api.js"
468
- );
469
- mockErrorResponse(400, JSON.stringify(handledErrorBody));
470
-
471
- const error = await searchTraces({
472
- startDate: 1000,
473
- endDate: 2000,
474
- }).catch((e) => e);
475
-
476
- expect(error).toBeInstanceOf(LangWatchApiError);
477
- expect(error.status).toBe(400);
478
- expect(error.responseBody).toBe(JSON.stringify(handledErrorBody));
479
- expect(error.code).toBe("invalid_filter");
480
- expect(error.tips).toEqual(handledErrorBody.tips);
481
- expect(error.docsUrl).toBe(handledErrorBody.docsUrl);
482
- expect(error.fault).toBe("customer");
483
- });
484
-
485
- it("formats the message with the server message, Tips section and Docs link", async () => {
486
- const { searchTraces } = await import("../langwatch-api.js");
487
- mockErrorResponse(400, JSON.stringify(handledErrorBody));
488
-
489
- const error = await searchTraces({
490
- startDate: 1000,
491
- endDate: 2000,
492
- }).catch((e) => e);
493
-
494
- expect(error.message).toContain(
495
- "LangWatch API error 400: Filter 'llm.model' is not supported"
496
- );
497
- expect(error.message).toContain("Tips:");
498
- expect(error.message).toContain("- Use 'metadata.model' instead");
499
- expect(error.message).toContain("- See the filter reference");
500
- expect(error.message).toContain(
501
- "Docs: https://docs.langwatch.ai/api/filters"
502
- );
503
- });
504
-
505
- // A validation failure names the offending field AND the values it would
506
- // have taken, in `reasons[].meta`. Dropping that leaves the message's own
507
- // advice ("pick one of the types in this error's expected list") naming a
508
- // list the caller was never given.
509
- describe("when the failure carries the values it would have accepted", () => {
510
- const rejectedTypeBody = {
511
- error: "validation_error",
512
- message:
513
- "Unknown evaluator type. Pick one of the types in this error's expected list and retry.",
514
- reasons: [
515
- {
516
- code: "schema_failure",
517
- kind: "schema_failure",
518
- meta: {
519
- field: "config.evaluatorType",
520
- expected: ["ragas/response_relevancy", "langevals/llm_boolean"],
521
- received: "ragas/answer_relevancy",
522
- },
523
- },
524
- ],
525
- };
526
-
527
- /** @scenario A rejection over MCP carries the accepted types */
528
- it("keeps the reasons on the error", async () => {
529
- const { createEvaluator } = await import(
530
- "../langwatch-api-evaluators.js"
531
- );
532
- mockErrorResponse(422, JSON.stringify(rejectedTypeBody));
533
-
534
- const error = await createEvaluator({
535
- name: "Relevancy",
536
- config: { evaluatorType: "ragas/answer_relevancy" },
537
- }).catch((e) => e);
538
-
539
- expect(error.reasons).toEqual(rejectedTypeBody.reasons);
540
- });
541
-
542
- it("names the rejected field and the accepted values in the message", async () => {
543
- const { createEvaluator } = await import(
544
- "../langwatch-api-evaluators.js"
545
- );
546
- mockErrorResponse(422, JSON.stringify(rejectedTypeBody));
547
-
548
- const error = await createEvaluator({
549
- name: "Relevancy",
550
- config: { evaluatorType: "ragas/answer_relevancy" },
551
- }).catch((e) => e);
552
-
553
- expect(error.message).toContain("config.evaluatorType");
554
- expect(error.message).toContain("ragas/response_relevancy");
555
- expect(error.message).toContain("langevals/llm_boolean");
556
- expect(error.message).toContain("ragas/answer_relevancy");
557
- });
558
- });
559
-
560
- it("parses the tRPC shape using `code` instead of `error`", async () => {
561
- const { searchTraces } = await import("../langwatch-api.js");
562
- const body = {
563
- code: "dataset_not_found",
564
- message: "Dataset 'abc' not found",
565
- meta: { datasetId: "abc" },
566
- httpStatus: 404,
567
- fault: "customer",
568
- tips: ["Check the dataset slug"],
569
- docsUrl: "https://docs.langwatch.ai/datasets",
570
- reasons: [],
571
- };
572
- mockErrorResponse(404, JSON.stringify(body));
573
-
574
- const error = await searchTraces({
575
- startDate: 1000,
576
- endDate: 2000,
577
- }).catch((e) => e);
578
-
579
- expect(error.code).toBe("dataset_not_found");
580
- expect(error.tips).toEqual(["Check the dataset slug"]);
581
- expect(error.docsUrl).toBe("https://docs.langwatch.ai/datasets");
582
- expect(error.fault).toBe("customer");
583
- expect(error.message).toContain("Dataset 'abc' not found");
584
- });
585
-
586
- it("omits the Tips and Docs sections when absent", async () => {
587
- const { searchTraces } = await import("../langwatch-api.js");
588
- mockErrorResponse(
589
- 401,
590
- JSON.stringify({ error: "unauthorized", message: "Invalid API key" })
591
- );
592
-
593
- const error = await searchTraces({
594
- startDate: 1000,
595
- endDate: 2000,
596
- }).catch((e) => e);
597
-
598
- expect(error.code).toBe("unauthorized");
599
- expect(error.tips).toBeUndefined();
600
- expect(error.docsUrl).toBeUndefined();
601
- expect(error.fault).toBeUndefined();
602
- expect(error.message).toBe(
603
- "LangWatch API error 401: Invalid API key"
604
- );
605
- });
606
-
607
- it("ignores an invalid fault value", async () => {
608
- const { searchTraces } = await import("../langwatch-api.js");
609
- mockErrorResponse(
610
- 500,
611
- JSON.stringify({ error: "boom", message: "Boom", fault: "nobody" })
612
- );
613
-
614
- const error = await searchTraces({
615
- startDate: 1000,
616
- endDate: 2000,
617
- }).catch((e) => e);
618
-
619
- expect(error.fault).toBeUndefined();
620
- });
621
- });
622
-
623
- describe("when the error body is not a handled-error envelope", () => {
624
- it("keeps the raw text as the message and sets no extra fields", async () => {
625
- const { searchTraces, LangWatchApiError } = await import(
626
- "../langwatch-api.js"
627
- );
628
- mockErrorResponse(502, "<html>Bad Gateway</html>");
629
-
630
- const error = await searchTraces({
631
- startDate: 1000,
632
- endDate: 2000,
633
- }).catch((e) => e);
634
-
635
- expect(error).toBeInstanceOf(LangWatchApiError);
636
- expect(error.status).toBe(502);
637
- expect(error.responseBody).toBe("<html>Bad Gateway</html>");
638
- expect(error.message).toBe(
639
- "LangWatch API error 502: <html>Bad Gateway</html>"
640
- );
641
- expect(error.code).toBeUndefined();
642
- expect(error.tips).toBeUndefined();
643
- expect(error.docsUrl).toBeUndefined();
644
- expect(error.fault).toBeUndefined();
645
- });
646
-
647
- it("treats JSON without error/code/message fields as raw text", async () => {
648
- const { searchTraces } = await import("../langwatch-api.js");
649
- const body = JSON.stringify({ unexpected: true });
650
- mockErrorResponse(500, body);
651
-
652
- const error = await searchTraces({
653
- startDate: 1000,
654
- endDate: 2000,
655
- }).catch((e) => e);
656
-
657
- expect(error.code).toBeUndefined();
658
- expect(error.message).toBe(`LangWatch API error 500: ${body}`);
659
- });
660
- });
661
- });