@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,262 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from "vitest";
2
-
3
- vi.mock("../langwatch-api-evaluators.js", async (importOriginal) => {
4
- const actual = await importOriginal() as Record<string, unknown>;
5
- return {
6
- ...actual,
7
- listEvaluators: vi.fn(),
8
- getEvaluator: vi.fn(),
9
- createEvaluator: vi.fn(),
10
- updateEvaluator: vi.fn(),
11
- };
12
- });
13
-
14
- import {
15
- listEvaluators,
16
- getEvaluator,
17
- createEvaluator,
18
- updateEvaluator,
19
- } from "../langwatch-api-evaluators.js";
20
-
21
- import { handleListEvaluators } from "../tools/list-evaluators.js";
22
- import { handleGetEvaluator } from "../tools/get-evaluator.js";
23
- import { handleCreateEvaluator } from "../tools/create-evaluator.js";
24
- import { handleUpdateEvaluator } from "../tools/update-evaluator.js";
25
-
26
- const mockListEvaluators = vi.mocked(listEvaluators);
27
- const mockGetEvaluator = vi.mocked(getEvaluator);
28
- const mockCreateEvaluator = vi.mocked(createEvaluator);
29
- const mockUpdateEvaluator = vi.mocked(updateEvaluator);
30
-
31
- beforeEach(() => {
32
- vi.clearAllMocks();
33
- });
34
-
35
- describe("handleListEvaluators()", () => {
36
- const sampleEvaluators = [
37
- {
38
- id: "evaluator_abc123",
39
- projectId: "proj_1",
40
- name: "Toxicity Check",
41
- slug: "toxicity-check",
42
- type: "evaluator",
43
- config: { evaluatorType: "openai/moderation" },
44
- workflowId: null,
45
- copiedFromEvaluatorId: null,
46
- createdAt: "2024-01-01T00:00:00.000Z",
47
- updatedAt: "2024-01-01T00:00:00.000Z",
48
- fields: [{ identifier: "input", type: "str" }],
49
- outputFields: [{ identifier: "passed", type: "bool" }],
50
- },
51
- {
52
- id: "evaluator_def456",
53
- projectId: "proj_1",
54
- name: "Exact Match",
55
- slug: "exact-match",
56
- type: "evaluator",
57
- config: { evaluatorType: "langevals/exact_match" },
58
- workflowId: null,
59
- copiedFromEvaluatorId: null,
60
- createdAt: "2024-01-02T00:00:00.000Z",
61
- updatedAt: "2024-01-02T00:00:00.000Z",
62
- fields: [
63
- { identifier: "output", type: "str" },
64
- { identifier: "expected_output", type: "str" },
65
- ],
66
- outputFields: [{ identifier: "passed", type: "bool" }],
67
- },
68
- ];
69
-
70
- describe("when evaluators exist", () => {
71
- let result: string;
72
-
73
- beforeEach(async () => {
74
- mockListEvaluators.mockResolvedValue(sampleEvaluators);
75
- result = await handleListEvaluators();
76
- });
77
-
78
- it("includes evaluator id", () => {
79
- expect(result).toContain("evaluator_abc123");
80
- });
81
-
82
- it("includes evaluator name", () => {
83
- expect(result).toContain("Toxicity Check");
84
- });
85
-
86
- it("includes evaluator type", () => {
87
- expect(result).toContain("openai/moderation");
88
- });
89
-
90
- it("includes slug", () => {
91
- expect(result).toContain("toxicity-check");
92
- });
93
-
94
- it("includes all evaluators in the list", () => {
95
- expect(result).toContain("evaluator_def456");
96
- });
97
-
98
- it("includes the total count header", () => {
99
- expect(result).toContain("# Evaluators (2 total)");
100
- });
101
- });
102
-
103
- describe("when no evaluators exist", () => {
104
- let result: string;
105
-
106
- beforeEach(async () => {
107
- mockListEvaluators.mockResolvedValue([]);
108
- result = await handleListEvaluators();
109
- });
110
-
111
- it("returns a no-evaluators message", () => {
112
- expect(result).toContain("No evaluators found");
113
- });
114
-
115
- it("includes a tip to use platform_create_evaluator", () => {
116
- expect(result).toContain("platform_create_evaluator");
117
- });
118
- });
119
- });
120
-
121
- describe("handleGetEvaluator()", () => {
122
- const sampleEvaluator = {
123
- id: "evaluator_abc123",
124
- projectId: "proj_1",
125
- name: "Toxicity Check",
126
- slug: "toxicity-check",
127
- type: "evaluator",
128
- config: {
129
- evaluatorType: "openai/moderation",
130
- settings: { model: "text-moderation-stable" },
131
- },
132
- workflowId: null,
133
- copiedFromEvaluatorId: null,
134
- createdAt: "2024-01-01T00:00:00.000Z",
135
- updatedAt: "2024-01-01T00:00:00.000Z",
136
- fields: [
137
- { identifier: "input", type: "str" },
138
- { identifier: "output", type: "str", optional: true },
139
- ],
140
- outputFields: [
141
- { identifier: "passed", type: "bool" },
142
- { identifier: "score", type: "float" },
143
- ],
144
- };
145
-
146
- describe("when evaluator is found", () => {
147
- let result: string;
148
-
149
- beforeEach(async () => {
150
- mockGetEvaluator.mockResolvedValue(sampleEvaluator);
151
- result = await handleGetEvaluator({ idOrSlug: "evaluator_abc123" });
152
- });
153
-
154
- it("includes the evaluator name in the heading", () => {
155
- expect(result).toContain("# Evaluator: Toxicity Check");
156
- });
157
-
158
- it("includes the evaluator type", () => {
159
- expect(result).toContain("openai/moderation");
160
- });
161
-
162
- it("includes the config as JSON", () => {
163
- expect(result).toContain("text-moderation-stable");
164
- });
165
-
166
- it("includes input fields", () => {
167
- expect(result).toContain("## Input Fields");
168
- expect(result).toContain("**input** (str)");
169
- });
170
-
171
- it("marks optional fields", () => {
172
- expect(result).toContain("(optional)");
173
- });
174
-
175
- it("includes output fields", () => {
176
- expect(result).toContain("## Output Fields");
177
- expect(result).toContain("**passed** (bool)");
178
- });
179
- });
180
- });
181
-
182
- describe("handleCreateEvaluator()", () => {
183
- describe("when creation succeeds", () => {
184
- let result: string;
185
-
186
- beforeEach(async () => {
187
- mockCreateEvaluator.mockResolvedValue({
188
- id: "evaluator_new123",
189
- projectId: "proj_1",
190
- name: "My LLM Judge",
191
- slug: "my-llm-judge",
192
- type: "evaluator",
193
- config: { evaluatorType: "langevals/llm_boolean" },
194
- workflowId: null,
195
- copiedFromEvaluatorId: null,
196
- createdAt: "2024-01-01T00:00:00.000Z",
197
- updatedAt: "2024-01-01T00:00:00.000Z",
198
- fields: [{ identifier: "input", type: "str" }],
199
- outputFields: [{ identifier: "passed", type: "bool" }],
200
- });
201
- result = await handleCreateEvaluator({
202
- name: "My LLM Judge",
203
- config: { evaluatorType: "langevals/llm_boolean" },
204
- });
205
- });
206
-
207
- it("confirms creation", () => {
208
- expect(result).toContain("Evaluator created successfully!");
209
- });
210
-
211
- it("includes the generated ID", () => {
212
- expect(result).toContain("evaluator_new123");
213
- });
214
-
215
- it("includes the slug", () => {
216
- expect(result).toContain("my-llm-judge");
217
- });
218
-
219
- it("includes the evaluator type", () => {
220
- expect(result).toContain("langevals/llm_boolean");
221
- });
222
- });
223
- });
224
-
225
- describe("handleUpdateEvaluator()", () => {
226
- describe("when update succeeds", () => {
227
- let result: string;
228
-
229
- beforeEach(async () => {
230
- mockUpdateEvaluator.mockResolvedValue({
231
- id: "evaluator_abc123",
232
- projectId: "proj_1",
233
- name: "Updated Name",
234
- slug: "toxicity-check",
235
- type: "evaluator",
236
- config: { evaluatorType: "openai/moderation" },
237
- workflowId: null,
238
- copiedFromEvaluatorId: null,
239
- createdAt: "2024-01-01T00:00:00.000Z",
240
- updatedAt: "2024-01-02T00:00:00.000Z",
241
- fields: [],
242
- outputFields: [],
243
- });
244
- result = await handleUpdateEvaluator({
245
- evaluatorId: "evaluator_abc123",
246
- name: "Updated Name",
247
- });
248
- });
249
-
250
- it("confirms update", () => {
251
- expect(result).toContain("Evaluator updated successfully!");
252
- });
253
-
254
- it("includes the evaluator ID", () => {
255
- expect(result).toContain("evaluator_abc123");
256
- });
257
-
258
- it("includes the updated name", () => {
259
- expect(result).toContain("Updated Name");
260
- });
261
- });
262
- });
@@ -1,157 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from "vitest";
2
-
3
- vi.mock("../langwatch-api.js", async (importOriginal) => {
4
- const actual = (await importOriginal()) as Record<string, unknown>;
5
- return {
6
- ...actual,
7
- makeRequest: vi.fn(),
8
- };
9
- });
10
-
11
- import { makeRequest } from "../langwatch-api.js";
12
- import { handleExperimentList } from "../tools/list-experiments.js";
13
- import { handleExperimentListRuns } from "../tools/list-experiment-runs.js";
14
-
15
- const mockMakeRequest = vi.mocked(makeRequest);
16
-
17
- describe("handleExperimentList()", () => {
18
- beforeEach(() => {
19
- vi.clearAllMocks();
20
- });
21
-
22
- describe("given experiments exist", () => {
23
- describe("when invoked with default limit", () => {
24
- /** @scenario "Lists experiments as markdown" */
25
- it("renders a markdown table with each slug", async () => {
26
- mockMakeRequest.mockResolvedValueOnce({
27
- experiments: [
28
- {
29
- id: "exp_1",
30
- slug: "checkout-flow",
31
- name: "Checkout Flow",
32
- type: "EVALUATIONS_V3",
33
- workflowId: null,
34
- createdAt: "2026-01-01T00:00:00Z",
35
- updatedAt: "2026-01-02T00:00:00Z",
36
- runsCount: 3,
37
- lastRunAt: "2026-01-02T00:00:00Z",
38
- },
39
- ],
40
- pagination: {
41
- page: 1,
42
- pageSize: 25,
43
- totalHits: 1,
44
- hasMore: false,
45
- },
46
- });
47
-
48
- const out = await handleExperimentList({});
49
- expect(out).toContain("# Experiments");
50
- expect(out).toContain("`checkout-flow`");
51
- expect(out).toContain("Checkout Flow");
52
- });
53
- });
54
-
55
- describe("when invoked with limit above the cap", () => {
56
- /** @scenario "Limit is bounded to protect agent context" */
57
- it("clamps the effective pageSize to 100", async () => {
58
- mockMakeRequest.mockResolvedValueOnce({
59
- experiments: [],
60
- pagination: { page: 1, pageSize: 100, totalHits: 0, hasMore: false },
61
- });
62
-
63
- await handleExperimentList({ limit: 5000 });
64
- const path = mockMakeRequest.mock.calls[0]![1] as string;
65
- expect(path).toContain("pageSize=100");
66
- });
67
- });
68
- });
69
-
70
- describe("given no experiments exist", () => {
71
- describe("when invoked", () => {
72
- it("returns an empty-state message", async () => {
73
- mockMakeRequest.mockResolvedValueOnce({
74
- experiments: [],
75
- pagination: { page: 1, pageSize: 25, totalHits: 0, hasMore: false },
76
- });
77
- const out = await handleExperimentList({});
78
- expect(out).toContain("No experiments");
79
- });
80
- });
81
- });
82
- });
83
-
84
- describe("handleExperimentListRuns()", () => {
85
- beforeEach(() => {
86
- vi.clearAllMocks();
87
- });
88
-
89
- describe("given a known experiment with runs", () => {
90
- describe("when invoked", () => {
91
- /** @scenario "Lists runs for a known experiment" */
92
- it("renders a markdown table with each runId", async () => {
93
- mockMakeRequest.mockResolvedValueOnce({
94
- experimentId: "exp_1",
95
- experimentSlug: "checkout-flow",
96
- runs: [
97
- {
98
- experimentId: "exp_1",
99
- runId: "run_visible",
100
- workflowVersion: null,
101
- timestamps: { createdAt: 1000, updatedAt: 2000, finishedAt: 2000 },
102
- summary: { evaluations: {} },
103
- },
104
- ],
105
- pagination: {
106
- page: 1,
107
- pageSize: 25,
108
- totalHits: 1,
109
- hasMore: false,
110
- },
111
- });
112
-
113
- const out = await handleExperimentListRuns({
114
- experimentSlug: "checkout-flow",
115
- });
116
- expect(out).toContain("# Evaluation Runs: checkout-flow");
117
- expect(out).toContain("`run_visible`");
118
- });
119
- });
120
- });
121
-
122
- describe("given the experiment slug is unknown", () => {
123
- describe("when the API throws 404", () => {
124
- /** @scenario "Unknown experiment slug returns a graceful not-found message" */
125
- it("returns a graceful not-found message suggesting platform_experiment_list", async () => {
126
- mockMakeRequest.mockRejectedValueOnce(
127
- new Error("LangWatch API error 404: experiment not found"),
128
- );
129
-
130
- const out = await handleExperimentListRuns({
131
- experimentSlug: "does-not-exist",
132
- });
133
- expect(out).toContain("not found");
134
- expect(out).toContain("platform_experiment_list");
135
- });
136
- });
137
- });
138
-
139
- describe("given the experiment exists but has no runs", () => {
140
- describe("when invoked", () => {
141
- it("returns an empty-state message that points at platform_run_experiment", async () => {
142
- mockMakeRequest.mockResolvedValueOnce({
143
- experimentId: "exp_1",
144
- experimentSlug: "support-bot",
145
- runs: [],
146
- pagination: { page: 1, pageSize: 25, totalHits: 0, hasMore: false },
147
- });
148
-
149
- const out = await handleExperimentListRuns({
150
- experimentSlug: "support-bot",
151
- });
152
- expect(out).toContain("no runs yet");
153
- expect(out).toContain("platform_run_experiment");
154
- });
155
- });
156
- });
157
- });
@@ -1,194 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from "vitest";
2
-
3
- vi.mock("../langwatch-api.js", async (importOriginal) => {
4
- const actual = (await importOriginal()) as Record<string, unknown>;
5
- return {
6
- ...actual,
7
- makeRequest: vi.fn(),
8
- };
9
- });
10
-
11
- import { LangWatchApiError, makeRequest } from "../langwatch-api.js";
12
- import { handleExperimentStatus } from "../tools/run-experiment.js";
13
- import {
14
- deriveRunStatus,
15
- isTerminalStatus,
16
- } from "../tools/experiment-run-status.js";
17
-
18
- const mockMakeRequest = vi.mocked(makeRequest);
19
-
20
- beforeEach(() => {
21
- vi.clearAllMocks();
22
- });
23
-
24
- describe("deriveRunStatus()", () => {
25
- describe("when stoppedAt is set", () => {
26
- it("is stopped", () => {
27
- expect(deriveRunStatus({ stoppedAt: 5 })).toBe("stopped");
28
- });
29
- });
30
-
31
- describe("when finishedAt is set", () => {
32
- it("is completed", () => {
33
- expect(deriveRunStatus({ finishedAt: 5 })).toBe("completed");
34
- });
35
- });
36
-
37
- describe("when no terminal marker and updates are recent", () => {
38
- it("is running", () => {
39
- const now = 1_000_000;
40
- expect(deriveRunStatus({ updatedAt: now - 1000 }, now)).toBe("running");
41
- });
42
- });
43
-
44
- describe("when no terminal marker and no recent updates", () => {
45
- it("is interrupted", () => {
46
- const now = 1_000_000;
47
- expect(deriveRunStatus({ updatedAt: now - 6 * 60 * 1000 }, now)).toBe(
48
- "interrupted",
49
- );
50
- });
51
- });
52
-
53
- describe("terminal classification", () => {
54
- it("treats completed and stopped as terminal", () => {
55
- expect(isTerminalStatus("completed")).toBe(true);
56
- expect(isTerminalStatus("stopped")).toBe(true);
57
- expect(isTerminalStatus("running")).toBe(false);
58
- expect(isTerminalStatus("interrupted")).toBe(false);
59
- });
60
- });
61
- });
62
-
63
- describe("handleExperimentStatus()", () => {
64
- describe("given the run state exists in Redis", () => {
65
- it("reports the status straight from the status endpoint", async () => {
66
- mockMakeRequest.mockResolvedValueOnce({
67
- runId: "run_1",
68
- status: "completed",
69
- progress: 3,
70
- total: 3,
71
- });
72
-
73
- const out = await handleExperimentStatus({ runId: "run_1" });
74
-
75
- expect(mockMakeRequest).toHaveBeenCalledWith(
76
- "GET",
77
- "/api/experiments/runs/run_1",
78
- );
79
- expect(out).toContain("**Status**: completed");
80
- expect(out).toContain("3/3 cells");
81
- });
82
- });
83
-
84
- describe("given an SDK-logged run with no Redis state", () => {
85
- it("falls back to deriving status from the results endpoint", async () => {
86
- mockMakeRequest
87
- .mockRejectedValueOnce(
88
- new LangWatchApiError("missing", 404, "Run not found"),
89
- )
90
- .mockResolvedValueOnce({
91
- progress: 5,
92
- total: 5,
93
- dataset: [1, 2, 3, 4, 5],
94
- timestamps: {
95
- createdAt: 1,
96
- updatedAt: 2,
97
- finishedAt: 3,
98
- stoppedAt: null,
99
- },
100
- });
101
-
102
- const out = await handleExperimentStatus({
103
- runId: "sdk_run",
104
- experimentSlug: "doc-qa",
105
- });
106
-
107
- expect(mockMakeRequest).toHaveBeenNthCalledWith(
108
- 1,
109
- "GET",
110
- "/api/experiments/runs/sdk_run",
111
- );
112
- expect(mockMakeRequest).toHaveBeenNthCalledWith(
113
- 2,
114
- "GET",
115
- "/api/experiments/runs/sdk_run/results?experimentSlug=doc-qa",
116
- );
117
- expect(out).toContain("**Status**: completed");
118
- expect(out).toContain("5/5 cells");
119
- expect(out).toContain("platform_experiment_results");
120
- });
121
-
122
- it("reports interrupted for a stale unfinished SDK run", async () => {
123
- mockMakeRequest
124
- .mockRejectedValueOnce(
125
- new LangWatchApiError("missing", 404, "Run not found"),
126
- )
127
- .mockResolvedValueOnce({
128
- progress: 2,
129
- total: 5,
130
- dataset: [1, 2],
131
- timestamps: {
132
- createdAt: Date.now() - 60 * 60 * 1000,
133
- updatedAt: Date.now() - 30 * 60 * 1000,
134
- finishedAt: null,
135
- stoppedAt: null,
136
- },
137
- });
138
-
139
- const out = await handleExperimentStatus({
140
- runId: "sdk_run",
141
- experimentSlug: "doc-qa",
142
- });
143
-
144
- expect(out).toContain("**Status**: interrupted");
145
- expect(out).toContain("2/5 cells");
146
- });
147
- });
148
-
149
- describe("given the run cannot be found anywhere", () => {
150
- it("returns actionable guidance instead of a raw 404", async () => {
151
- mockMakeRequest
152
- .mockRejectedValueOnce(
153
- new LangWatchApiError("missing", 404, "Run not found"),
154
- )
155
- .mockRejectedValueOnce(
156
- new LangWatchApiError("missing", 404, "Run not found"),
157
- );
158
-
159
- const out = await handleExperimentStatus({
160
- runId: "nope",
161
- experimentSlug: "doc-qa",
162
- });
163
-
164
- expect(out).toContain("not found");
165
- expect(out).toContain("experimentSlug");
166
- expect(out).toContain("platform_experiment_results");
167
- });
168
-
169
- it("rethrows non-404 errors from the status endpoint", async () => {
170
- mockMakeRequest.mockRejectedValueOnce(
171
- new LangWatchApiError("boom", 500, "Internal error"),
172
- );
173
-
174
- await expect(
175
- handleExperimentStatus({ runId: "nope" }),
176
- ).rejects.toThrow();
177
- });
178
-
179
- it("propagates a real (non-404) error from the results fallback instead of faking not-found", async () => {
180
- mockMakeRequest
181
- .mockRejectedValueOnce(
182
- new LangWatchApiError("missing", 404, "Run not found"),
183
- )
184
- .mockRejectedValueOnce(
185
- new LangWatchApiError("boom", 500, "Internal error"),
186
- );
187
-
188
- // The fallback's 500 ("boom") must surface, not the original 404 ("missing").
189
- await expect(
190
- handleExperimentStatus({ runId: "sdk_run", experimentSlug: "doc-qa" }),
191
- ).rejects.toThrow(/boom/);
192
- });
193
- });
194
- });
@@ -1,93 +0,0 @@
1
- /**
2
- * Drift guard between the MCP tools this server registers and the names
3
- * `feature-map.json` tells agents to call.
4
- *
5
- * The feature map is the canonical information architecture: it is embedded
6
- * into the CLI at codegen time and shipped inside the npx server package, so a
7
- * name in it is a name an agent will try. Two entries pointed at
8
- * `platform_run_evaluation` and `platform_evaluation_status`, which have never
9
- * existed — the tools are `platform_run_experiment` and
10
- * `platform_experiment_status`. An agent following the map for the experiments
11
- * feature called two tools that were not there.
12
- *
13
- * Nothing compared the two lists, which is why it went unnoticed. This does.
14
- *
15
- * @see .claude/skills/feature-map/SKILL.md
16
- */
17
- import { readFileSync } from "node:fs";
18
- import { join } from "node:path";
19
- import { describe, expect, it } from "vitest";
20
-
21
- const REPO_ROOT = join(__dirname, "../../../..");
22
-
23
- /**
24
- * Every tool name the feature map hands to an agent, from any depth: `mcp`
25
- * arrays hang off surfaces nested several levels into the tree.
26
- */
27
- function toolNamesInFeatureMap(): Set<string> {
28
- const map: unknown = JSON.parse(
29
- readFileSync(join(REPO_ROOT, "feature-map.json"), "utf-8")
30
- );
31
- const names = new Set<string>();
32
-
33
- const walk = (node: unknown): void => {
34
- if (Array.isArray(node)) {
35
- for (const item of node) walk(item);
36
- return;
37
- }
38
- if (node === null || typeof node !== "object") return;
39
-
40
- const entry = node as Record<string, unknown>;
41
- if (Array.isArray(entry.mcp)) {
42
- for (const name of entry.mcp) {
43
- if (typeof name === "string") names.add(name);
44
- }
45
- }
46
- for (const value of Object.values(entry)) walk(value);
47
- };
48
-
49
- walk(map);
50
- return names;
51
- }
52
-
53
- /**
54
- * Every name passed as the first argument of a `server.tool(` registration.
55
- *
56
- * Read from the source rather than by constructing a server: building one
57
- * needs config and credentials this test has no business holding, and the
58
- * registration is a string literal in every case.
59
- */
60
- function registeredToolNames(): Set<string> {
61
- const source = readFileSync(
62
- join(__dirname, "../create-mcp-server.ts"),
63
- "utf-8"
64
- );
65
- const names = new Set<string>();
66
- for (const match of source.matchAll(/server\.tool\(\s*"([^"]+)"/g)) {
67
- names.add(match[1]!);
68
- }
69
- return names;
70
- }
71
-
72
- describe("feature map MCP tool names", () => {
73
- describe("given the tools this server registers", () => {
74
- it("names only tools that exist", () => {
75
- const registered = registeredToolNames();
76
- const missing = [...toolNamesInFeatureMap()]
77
- .filter((name) => !registered.has(name))
78
- .sort();
79
-
80
- // Listed, not registered: an agent following the map calls a tool that
81
- // is not there. Either rename the entry, or register the tool.
82
- expect(missing).toEqual([]);
83
- });
84
-
85
- it("finds the registrations it is reading", () => {
86
- // A regex that silently matched nothing would make the check above pass
87
- // for the wrong reason.
88
- const registered = registeredToolNames();
89
- expect(registered.size).toBeGreaterThan(50);
90
- expect(registered).toContain("platform_run_experiment");
91
- });
92
- });
93
- });