@langwatch/mcp-server 2.0.0 → 2.2.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 (430) hide show
  1. package/.gitignore +7 -0
  2. package/.npmignore +41 -0
  3. package/CHANGELOG.md +280 -200
  4. package/CONTRIBUTING.md +10 -0
  5. package/README.md +82 -52
  6. package/dist/add-dashboard-widget-4ZC5UN73.js +50 -0
  7. package/dist/add-dashboard-widget-ACC6QYBG.js +49 -0
  8. package/dist/archive-project-KWFM3I5Z.js +19 -0
  9. package/dist/{archive-project-4EQGLBJJ.js → archive-project-SPVHXK6A.js} +4 -4
  10. package/dist/archive-run-plan-65QN3XRX.js +16 -0
  11. package/dist/archive-run-plan-Z4SYE6BP.js +15 -0
  12. package/dist/{archive-scenario-W6BXYDZ3.js → archive-scenario-A6QV5LOW.js} +4 -4
  13. package/dist/archive-scenario-FXEYQNEH.js +19 -0
  14. package/dist/archive-test-suite-5ADQ3KPQ.js +15 -0
  15. package/dist/archive-test-suite-NKZDZY3D.js +16 -0
  16. package/dist/assign-prompt-tag-5IUZXJ2T.js +23 -0
  17. package/dist/{assign-prompt-tag-VLXUWEKU.js → assign-prompt-tag-HBZLBIFD.js} +8 -4
  18. package/dist/{chunk-CDYQOY5U.js → chunk-3OCG3QPU.js} +7 -10
  19. package/dist/chunk-3YLN3ATJ.js +241 -0
  20. package/dist/chunk-5FNCQRCX.js +91 -0
  21. package/dist/chunk-6YZUOD34.js +55 -0
  22. package/dist/{chunk-WVI5CJ6S.js → chunk-7AQLPVFL.js} +2 -2
  23. package/dist/chunk-7VNSRCXO.js +129 -0
  24. package/dist/{chunk-7RHG56OH.js → chunk-B4J3PJLX.js} +11 -10
  25. package/dist/{chunk-ZXKLPC2E.js → chunk-BIIKE3EI.js} +1 -1
  26. package/dist/{chunk-37SMPMQS.js → chunk-DMM3JQ42.js} +7 -2
  27. package/dist/{chunk-NUFPTHKU.js → chunk-FOKVY3BK.js} +1 -1
  28. package/dist/{chunk-WT4PO4A3.js → chunk-H6WGMG2T.js} +10 -7
  29. package/dist/{chunk-TOXJQDIZ.js → chunk-HGELNIVY.js} +135 -51
  30. package/dist/{chunk-UJPXFA26.js → chunk-HHMNZAPD.js} +101 -74
  31. package/dist/{chunk-J42FWRJ2.js → chunk-I7ATIZED.js} +7 -7
  32. package/dist/{chunk-AQJO2EI5.js → chunk-ILZDO25L.js} +7 -10
  33. package/dist/{chunk-4QC7SA2L.js → chunk-J7PQKBLD.js} +884 -559
  34. package/dist/{chunk-YX3A3CFM.js → chunk-JRJPH75H.js} +7 -13
  35. package/dist/chunk-K2I7Z3LZ.js +28 -0
  36. package/dist/{chunk-5CCZFUXS.js → chunk-NKMTIHIJ.js} +6 -9
  37. package/dist/chunk-O7EMWEVJ.js +44 -0
  38. package/dist/chunk-PTDR56Z3.js +37 -0
  39. package/dist/chunk-RABYBFX5.js +43 -0
  40. package/dist/chunk-SUPUUC4W.js +64 -0
  41. package/dist/{chunk-SFB4MU6H.js → chunk-SXFC3FNH.js} +4 -4
  42. package/dist/chunk-U24EACC4.js +67 -0
  43. package/dist/chunk-UNJM3BIL.js +21 -0
  44. package/dist/{chunk-ZWIL4EFL.js → chunk-UTJCWXPZ.js} +4 -4
  45. package/dist/chunk-UWLE5T2F.js +312 -0
  46. package/dist/chunk-VMWJD732.js +57 -0
  47. package/dist/chunk-XUIJYNRJ.js +15 -0
  48. package/dist/chunk-Y34DHR5K.js +67 -0
  49. package/dist/chunk-YCARO42Z.js +516 -0
  50. package/dist/config-EAKW6F26.js +16 -0
  51. package/dist/config.cjs +109 -0
  52. package/dist/config.js +5 -4
  53. package/dist/{create-agent-7XHO6UIS.js → create-agent-AYZ3LB3V.js} +4 -4
  54. package/dist/create-agent-S5ZBCEFT.js +23 -0
  55. package/dist/create-annotation-LHNCLHYP.js +29 -0
  56. package/dist/{create-annotation-YQXRQC6A.js → create-annotation-VUSXULQK.js} +10 -5
  57. package/dist/{create-api-key-YUS36KBU.js → create-api-key-NNYKARMG.js} +5 -7
  58. package/dist/create-api-key-T4KSNPKB.js +24 -0
  59. package/dist/create-dashboard-DHVFMEU4.js +18 -0
  60. package/dist/{create-dashboard-4Z5JO5LB.js → create-dashboard-WTKKS5Z6.js} +4 -4
  61. package/dist/{create-dataset-E6NMSVX7.js → create-dataset-2MC4SD4O.js} +6 -6
  62. package/dist/create-dataset-LUP5PVDM.js +22 -0
  63. package/dist/create-dataset-records-NSKBZP3G.js +20 -0
  64. package/dist/{create-dataset-records-SKHPRD2K.js → create-dataset-records-W4GLN2FV.js} +5 -7
  65. package/dist/{create-evaluator-JXF5PF33.js → create-evaluator-643G6LXL.js} +4 -4
  66. package/dist/create-evaluator-HMTYO5SS.js +27 -0
  67. package/dist/create-mcp-server.cjs +9513 -0
  68. package/dist/create-mcp-server.js +2647 -5
  69. package/dist/create-project-6N7PIYRY.js +44 -0
  70. package/dist/{create-project-CS2CB57Y.js → create-project-KAIC46UY.js} +4 -4
  71. package/dist/{create-prompt-F5RMX3L3.js → create-prompt-E67LXIYT.js} +5 -7
  72. package/dist/create-prompt-PKJ7EDRR.js +37 -0
  73. package/dist/create-prompt-tag-4YO3FSJ3.js +17 -0
  74. package/dist/{create-prompt-tag-GMRWTEFR.js → create-prompt-tag-OPQUEXWB.js} +3 -3
  75. package/dist/create-scenario-5PJBMAXO.js +33 -0
  76. package/dist/{create-scenario-JDR2VB2H.js → create-scenario-UEM77OE7.js} +11 -4
  77. package/dist/create-test-suite-4IPXVSFQ.js +37 -0
  78. package/dist/create-test-suite-SZEPVXSE.js +36 -0
  79. package/dist/create-trigger-5HZSCRAN.js +49 -0
  80. package/dist/create-trigger-PRELMT6J.js +48 -0
  81. package/dist/delete-agent-JUIZWAXG.js +18 -0
  82. package/dist/{delete-agent-O3EEH4S5.js → delete-agent-QMEK3XHK.js} +4 -4
  83. package/dist/delete-annotation-HY3O2OGR.js +17 -0
  84. package/dist/{delete-annotation-XP6FQM7A.js → delete-annotation-VKIQWUYW.js} +4 -4
  85. package/dist/delete-dashboard-76N66XXL.js +18 -0
  86. package/dist/{delete-dashboard-RFUNYCNP.js → delete-dashboard-JVIVHNJM.js} +4 -4
  87. package/dist/delete-dataset-HQCR66MG.js +18 -0
  88. package/dist/{delete-dataset-3MJFRDLP.js → delete-dataset-WKRUW4FP.js} +5 -7
  89. package/dist/{delete-dataset-records-WPMU5GL5.js → delete-dataset-records-C2IQFFVQ.js} +5 -7
  90. package/dist/delete-dataset-records-SDUHQLLM.js +19 -0
  91. package/dist/delete-evaluator-4SNSCLEE.js +16 -0
  92. package/dist/delete-evaluator-QP3QHTLN.js +15 -0
  93. package/dist/delete-prompt-tag-NZ4JQMYG.js +17 -0
  94. package/dist/{delete-prompt-tag-KNMZVSPB.js → delete-prompt-tag-YYQ4VMAD.js} +3 -3
  95. package/dist/{delete-workflow-3NUXO46U.js → delete-workflow-5J46T73T.js} +4 -4
  96. package/dist/delete-workflow-JSWABL5F.js +17 -0
  97. package/dist/discover-evaluator-schema-UHWA5HVL.js +120 -0
  98. package/dist/discover-evaluator-schema-XKCLLCB3.js +118 -0
  99. package/dist/discover-scenario-schema-NOJY6S7E.js +137 -0
  100. package/dist/discover-scenario-schema-OOFIQKOG.js +139 -0
  101. package/dist/{discover-schema-L6QDPON3.js → discover-schema-55YJBFGQ.js} +181 -186
  102. package/dist/discover-schema-A33SLMXW.js +442 -0
  103. package/dist/get-agent-LJQX7OF4.js +69 -0
  104. package/dist/get-agent-OTIYUFZA.js +70 -0
  105. package/dist/get-analytics-DCS72353.js +80 -0
  106. package/dist/get-analytics-IQZKJHLW.js +79 -0
  107. package/dist/get-dashboard-5NYJEIX2.js +29 -0
  108. package/dist/{get-dashboard-KHBEGZGL.js → get-dashboard-QMTYDQAZ.js} +4 -4
  109. package/dist/get-dataset-ALSP7RTX.js +64 -0
  110. package/dist/get-dataset-X4B5JDG2.js +63 -0
  111. package/dist/{get-evaluator-ADMKVWYZ.js → get-evaluator-ISMC4LLI.js} +4 -4
  112. package/dist/get-evaluator-XEUZGZCH.js +47 -0
  113. package/dist/{get-project-RAK7URQJ.js → get-project-5VKROSDH.js} +4 -4
  114. package/dist/get-project-RM6FRCBK.js +26 -0
  115. package/dist/get-prompt-OWXJZHQQ.js +95 -0
  116. package/dist/get-prompt-W52DY36E.js +94 -0
  117. package/dist/get-run-plan-BE3M2AUX.js +59 -0
  118. package/dist/get-run-plan-RUXQ6PAX.js +58 -0
  119. package/dist/get-scenario-RNM7BAX2.js +37 -0
  120. package/dist/{get-scenario-ZTAJJL5T.js → get-scenario-YM4ODWW6.js} +8 -4
  121. package/dist/get-simulation-run-6GIATQE5.js +69 -0
  122. package/dist/{get-simulation-run-T2ZQWYH2.js → get-simulation-run-LCFSMPGQ.js} +33 -20
  123. package/dist/get-test-suite-GC2O7YH6.js +49 -0
  124. package/dist/get-test-suite-P5LJ6VLF.js +48 -0
  125. package/dist/get-trace-KBRVV4NN.js +45 -0
  126. package/dist/{get-trace-K7U234Q4.js → get-trace-SEF3FMR5.js} +11 -13
  127. package/dist/get-workflow-7PVED7JE.js +25 -0
  128. package/dist/{get-workflow-L5L2PSK3.js → get-workflow-YXULW4GC.js} +4 -4
  129. package/dist/{http-security-EU3CHTY7.js → http-security-DNLBNQZL.js} +2 -2
  130. package/dist/{http-server-YXHFPPGA.js → http-server-IR4QOS43.js} +4071 -342
  131. package/dist/index.js +60221 -38077
  132. package/dist/langwatch-api-annotations-6SA4OB4C.js +17 -0
  133. package/dist/{langwatch-api-annotations-FDAS6NQ7.js → langwatch-api-annotations-TBHLCQ5R.js} +4 -4
  134. package/dist/langwatch-api-dashboards-6EO2VVZW.js +17 -0
  135. package/dist/{langwatch-api-dashboards-JTVCS7ZJ.js → langwatch-api-dashboards-NHU5BZD7.js} +4 -4
  136. package/dist/langwatch-api-monitors-CBF3FGIM.js +47 -0
  137. package/dist/{langwatch-api-monitors-3J7UIQME.js → langwatch-api-monitors-YNWA2M5Y.js} +11 -16
  138. package/dist/langwatch-api-secrets-ADTOJELP.js +56 -0
  139. package/dist/langwatch-api-secrets-RNFO4LF2.js +55 -0
  140. package/dist/langwatch-api-triggers-KQDQC6L5.js +22 -0
  141. package/dist/langwatch-api-triggers-QS7HDIVW.js +23 -0
  142. package/dist/{langwatch-api-workflows-NBJX5KOG.js → langwatch-api-workflows-OKC4FXIF.js} +4 -4
  143. package/dist/langwatch-api-workflows-XGJE6SR5.js +15 -0
  144. package/dist/list-agents-HVYWEQMI.js +43 -0
  145. package/dist/list-agents-RBAOCF53.js +42 -0
  146. package/dist/list-annotations-HJH4NBLD.js +38 -0
  147. package/dist/{list-annotations-ZTVP4EEL.js → list-annotations-J4UAHSUN.js} +10 -5
  148. package/dist/{list-api-keys-CWD4UQT5.js → list-api-keys-7UTJRZDG.js} +10 -5
  149. package/dist/list-api-keys-A2PMV435.js +42 -0
  150. package/dist/list-dashboard-boards-OPWROHMG.js +33 -0
  151. package/dist/list-dashboard-boards-U2GJ7GC5.js +34 -0
  152. package/dist/{list-dashboards-PWG6P6KR.js → list-dashboards-ROSYFLDQ.js} +4 -4
  153. package/dist/list-dashboards-RQ635ZU7.js +32 -0
  154. package/dist/{list-dataset-records-IOE7LQXS.js → list-dataset-records-M5TKA6LK.js} +14 -10
  155. package/dist/list-dataset-records-WFM7F33C.js +43 -0
  156. package/dist/{list-datasets-ZT4JYUDT.js → list-datasets-B5X4P7BQ.js} +9 -13
  157. package/dist/list-datasets-THUKQHPX.js +56 -0
  158. package/dist/{list-evaluators-SJHC7VBH.js → list-evaluators-MYH2OVCI.js} +5 -7
  159. package/dist/list-evaluators-NLVWF6K7.js +32 -0
  160. package/dist/{list-model-providers-PPD2WPD2.js → list-model-providers-3JUGP4YI.js} +4 -4
  161. package/dist/list-model-providers-H3XKORFO.js +35 -0
  162. package/dist/{list-projects-K7QAIX2I.js → list-projects-6EJ5YYEW.js} +5 -7
  163. package/dist/list-projects-YNNSRMLC.js +40 -0
  164. package/dist/{list-prompt-tags-FOO6TNHB.js → list-prompt-tags-NVFQO6WX.js} +3 -3
  165. package/dist/list-prompt-tags-XUQTTAH4.js +23 -0
  166. package/dist/{list-prompts-SC2HAUFG.js → list-prompts-HSIMMHTF.js} +4 -6
  167. package/dist/list-prompts-IRI6AIXO.js +30 -0
  168. package/dist/list-run-plans-PX2XI6EK.js +46 -0
  169. package/dist/list-run-plans-QALLCN2K.js +45 -0
  170. package/dist/list-scenarios-QZRPVHS4.js +46 -0
  171. package/dist/list-scenarios-SSJQEMJP.js +45 -0
  172. package/dist/list-simulation-runs-KNOLGMDV.js +53 -0
  173. package/dist/{list-simulation-runs-KF5THG5H.js → list-simulation-runs-OEADLLQR.js} +19 -9
  174. package/dist/list-test-suites-ANAQBLDG.js +34 -0
  175. package/dist/list-test-suites-N4WVLBKK.js +35 -0
  176. package/dist/list-trigger-fires-JV3WFYYG.js +19 -0
  177. package/dist/list-trigger-fires-WTW4DVIW.js +20 -0
  178. package/dist/list-triggers-SQNIG35Q.js +45 -0
  179. package/dist/list-triggers-V4Y356AK.js +46 -0
  180. package/dist/{list-workflows-QSJWURCK.js → list-workflows-IMSX7SXU.js} +5 -7
  181. package/dist/list-workflows-ZHTX5LCL.js +33 -0
  182. package/dist/{rename-prompt-tag-EKWU5QF3.js → rename-prompt-tag-IQI7MHOI.js} +3 -3
  183. package/dist/rename-prompt-tag-PA2BRIE6.js +18 -0
  184. package/dist/rename-test-suite-4J7UX5S2.js +21 -0
  185. package/dist/rename-test-suite-NNVLMLKY.js +20 -0
  186. package/dist/report-issue-AS34ZMJF.js +898 -0
  187. package/dist/report-issue-DCZFLGDO.js +899 -0
  188. package/dist/rerun-run-plan-TG2V4WM4.js +22 -0
  189. package/dist/rerun-run-plan-ZI5OY3VA.js +21 -0
  190. package/dist/revoke-api-key-3J3ZA4UB.js +15 -0
  191. package/dist/{revoke-api-key-FTRTZMOF.js → revoke-api-key-SFMEFWJC.js} +4 -4
  192. package/dist/run-agent-W4VJP72Z.js +75 -0
  193. package/dist/run-agent-YNV6ZHW4.js +74 -0
  194. package/dist/run-plan-6C77GWG4.js +38 -0
  195. package/dist/run-plan-PAARQSI4.js +39 -0
  196. package/dist/run-query-KJDH544C.js +47 -0
  197. package/dist/run-query-T4QW2Z5O.js +46 -0
  198. package/dist/run-test-suite-SQJELEZX.js +26 -0
  199. package/dist/run-test-suite-STB6NUJM.js +25 -0
  200. package/dist/{run-workflow-QPXC627O.js → run-workflow-D6PQNBI6.js} +4 -4
  201. package/dist/{run-agent-6SM4XNA7.js → run-workflow-SP32SO5M.js} +10 -11
  202. package/dist/search-traces-HCBGOG6R.js +170 -0
  203. package/dist/search-traces-HSTQ6WTQ.js +171 -0
  204. package/dist/{set-model-provider-3WKT63ZN.js → set-model-provider-GF7NXUJA.js} +4 -4
  205. package/dist/set-model-provider-KDQ7C4EZ.js +33 -0
  206. package/dist/{update-agent-SMAEHLXH.js → update-agent-DWG43T2P.js} +4 -4
  207. package/dist/update-agent-MXNOBS4H.js +20 -0
  208. package/dist/update-dashboard-widget-CJKJLCDY.js +71 -0
  209. package/dist/update-dashboard-widget-CYQDS2NR.js +70 -0
  210. package/dist/update-dataset-DQH3OHOU.js +22 -0
  211. package/dist/{update-dataset-BDUK7TUO.js → update-dataset-SQZ6T4WX.js} +6 -6
  212. package/dist/{update-dataset-record-4ZSDRBSW.js → update-dataset-record-3AT4IPBC.js} +4 -4
  213. package/dist/update-dataset-record-7PLDGTMR.js +19 -0
  214. package/dist/update-evaluator-4LFTKFPT.js +24 -0
  215. package/dist/{update-evaluator-LS6TIBY7.js → update-evaluator-IGTX6PX4.js} +4 -4
  216. package/dist/{update-project-LKVYXENH.js → update-project-PLJIOZS6.js} +4 -4
  217. package/dist/update-project-QVHSJRUP.js +24 -0
  218. package/dist/update-prompt-GDKRYJI3.js +140 -0
  219. package/dist/update-prompt-MY263DYF.js +141 -0
  220. package/dist/update-scenario-7KA3JDXA.js +34 -0
  221. package/dist/{update-scenario-NEXCAQI7.js → update-scenario-MOHRQKAQ.js} +11 -4
  222. package/package.json +39 -44
  223. package/pyproject.toml +8 -8
  224. package/src/config.d.ts +4 -0
  225. package/src/config.ts +20 -29
  226. package/src/create-mcp-server.ts +1021 -596
  227. package/src/documentation-fetch.ts +21 -20
  228. package/src/http-security.ts +166 -135
  229. package/src/http-server.ts +189 -224
  230. package/src/index.ts +14 -16
  231. package/src/langwatch-api-agents.ts +202 -21
  232. package/src/langwatch-api-annotations.ts +11 -12
  233. package/src/langwatch-api-api-keys.ts +8 -9
  234. package/src/langwatch-api-boards.ts +46 -0
  235. package/src/langwatch-api-dashboard-widgets.ts +112 -0
  236. package/src/langwatch-api-dashboards.ts +13 -10
  237. package/src/langwatch-api-datasets.ts +98 -32
  238. package/src/langwatch-api-evaluators.ts +13 -19
  239. package/src/langwatch-api-model-providers.ts +4 -4
  240. package/src/langwatch-api-monitors.ts +14 -18
  241. package/src/langwatch-api-projects.ts +27 -9
  242. package/src/langwatch-api-query.ts +114 -0
  243. package/src/langwatch-api-run-plans.ts +140 -0
  244. package/src/langwatch-api-scenarios.ts +17 -10
  245. package/src/langwatch-api-secrets.ts +31 -24
  246. package/src/langwatch-api-simulation-runs.ts +10 -7
  247. package/src/langwatch-api-test-suites.ts +116 -0
  248. package/src/langwatch-api-triggers.ts +96 -34
  249. package/src/langwatch-api-workflows.ts +9 -9
  250. package/src/langwatch-api.ts +143 -109
  251. package/src/public-http-request.ts +21 -12
  252. package/src/schemas/analytics-metrics.ts +3 -15
  253. package/src/schemas/create-dataset.ts +3 -4
  254. package/src/schemas/run-plan.ts +76 -0
  255. package/src/schemas/suite-fields.ts +132 -0
  256. package/src/schemas/triggers.ts +365 -0
  257. package/src/tools/add-dashboard-widget.ts +63 -0
  258. package/src/tools/archive-project.ts +2 -4
  259. package/src/tools/archive-run-plan.ts +10 -0
  260. package/src/tools/archive-scenario.ts +2 -4
  261. package/src/tools/archive-test-suite.ts +10 -0
  262. package/src/tools/assign-prompt-tag.ts +6 -2
  263. package/src/tools/create-agent.ts +1 -1
  264. package/src/tools/create-annotation.ts +7 -2
  265. package/src/tools/create-api-key.ts +4 -6
  266. package/src/tools/create-dashboard.ts +1 -1
  267. package/src/tools/create-dataset-records.ts +4 -8
  268. package/src/tools/create-dataset.ts +5 -7
  269. package/src/tools/create-evaluator.ts +3 -5
  270. package/src/tools/create-project.ts +2 -2
  271. package/src/tools/create-prompt-tag.ts +2 -4
  272. package/src/tools/create-prompt.ts +9 -18
  273. package/src/tools/create-scenario.ts +11 -5
  274. package/src/tools/create-test-suite.ts +38 -0
  275. package/src/tools/create-trigger.ts +55 -0
  276. package/src/tools/dashboard-exists.ts +25 -0
  277. package/src/tools/dashboard-widget-queries.ts +32 -0
  278. package/src/tools/delete-agent.ts +1 -1
  279. package/src/tools/delete-annotation.ts +1 -1
  280. package/src/tools/delete-dashboard.ts +1 -1
  281. package/src/tools/delete-dataset-records.ts +4 -8
  282. package/src/tools/delete-dataset.ts +3 -7
  283. package/src/tools/delete-evaluator.ts +4 -6
  284. package/src/tools/delete-prompt-tag.ts +2 -4
  285. package/src/tools/delete-workflow.ts +1 -1
  286. package/src/tools/discover-evaluator-schema.ts +34 -25
  287. package/src/tools/discover-scenario-schema.ts +86 -12
  288. package/src/tools/discover-schema.ts +149 -27
  289. package/src/tools/experiment-run-status.ts +2 -8
  290. package/src/tools/format-dataset-mutation.ts +5 -10
  291. package/src/tools/format-run-plan.ts +54 -0
  292. package/src/tools/format-scenario.ts +12 -0
  293. package/src/tools/format-suite-details.ts +90 -0
  294. package/src/tools/get-agent.ts +54 -3
  295. package/src/tools/get-analytics.ts +52 -46
  296. package/src/tools/get-dashboard.ts +1 -1
  297. package/src/tools/get-dataset.ts +34 -16
  298. package/src/tools/get-evaluator.ts +4 -11
  299. package/src/tools/get-experiment-results.ts +219 -186
  300. package/src/tools/get-project.ts +2 -4
  301. package/src/tools/get-prompt.ts +100 -37
  302. package/src/tools/get-run-plan.ts +60 -0
  303. package/src/tools/get-scenario.ts +6 -5
  304. package/src/tools/get-simulation-run.ts +32 -20
  305. package/src/tools/get-test-suite.ts +46 -0
  306. package/src/tools/get-trace.ts +16 -17
  307. package/src/tools/get-workflow.ts +1 -1
  308. package/src/tools/list-agents.ts +20 -3
  309. package/src/tools/list-annotations.ts +8 -5
  310. package/src/tools/list-api-keys.ts +7 -2
  311. package/src/tools/list-dashboard-boards.ts +28 -0
  312. package/src/tools/list-dashboards.ts +1 -1
  313. package/src/tools/list-dataset-records.ts +8 -6
  314. package/src/tools/list-datasets.ts +12 -23
  315. package/src/tools/list-evaluators.ts +4 -8
  316. package/src/tools/list-experiment-runs.ts +5 -9
  317. package/src/tools/list-experiments.ts +5 -11
  318. package/src/tools/list-model-providers.ts +3 -5
  319. package/src/tools/list-projects.ts +2 -4
  320. package/src/tools/list-prompt-tags.ts +3 -3
  321. package/src/tools/list-prompts.ts +4 -8
  322. package/src/tools/list-run-plans.ts +47 -0
  323. package/src/tools/list-scenarios.ts +26 -17
  324. package/src/tools/list-simulation-runs.ts +13 -5
  325. package/src/tools/list-test-suites.ts +35 -0
  326. package/src/tools/list-trigger-fires.ts +17 -0
  327. package/src/tools/list-triggers.ts +39 -0
  328. package/src/tools/list-workflows.ts +2 -4
  329. package/src/tools/rename-prompt-tag.ts +1 -1
  330. package/src/tools/rename-test-suite.ts +15 -0
  331. package/src/tools/report-issue.ts +5 -9
  332. package/src/tools/rerun-run-plan.ts +18 -0
  333. package/src/tools/revoke-api-key.ts +2 -4
  334. package/src/tools/run-agent.ts +65 -14
  335. package/src/tools/run-experiment.ts +36 -37
  336. package/src/tools/run-plan.ts +46 -0
  337. package/src/tools/run-query.ts +47 -0
  338. package/src/tools/run-test-suite.ts +27 -0
  339. package/src/tools/run-workflow.ts +2 -5
  340. package/src/tools/search-traces.ts +161 -47
  341. package/src/tools/set-model-provider.ts +4 -6
  342. package/src/tools/test-agent.ts +18 -0
  343. package/src/tools/update-agent.ts +1 -1
  344. package/src/tools/update-dashboard-widget.ts +97 -0
  345. package/src/tools/update-dataset-record.ts +1 -1
  346. package/src/tools/update-dataset.ts +5 -7
  347. package/src/tools/update-evaluator.ts +3 -5
  348. package/src/tools/update-project.ts +1 -1
  349. package/src/tools/update-prompt.ts +185 -15
  350. package/src/tools/update-scenario.ts +11 -5
  351. package/src/tools/update-test-suite.ts +40 -0
  352. package/src/utils/date-parsing.ts +1 -1
  353. package/src/utils/escape-markdown.ts +3 -8
  354. package/src/utils/format-evaluations.ts +6 -6
  355. package/src/utils/markdown-table.ts +58 -0
  356. package/src/utils/trace-id-shape.ts +20 -0
  357. package/tsconfig.app.json +24 -0
  358. package/tsconfig.json +19 -12
  359. package/uv.lock +416 -296
  360. package/vitest.integration.config.js +10 -0
  361. package/vitest.scenario.config.js +9 -0
  362. package/.eslintrc.cjs +0 -36
  363. package/dist/archive-suite-4T6BSRS7.js +0 -16
  364. package/dist/chunk-77BNWQ3U.js +0 -86
  365. package/dist/chunk-A2LEVYQ5.js +0 -217
  366. package/dist/chunk-TJCXFNDT.js +0 -24
  367. package/dist/chunk-YZLYHLLI.js +0 -48
  368. package/dist/config.d.ts +0 -17
  369. package/dist/create-mcp-server.d.ts +0 -10
  370. package/dist/create-suite-LZS6QIAF.js +0 -39
  371. package/dist/delete-evaluator-33SP2JFX.js +0 -16
  372. package/dist/discover-evaluator-schema-XTAD4X7D.js +0 -2191
  373. package/dist/discover-scenario-schema-FE64QK2D.js +0 -67
  374. package/dist/get-agent-Y7MWZ65F.js +0 -29
  375. package/dist/get-analytics-TETCSOK6.js +0 -73
  376. package/dist/get-dataset-RCMU5VAH.js +0 -49
  377. package/dist/get-prompt-OY5B7TRI.js +0 -46
  378. package/dist/get-suite-J7JVWO6O.js +0 -45
  379. package/dist/index.d.ts +0 -2
  380. package/dist/langwatch-api-secrets-BUBSNCNO.js +0 -41
  381. package/dist/langwatch-api-triggers-EDFUCJN6.js +0 -31
  382. package/dist/list-agents-KFHKGPXV.js +0 -33
  383. package/dist/list-scenarios-F2WYNRIE.js +0 -41
  384. package/dist/list-suites-CRY4VWW6.js +0 -43
  385. package/dist/report-issue-XYVAPAYJ.js +0 -412
  386. package/dist/run-suite-NKZCJ2IN.js +0 -30
  387. package/dist/search-traces-A6HFKPLJ.js +0 -79
  388. package/dist/update-prompt-ODCRQRN6.js +0 -25
  389. package/dist/update-suite-SNO3GS7T.js +0 -40
  390. package/src/__tests__/all-tools.integration.test.ts +0 -1626
  391. package/src/__tests__/config.unit.test.ts +0 -202
  392. package/src/__tests__/datasets.integration.test.ts +0 -620
  393. package/src/__tests__/datasets.unit.test.ts +0 -244
  394. package/src/__tests__/date-parsing.unit.test.ts +0 -78
  395. package/src/__tests__/discover-evaluator-schema.unit.test.ts +0 -89
  396. package/src/__tests__/discover-schema.unit.test.ts +0 -118
  397. package/src/__tests__/docker.integration.test.ts +0 -318
  398. package/src/__tests__/documentation-fetch-security.integration.test.ts +0 -182
  399. package/src/__tests__/evaluator-tools.unit.test.ts +0 -262
  400. package/src/__tests__/experiment-list-tools.unit.test.ts +0 -157
  401. package/src/__tests__/experiment-status.unit.test.ts +0 -194
  402. package/src/__tests__/feature-map-tool-drift.unit.test.ts +0 -93
  403. package/src/__tests__/get-experiment-results.unit.test.ts +0 -313
  404. package/src/__tests__/http-security-origin.unit.test.ts +0 -97
  405. package/src/__tests__/http-security-sessions.unit.test.ts +0 -209
  406. package/src/__tests__/http-security-verifier.unit.test.ts +0 -248
  407. package/src/__tests__/http-server-allocation.integration.test.ts +0 -279
  408. package/src/__tests__/http-server-origin.integration.test.ts +0 -169
  409. package/src/__tests__/http-server-session-auth.integration.test.ts +0 -341
  410. package/src/__tests__/http-transport.integration.test.ts +0 -395
  411. package/src/__tests__/integration.integration.test.ts +0 -288
  412. package/src/__tests__/langwatch-api.unit.test.ts +0 -661
  413. package/src/__tests__/model-provider-tools.unit.test.ts +0 -190
  414. package/src/__tests__/project-api-key-tools.unit.test.ts +0 -451
  415. package/src/__tests__/public-http-request-security.integration.test.ts +0 -118
  416. package/src/__tests__/report-issue.integration.test.ts +0 -147
  417. package/src/__tests__/scenario-tools.integration.test.ts +0 -286
  418. package/src/__tests__/scenario-tools.unit.test.ts +0 -188
  419. package/src/__tests__/schemas.unit.test.ts +0 -85
  420. package/src/__tests__/support/http-server-harness.ts +0 -138
  421. package/src/__tests__/tools.unit.test.ts +0 -924
  422. package/src/langwatch-api-suites.ts +0 -118
  423. package/src/schemas/filter-fields.ts +0 -119
  424. package/src/schemas/index.ts +0 -4
  425. package/src/tools/archive-suite.ts +0 -12
  426. package/src/tools/create-suite.ts +0 -42
  427. package/src/tools/get-suite.ts +0 -47
  428. package/src/tools/list-suites.ts +0 -43
  429. package/src/tools/run-suite.ts +0 -28
  430. package/src/tools/update-suite.ts +0 -44
@@ -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
- });