@langwatch/mcp-server 2.2.0 → 3.1.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 (253) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/dist/add-dashboard-widget-3IE3W5RR.js +46 -0
  3. package/dist/add-dashboard-widget-XNAIGV37.js +45 -0
  4. package/dist/{archive-project-KWFM3I5Z.js → archive-project-LAWWNKTX.js} +4 -4
  5. package/dist/{archive-project-SPVHXK6A.js → archive-project-X64627XS.js} +4 -4
  6. package/dist/{archive-run-plan-Z4SYE6BP.js → archive-run-plan-3HKFL5MS.js} +4 -4
  7. package/dist/{archive-run-plan-65QN3XRX.js → archive-run-plan-C35EJACZ.js} +4 -4
  8. package/dist/{archive-scenario-A6QV5LOW.js → archive-scenario-3DOXHOJJ.js} +4 -4
  9. package/dist/{archive-scenario-FXEYQNEH.js → archive-scenario-7KDGEZM5.js} +4 -4
  10. package/dist/{archive-test-suite-NKZDZY3D.js → archive-test-suite-KZOESY2Y.js} +4 -4
  11. package/dist/{archive-test-suite-5ADQ3KPQ.js → archive-test-suite-RPJ6ZKBV.js} +4 -4
  12. package/dist/{assign-prompt-tag-5IUZXJ2T.js → assign-prompt-tag-2A25CXB7.js} +3 -3
  13. package/dist/{assign-prompt-tag-HBZLBIFD.js → assign-prompt-tag-TQRV6D6V.js} +3 -3
  14. package/dist/{chunk-Y34DHR5K.js → chunk-27SS5FBC.js} +2 -2
  15. package/dist/chunk-2RLDGMPZ.js +79 -0
  16. package/dist/{chunk-VMWJD732.js → chunk-3GVTJ7NK.js} +2 -2
  17. package/dist/chunk-6DF65T3B.js +36 -0
  18. package/dist/{chunk-3OCG3QPU.js → chunk-6OLI3LFY.js} +2 -2
  19. package/dist/{chunk-B4J3PJLX.js → chunk-7HJSQOSZ.js} +2 -6
  20. package/dist/{chunk-UWLE5T2F.js → chunk-7MNQDTKJ.js} +46 -27
  21. package/dist/{chunk-I7ATIZED.js → chunk-BHCYKMRH.js} +2 -2
  22. package/dist/{chunk-H6WGMG2T.js → chunk-DULFP3MK.js} +1 -1
  23. package/dist/{chunk-NKMTIHIJ.js → chunk-FSU2ZBUM.js} +2 -2
  24. package/dist/{chunk-SXFC3FNH.js → chunk-I2Z5CBOU.js} +2 -2
  25. package/dist/{chunk-J7PQKBLD.js → chunk-JEMUBKLJ.js} +533 -402
  26. package/dist/{chunk-7VNSRCXO.js → chunk-JOFSQFCN.js} +2 -2
  27. package/dist/{chunk-HGELNIVY.js → chunk-JQN3VXPH.js} +3 -3
  28. package/dist/{chunk-UTJCWXPZ.js → chunk-LXBQK3J3.js} +2 -2
  29. package/dist/{chunk-JRJPH75H.js → chunk-MQRTYXHJ.js} +2 -2
  30. package/dist/{chunk-YCARO42Z.js → chunk-P2JRKSYI.js} +3 -3
  31. package/dist/{chunk-PTDR56Z3.js → chunk-QF7ZGYVI.js} +2 -2
  32. package/dist/{chunk-UNJM3BIL.js → chunk-QTAHHJH3.js} +2 -2
  33. package/dist/chunk-SLRQHMJZ.js +41 -0
  34. package/dist/{chunk-SUPUUC4W.js → chunk-YQWZ4CDN.js} +5 -3
  35. package/dist/{config-EAKW6F26.js → config-2WQGMAEN.js} +2 -2
  36. package/dist/config.js +1 -1
  37. package/dist/{create-agent-S5ZBCEFT.js → create-agent-IE7Q2Z4C.js} +4 -4
  38. package/dist/{create-agent-AYZ3LB3V.js → create-agent-JMCQ5WZC.js} +4 -4
  39. package/dist/create-analytics-report-4X5N7EOT.js +19 -0
  40. package/dist/create-analytics-report-IKWZRS2O.js +18 -0
  41. package/dist/{create-annotation-VUSXULQK.js → create-annotation-IZ53SJOX.js} +4 -4
  42. package/dist/{create-annotation-LHNCLHYP.js → create-annotation-JR6DBHPW.js} +4 -4
  43. package/dist/{create-api-key-T4KSNPKB.js → create-api-key-IKMOTWCD.js} +4 -4
  44. package/dist/{create-api-key-NNYKARMG.js → create-api-key-YUDAGOWL.js} +4 -4
  45. package/dist/{create-dataset-2MC4SD4O.js → create-dataset-54FJCX45.js} +4 -4
  46. package/dist/{create-dataset-LUP5PVDM.js → create-dataset-ONX3RADL.js} +4 -4
  47. package/dist/{create-dataset-records-W4GLN2FV.js → create-dataset-records-HPLMFDJY.js} +4 -4
  48. package/dist/{create-dataset-records-NSKBZP3G.js → create-dataset-records-QZZZF64Z.js} +4 -4
  49. package/dist/{create-evaluator-HMTYO5SS.js → create-evaluator-I5I52HOQ.js} +4 -4
  50. package/dist/{create-evaluator-643G6LXL.js → create-evaluator-L66QGSDX.js} +4 -4
  51. package/dist/create-mcp-server.cjs +851 -597
  52. package/dist/create-mcp-server.js +523 -392
  53. package/dist/{create-project-6N7PIYRY.js → create-project-UPZGETN5.js} +4 -4
  54. package/dist/{create-project-KAIC46UY.js → create-project-Y5EGJKDG.js} +4 -4
  55. package/dist/{create-prompt-PKJ7EDRR.js → create-prompt-RNUJOL25.js} +3 -3
  56. package/dist/{create-prompt-E67LXIYT.js → create-prompt-WGQLJASD.js} +3 -3
  57. package/dist/{create-prompt-tag-OPQUEXWB.js → create-prompt-tag-3ZCA7M7O.js} +3 -3
  58. package/dist/{create-prompt-tag-4YO3FSJ3.js → create-prompt-tag-R6KIAZTB.js} +3 -3
  59. package/dist/{create-scenario-UEM77OE7.js → create-scenario-WIMKZLQO.js} +4 -4
  60. package/dist/{create-scenario-5PJBMAXO.js → create-scenario-WO5NWXVQ.js} +4 -4
  61. package/dist/{create-test-suite-4IPXVSFQ.js → create-test-suite-AVSR7IIM.js} +4 -4
  62. package/dist/{create-test-suite-SZEPVXSE.js → create-test-suite-LRKCNIJA.js} +4 -4
  63. package/dist/{create-trigger-5HZSCRAN.js → create-trigger-CBO2XDYC.js} +4 -4
  64. package/dist/{create-trigger-PRELMT6J.js → create-trigger-M3VFK5UH.js} +4 -4
  65. package/dist/dashboards-4X6QUT3E.js +90 -0
  66. package/dist/dashboards-CX2T6RKH.js +91 -0
  67. package/dist/{delete-agent-QMEK3XHK.js → delete-agent-QUVDMSOC.js} +4 -4
  68. package/dist/{delete-agent-JUIZWAXG.js → delete-agent-Y4QTEQ3B.js} +4 -4
  69. package/dist/delete-analytics-report-T4GIMEOA.js +18 -0
  70. package/dist/delete-analytics-report-WIP24EXV.js +19 -0
  71. package/dist/{delete-annotation-VKIQWUYW.js → delete-annotation-BWO5ZEZY.js} +4 -4
  72. package/dist/{delete-annotation-HY3O2OGR.js → delete-annotation-ESUH3RWN.js} +4 -4
  73. package/dist/{delete-dataset-WKRUW4FP.js → delete-dataset-N4AEYIAA.js} +4 -4
  74. package/dist/{delete-dataset-HQCR66MG.js → delete-dataset-ZRD23FLO.js} +4 -4
  75. package/dist/{delete-dataset-records-SDUHQLLM.js → delete-dataset-records-HC7VLBT7.js} +4 -4
  76. package/dist/{delete-dataset-records-C2IQFFVQ.js → delete-dataset-records-XC2DFVXD.js} +4 -4
  77. package/dist/{delete-evaluator-QP3QHTLN.js → delete-evaluator-27P5XLNV.js} +4 -4
  78. package/dist/{delete-evaluator-4SNSCLEE.js → delete-evaluator-LJII4YLC.js} +4 -4
  79. package/dist/{delete-prompt-tag-YYQ4VMAD.js → delete-prompt-tag-DH7IQO4X.js} +3 -3
  80. package/dist/{delete-prompt-tag-NZ4JQMYG.js → delete-prompt-tag-OC57CN32.js} +3 -3
  81. package/dist/{delete-workflow-5J46T73T.js → delete-workflow-I4IXK3ZL.js} +4 -4
  82. package/dist/{delete-workflow-JSWABL5F.js → delete-workflow-JXREDDW7.js} +4 -4
  83. package/dist/{discover-schema-A33SLMXW.js → discover-schema-ME5BAD2S.js} +4 -4
  84. package/dist/{discover-schema-55YJBFGQ.js → discover-schema-OHYBG3CY.js} +4 -4
  85. package/dist/{get-agent-LJQX7OF4.js → get-agent-6GKIKKL7.js} +4 -4
  86. package/dist/{get-agent-OTIYUFZA.js → get-agent-UKZUBVPB.js} +4 -4
  87. package/dist/{get-analytics-IQZKJHLW.js → get-analytics-TI2U3JLA.js} +3 -3
  88. package/dist/{get-analytics-DCS72353.js → get-analytics-ZGQ4LY3I.js} +3 -3
  89. package/dist/get-analytics-report-PD6XZ4ZA.js +29 -0
  90. package/dist/get-analytics-report-QMXNQ7VA.js +30 -0
  91. package/dist/{get-dataset-ALSP7RTX.js → get-dataset-5QORNVOZ.js} +4 -4
  92. package/dist/{get-dataset-X4B5JDG2.js → get-dataset-E5WLIPNK.js} +4 -4
  93. package/dist/{get-evaluator-XEUZGZCH.js → get-evaluator-GYQFB4F3.js} +4 -4
  94. package/dist/{get-evaluator-ISMC4LLI.js → get-evaluator-QQV65MQB.js} +4 -4
  95. package/dist/{get-project-5VKROSDH.js → get-project-43SGQCAT.js} +4 -4
  96. package/dist/{get-project-RM6FRCBK.js → get-project-W5DCKXZP.js} +4 -4
  97. package/dist/{get-prompt-OWXJZHQQ.js → get-prompt-IUTPSRRI.js} +3 -3
  98. package/dist/{get-prompt-W52DY36E.js → get-prompt-ZTCWGYJV.js} +3 -3
  99. package/dist/{get-run-plan-BE3M2AUX.js → get-run-plan-M3LVXMGO.js} +4 -4
  100. package/dist/{get-run-plan-RUXQ6PAX.js → get-run-plan-MEPEU353.js} +4 -4
  101. package/dist/{get-scenario-RNM7BAX2.js → get-scenario-2DM4XR44.js} +4 -4
  102. package/dist/{get-scenario-YM4ODWW6.js → get-scenario-D6EPSSPW.js} +4 -4
  103. package/dist/{get-simulation-run-6GIATQE5.js → get-simulation-run-53WM2XOO.js} +4 -4
  104. package/dist/{get-simulation-run-LCFSMPGQ.js → get-simulation-run-RKQ52TKP.js} +4 -4
  105. package/dist/{get-test-suite-P5LJ6VLF.js → get-test-suite-DP2HNOQZ.js} +4 -4
  106. package/dist/{get-test-suite-GC2O7YH6.js → get-test-suite-MUSY2CDJ.js} +4 -4
  107. package/dist/{get-trace-SEF3FMR5.js → get-trace-5Z2BIZ3V.js} +3 -3
  108. package/dist/{get-trace-KBRVV4NN.js → get-trace-THPWSLD3.js} +3 -3
  109. package/dist/{get-workflow-YXULW4GC.js → get-workflow-63E7BNLY.js} +4 -4
  110. package/dist/{get-workflow-7PVED7JE.js → get-workflow-R6XUKTZ7.js} +4 -4
  111. package/dist/{http-server-IR4QOS43.js → http-server-4JHSQN56.js} +245 -45
  112. package/dist/index.js +1847 -899
  113. package/dist/langwatch-api-analytics-reports-IIHGTTQA.js +17 -0
  114. package/dist/langwatch-api-analytics-reports-IQ6CHM5Y.js +18 -0
  115. package/dist/{langwatch-api-annotations-TBHLCQ5R.js → langwatch-api-annotations-CN2KYV3Z.js} +4 -4
  116. package/dist/{langwatch-api-annotations-6SA4OB4C.js → langwatch-api-annotations-CRI6JTQR.js} +4 -4
  117. package/dist/{langwatch-api-monitors-CBF3FGIM.js → langwatch-api-monitors-66O5Z5LB.js} +3 -3
  118. package/dist/{langwatch-api-monitors-YNWA2M5Y.js → langwatch-api-monitors-GNHQRPMR.js} +3 -3
  119. package/dist/{langwatch-api-secrets-RNFO4LF2.js → langwatch-api-secrets-B7BURV76.js} +3 -3
  120. package/dist/{langwatch-api-secrets-ADTOJELP.js → langwatch-api-secrets-P6SHZOHE.js} +3 -3
  121. package/dist/{langwatch-api-triggers-KQDQC6L5.js → langwatch-api-triggers-6FR4VWDL.js} +4 -4
  122. package/dist/{langwatch-api-triggers-QS7HDIVW.js → langwatch-api-triggers-VKNGXSJH.js} +4 -4
  123. package/dist/langwatch-api-workflows-22RQFYO7.js +15 -0
  124. package/dist/{langwatch-api-workflows-OKC4FXIF.js → langwatch-api-workflows-KDACD36L.js} +4 -4
  125. package/dist/{list-agents-RBAOCF53.js → list-agents-SVXWLLO7.js} +4 -4
  126. package/dist/{list-agents-HVYWEQMI.js → list-agents-XM5JNCVK.js} +4 -4
  127. package/dist/list-analytics-reports-DEKKC6BU.js +32 -0
  128. package/dist/list-analytics-reports-E7QFC22G.js +33 -0
  129. package/dist/{list-annotations-J4UAHSUN.js → list-annotations-5CGNOIKI.js} +4 -4
  130. package/dist/{list-annotations-HJH4NBLD.js → list-annotations-P26ELIAO.js} +4 -4
  131. package/dist/{list-api-keys-A2PMV435.js → list-api-keys-B4YL7STE.js} +4 -4
  132. package/dist/{list-api-keys-7UTJRZDG.js → list-api-keys-ZIJJH755.js} +4 -4
  133. package/dist/list-dashboards-F4YJPDKD.js +29 -0
  134. package/dist/list-dashboards-XHYTXEQK.js +30 -0
  135. package/dist/{list-dataset-records-WFM7F33C.js → list-dataset-records-SWCEDRPX.js} +4 -4
  136. package/dist/{list-dataset-records-M5TKA6LK.js → list-dataset-records-YWGROVKC.js} +4 -4
  137. package/dist/{list-datasets-B5X4P7BQ.js → list-datasets-32SCF66H.js} +4 -4
  138. package/dist/{list-datasets-THUKQHPX.js → list-datasets-YYADWT4D.js} +4 -4
  139. package/dist/{list-evaluators-MYH2OVCI.js → list-evaluators-KKQKBJKN.js} +4 -4
  140. package/dist/{list-evaluators-NLVWF6K7.js → list-evaluators-V6LP6ZQA.js} +4 -4
  141. package/dist/{list-model-providers-3JUGP4YI.js → list-model-providers-RCPVT7R4.js} +4 -4
  142. package/dist/{list-model-providers-H3XKORFO.js → list-model-providers-TMBSB6EE.js} +4 -4
  143. package/dist/{list-projects-YNNSRMLC.js → list-projects-4Y74TFDZ.js} +4 -4
  144. package/dist/{list-projects-6EJ5YYEW.js → list-projects-R4MTRF3C.js} +4 -4
  145. package/dist/{list-prompt-tags-NVFQO6WX.js → list-prompt-tags-C345AGM2.js} +3 -3
  146. package/dist/{list-prompt-tags-XUQTTAH4.js → list-prompt-tags-RITKQDC5.js} +3 -3
  147. package/dist/{list-prompts-IRI6AIXO.js → list-prompts-DSJ2LUSU.js} +3 -3
  148. package/dist/{list-prompts-HSIMMHTF.js → list-prompts-F7C5L5XK.js} +3 -3
  149. package/dist/{list-run-plans-PX2XI6EK.js → list-run-plans-YPGLC5QG.js} +4 -4
  150. package/dist/{list-run-plans-QALLCN2K.js → list-run-plans-ZHRZHCDL.js} +4 -4
  151. package/dist/{list-scenarios-SSJQEMJP.js → list-scenarios-6HN72TMW.js} +4 -4
  152. package/dist/{list-scenarios-QZRPVHS4.js → list-scenarios-HCYFOTSL.js} +4 -4
  153. package/dist/{list-simulation-runs-OEADLLQR.js → list-simulation-runs-BKVMQQMT.js} +4 -4
  154. package/dist/{list-simulation-runs-KNOLGMDV.js → list-simulation-runs-JNST5PQU.js} +4 -4
  155. package/dist/{list-test-suites-N4WVLBKK.js → list-test-suites-4ZVYYKVB.js} +4 -4
  156. package/dist/{list-test-suites-ANAQBLDG.js → list-test-suites-YY4J3L7H.js} +4 -4
  157. package/dist/{list-trigger-fires-WTW4DVIW.js → list-trigger-fires-3XM6YZWG.js} +4 -4
  158. package/dist/{list-trigger-fires-JV3WFYYG.js → list-trigger-fires-5C5XM2KQ.js} +4 -4
  159. package/dist/{list-triggers-V4Y356AK.js → list-triggers-DARBIIRA.js} +4 -4
  160. package/dist/{list-triggers-SQNIG35Q.js → list-triggers-MRSWN7RR.js} +4 -4
  161. package/dist/{list-workflows-ZHTX5LCL.js → list-workflows-BGUSQUJX.js} +4 -4
  162. package/dist/{list-workflows-IMSX7SXU.js → list-workflows-NXOWP3XS.js} +4 -4
  163. package/dist/{rename-prompt-tag-IQI7MHOI.js → rename-prompt-tag-F3WT4FB4.js} +3 -3
  164. package/dist/{rename-prompt-tag-PA2BRIE6.js → rename-prompt-tag-HR5HZZI2.js} +3 -3
  165. package/dist/{rename-test-suite-NNVLMLKY.js → rename-test-suite-2ZRXG5O7.js} +4 -4
  166. package/dist/{rename-test-suite-4J7UX5S2.js → rename-test-suite-PWXKE7Z4.js} +4 -4
  167. package/dist/{report-issue-AS34ZMJF.js → report-issue-HG7XCPOY.js} +28 -2
  168. package/dist/{report-issue-DCZFLGDO.js → report-issue-TWRFUPGB.js} +28 -2
  169. package/dist/{rerun-run-plan-TG2V4WM4.js → rerun-run-plan-BFRZFEJB.js} +4 -4
  170. package/dist/{rerun-run-plan-ZI5OY3VA.js → rerun-run-plan-LXM3RFZC.js} +4 -4
  171. package/dist/{revoke-api-key-3J3ZA4UB.js → revoke-api-key-GR55PUP4.js} +4 -4
  172. package/dist/{revoke-api-key-SFMEFWJC.js → revoke-api-key-KCDOYPUK.js} +4 -4
  173. package/dist/{run-agent-YNV6ZHW4.js → run-agent-HRVRHRHI.js} +4 -4
  174. package/dist/{run-agent-W4VJP72Z.js → run-agent-WS6TADJQ.js} +4 -4
  175. package/dist/{run-plan-6C77GWG4.js → run-plan-G24DBB5D.js} +4 -4
  176. package/dist/{run-plan-PAARQSI4.js → run-plan-NSXMBEC5.js} +4 -4
  177. package/dist/{run-query-T4QW2Z5O.js → run-query-6YVOA5NV.js} +19 -5
  178. package/dist/{run-query-KJDH544C.js → run-query-7QIYSDVI.js} +19 -5
  179. package/dist/{run-test-suite-STB6NUJM.js → run-test-suite-NTKLJZCJ.js} +4 -4
  180. package/dist/{run-test-suite-SQJELEZX.js → run-test-suite-P33XFQ6H.js} +4 -4
  181. package/dist/{run-workflow-D6PQNBI6.js → run-workflow-E5ZRSXUB.js} +4 -4
  182. package/dist/{run-workflow-SP32SO5M.js → run-workflow-HDF6CRLM.js} +4 -4
  183. package/dist/{search-traces-HCBGOG6R.js → search-traces-X7NSRTTP.js} +3 -3
  184. package/dist/{search-traces-HSTQ6WTQ.js → search-traces-XWZYOZOM.js} +3 -3
  185. package/dist/{set-model-provider-GF7NXUJA.js → set-model-provider-XJF47L6H.js} +4 -4
  186. package/dist/{set-model-provider-KDQ7C4EZ.js → set-model-provider-YPUCFEXG.js} +4 -4
  187. package/dist/{update-agent-MXNOBS4H.js → update-agent-6FHGWOO7.js} +4 -4
  188. package/dist/{update-agent-DWG43T2P.js → update-agent-VEDXQRSM.js} +4 -4
  189. package/dist/update-dashboard-widget-VOKXN7JA.js +64 -0
  190. package/dist/update-dashboard-widget-VUIQZ7F5.js +63 -0
  191. package/dist/{update-dataset-SQZ6T4WX.js → update-dataset-7AQ24NRS.js} +4 -4
  192. package/dist/{update-dataset-DQH3OHOU.js → update-dataset-GHKDCJJQ.js} +4 -4
  193. package/dist/{update-dataset-record-3AT4IPBC.js → update-dataset-record-IRD6FH2C.js} +4 -4
  194. package/dist/{update-dataset-record-7PLDGTMR.js → update-dataset-record-ZZUPG7AS.js} +4 -4
  195. package/dist/{update-evaluator-4LFTKFPT.js → update-evaluator-O6EJFTQJ.js} +4 -4
  196. package/dist/{update-evaluator-IGTX6PX4.js → update-evaluator-PUJFU5LT.js} +4 -4
  197. package/dist/{update-project-PLJIOZS6.js → update-project-HO53IHXC.js} +4 -4
  198. package/dist/{update-project-QVHSJRUP.js → update-project-VTVU6KNP.js} +4 -4
  199. package/dist/{update-prompt-GDKRYJI3.js → update-prompt-FABVQCAC.js} +3 -3
  200. package/dist/{update-prompt-MY263DYF.js → update-prompt-MNRLCLBA.js} +3 -3
  201. package/dist/{update-scenario-MOHRQKAQ.js → update-scenario-MQZZM5CP.js} +4 -4
  202. package/dist/{update-scenario-7KA3JDXA.js → update-scenario-XIZNUH4I.js} +4 -4
  203. package/package.json +2 -2
  204. package/pyproject.toml +17 -2
  205. package/src/config.d.ts +2 -0
  206. package/src/config.ts +2 -0
  207. package/src/create-mcp-server.ts +165 -41
  208. package/src/langwatch-api-analytics-reports.ts +62 -0
  209. package/src/langwatch-api-dashboard-widgets.ts +4 -68
  210. package/src/langwatch-api-dashboards.ts +110 -28
  211. package/src/langwatch-api-projects.ts +0 -17
  212. package/src/langwatch-api-query.ts +6 -0
  213. package/src/langwatch-api.ts +60 -27
  214. package/src/schemas/widget-sources.ts +69 -0
  215. package/src/tools/add-dashboard-widget.ts +23 -32
  216. package/src/tools/create-analytics-report.ts +7 -0
  217. package/src/tools/dashboard-widget-queries.ts +22 -0
  218. package/src/tools/dashboards.ts +104 -0
  219. package/src/tools/delete-analytics-report.ts +7 -0
  220. package/src/tools/get-analytics-report.ts +23 -0
  221. package/src/tools/list-analytics-reports.ts +27 -0
  222. package/src/tools/list-dashboards.ts +20 -21
  223. package/src/tools/report-issue.ts +2 -0
  224. package/src/tools/run-experiment.ts +5 -1
  225. package/src/tools/run-query.ts +23 -1
  226. package/src/tools/update-dashboard-widget.ts +32 -40
  227. package/uv.lock +667 -341
  228. package/dist/add-dashboard-widget-4ZC5UN73.js +0 -50
  229. package/dist/add-dashboard-widget-ACC6QYBG.js +0 -49
  230. package/dist/chunk-5FNCQRCX.js +0 -91
  231. package/dist/chunk-ILZDO25L.js +0 -36
  232. package/dist/chunk-K2I7Z3LZ.js +0 -28
  233. package/dist/create-dashboard-DHVFMEU4.js +0 -18
  234. package/dist/create-dashboard-WTKKS5Z6.js +0 -19
  235. package/dist/delete-dashboard-76N66XXL.js +0 -18
  236. package/dist/delete-dashboard-JVIVHNJM.js +0 -19
  237. package/dist/get-dashboard-5NYJEIX2.js +0 -29
  238. package/dist/get-dashboard-QMTYDQAZ.js +0 -30
  239. package/dist/langwatch-api-dashboards-6EO2VVZW.js +0 -17
  240. package/dist/langwatch-api-dashboards-NHU5BZD7.js +0 -18
  241. package/dist/langwatch-api-workflows-XGJE6SR5.js +0 -15
  242. package/dist/list-dashboard-boards-OPWROHMG.js +0 -33
  243. package/dist/list-dashboard-boards-U2GJ7GC5.js +0 -34
  244. package/dist/list-dashboards-ROSYFLDQ.js +0 -33
  245. package/dist/list-dashboards-RQ635ZU7.js +0 -32
  246. package/dist/update-dashboard-widget-CJKJLCDY.js +0 -71
  247. package/dist/update-dashboard-widget-CYQDS2NR.js +0 -70
  248. package/src/langwatch-api-boards.ts +0 -46
  249. package/src/tools/create-dashboard.ts +0 -7
  250. package/src/tools/dashboard-exists.ts +0 -25
  251. package/src/tools/delete-dashboard.ts +0 -7
  252. package/src/tools/get-dashboard.ts +0 -22
  253. package/src/tools/list-dashboard-boards.ts +0 -28
@@ -1,51 +1,133 @@
1
- import { makeRequest } from "./langwatch-api.ts";
1
+ import type {
2
+ DashboardWidget,
3
+ DashboardWidgetQueryInput,
4
+ } from "./langwatch-api-dashboard-widgets.js";
5
+ import { makeRequest } from "./langwatch-api.js";
2
6
 
3
- export interface DashboardSummary {
7
+ /**
8
+ * A dashboard in the Dashboards area, at `/api/v1/dashboards`; the project comes from the API key
9
+ * (`modules/dashboard/contract/src/board-rest.schemas.ts`). Every route answers 404 while
10
+ * Dashboards is off for the key's project. Analytics Reports live at `/api/v1/analytics/reports`.
11
+ */
12
+ export interface Dashboard {
4
13
  id: string;
5
14
  name: string;
6
- order: number;
7
- graphCount: number;
15
+ description: string | null;
16
+ scope: "PRIVATE" | "PROJECT" | "ORGANIZATION";
17
+ createdById: string | null;
8
18
  createdAt: string;
9
19
  updatedAt: string;
20
+ platformUrl: string;
10
21
  }
11
22
 
12
- export interface DashboardDetail extends DashboardSummary {
13
- graphs: unknown[];
23
+ export interface DashboardListItem extends Dashboard {
24
+ widgetCount: number;
14
25
  }
15
26
 
16
- export interface DashboardListResponse {
17
- data: DashboardSummary[];
27
+ const dashboardPath = (dashboardId: string) =>
28
+ `/api/v1/dashboards/${encodeURIComponent(dashboardId)}`;
29
+ const widgetPath = (dashboardId: string, widgetId: string) =>
30
+ `${dashboardPath(dashboardId)}/widgets/${encodeURIComponent(widgetId)}`;
31
+
32
+ /** The key's project's dashboards, each with how many widgets it holds. */
33
+ export async function listDashboards(): Promise<{ data: DashboardListItem[] }> {
34
+ return makeRequest("GET", "/api/v1/dashboards") as Promise<{ data: DashboardListItem[] }>;
35
+ }
36
+
37
+ /** Reads one dashboard; a dashboard in another project, or an Analytics Report, answers 404. */
38
+ export async function getDashboard({ dashboardId }: { dashboardId: string }): Promise<Dashboard> {
39
+ return makeRequest("GET", dashboardPath(dashboardId)) as Promise<Dashboard>;
40
+ }
41
+
42
+ export async function createDashboard({ name }: { name: string }): Promise<Dashboard> {
43
+ return makeRequest("POST", "/api/v1/dashboards", { name }) as Promise<Dashboard>;
44
+ }
45
+
46
+ /** A field left out keeps its value; a `null` description clears it. */
47
+ export async function updateDashboard({
48
+ dashboardId,
49
+ ...changes
50
+ }: {
51
+ dashboardId: string;
52
+ name?: string;
53
+ description?: string | null;
54
+ }): Promise<Dashboard> {
55
+ return makeRequest("PATCH", dashboardPath(dashboardId), changes) as Promise<Dashboard>;
18
56
  }
19
57
 
20
- export async function listDashboards(): Promise<DashboardListResponse> {
21
- return makeRequest("GET", "/api/v1/dashboards") as Promise<DashboardListResponse>;
58
+ /** Deletes the dashboard with the widgets on it. */
59
+ export async function deleteDashboard({
60
+ dashboardId,
61
+ }: {
62
+ dashboardId: string;
63
+ }): Promise<{ id: string; name: string }> {
64
+ return makeRequest("DELETE", dashboardPath(dashboardId)) as Promise<{ id: string; name: string }>;
22
65
  }
23
66
 
24
- export async function getDashboard(id: string): Promise<DashboardDetail> {
67
+ export async function listWidgetsOnDashboard({
68
+ dashboardId,
69
+ }: {
70
+ dashboardId: string;
71
+ }): Promise<{ data: DashboardWidget[] }> {
72
+ return makeRequest("GET", `${dashboardPath(dashboardId)}/widgets`) as Promise<{
73
+ data: DashboardWidget[];
74
+ }>;
75
+ }
76
+
77
+ /** Saves a widget placed on this dashboard at the next free row. */
78
+ export async function createWidgetOnDashboard({
79
+ dashboardId,
80
+ ...data
81
+ }: {
82
+ dashboardId: string;
83
+ name: string;
84
+ code: string;
85
+ queries: DashboardWidgetQueryInput[];
86
+ description?: string;
87
+ }): Promise<DashboardWidget> {
25
88
  return makeRequest(
26
- "GET",
27
- `/api/v1/dashboards/${encodeURIComponent(id)}`,
28
- ) as Promise<DashboardDetail>;
89
+ "POST",
90
+ `${dashboardPath(dashboardId)}/widgets`,
91
+ data,
92
+ ) as Promise<DashboardWidget>;
29
93
  }
30
94
 
31
- export async function createDashboard(data: { name: string }): Promise<DashboardDetail> {
32
- return makeRequest("POST", "/api/v1/dashboards", data) as Promise<DashboardDetail>;
95
+ /** A widget on any other dashboard answers 404. */
96
+ export async function getWidgetOnDashboard({
97
+ dashboardId,
98
+ widgetId,
99
+ }: {
100
+ dashboardId: string;
101
+ widgetId: string;
102
+ }): Promise<DashboardWidget> {
103
+ return makeRequest("GET", widgetPath(dashboardId, widgetId)) as Promise<DashboardWidget>;
33
104
  }
34
105
 
35
- export async function renameDashboard(
36
- id: string,
37
- data: { name: string },
38
- ): Promise<DashboardDetail> {
106
+ export async function updateWidgetOnDashboard({
107
+ dashboardId,
108
+ widgetId,
109
+ ...changes
110
+ }: {
111
+ dashboardId: string;
112
+ widgetId: string;
113
+ name?: string;
114
+ code?: string;
115
+ queries?: DashboardWidgetQueryInput[];
116
+ description?: string;
117
+ }): Promise<DashboardWidget> {
39
118
  return makeRequest(
40
119
  "PATCH",
41
- `/api/v1/dashboards/${encodeURIComponent(id)}`,
42
- data,
43
- ) as Promise<DashboardDetail>;
120
+ widgetPath(dashboardId, widgetId),
121
+ changes,
122
+ ) as Promise<DashboardWidget>;
44
123
  }
45
124
 
46
- export async function deleteDashboard(id: string): Promise<{ id: string; name: string }> {
47
- return makeRequest("DELETE", `/api/v1/dashboards/${encodeURIComponent(id)}`) as Promise<{
48
- id: string;
49
- name: string;
50
- }>;
125
+ export async function deleteWidgetOnDashboard({
126
+ dashboardId,
127
+ widgetId,
128
+ }: {
129
+ dashboardId: string;
130
+ widgetId: string;
131
+ }): Promise<void> {
132
+ await makeRequest("DELETE", widgetPath(dashboardId, widgetId));
51
133
  }
@@ -45,23 +45,6 @@ export async function getProject(id: string): Promise<ProjectSummary> {
45
45
  ) as Promise<ProjectSummary>;
46
46
  }
47
47
 
48
- /** Identity of the project the calling API key belongs to. */
49
- export interface CurrentProjectIdentity {
50
- id: string;
51
- name: string;
52
- slug: string;
53
- isPersonal: boolean;
54
- }
55
-
56
- /**
57
- * Resolves the project behind the configured API key. Needed for the
58
- * `/api/v1/projects/:projectId/...` route family, whose path must name the
59
- * caller's own project — there is no "current project" shorthand there.
60
- */
61
- export async function getCurrentProject(): Promise<CurrentProjectIdentity> {
62
- return makeRequest("GET", "/api/v1/me/project") as Promise<CurrentProjectIdentity>;
63
- }
64
-
65
48
  export async function createProject(data: {
66
49
  name: string;
67
50
  language: string;
@@ -25,6 +25,8 @@ export interface QueryRunResponse {
25
25
  };
26
26
  truncated: boolean;
27
27
  diagnostics: { code: string; message: string }[];
28
+ /** Each placeholder the SQL declares by its name, plus `period`; absent on an older platform. */
29
+ params?: Record<string, unknown>;
28
30
  }
29
31
 
30
32
  /** One published dataset. */
@@ -101,10 +103,14 @@ export interface QueryReferenceResponse {
101
103
  export async function runQuery(params: {
102
104
  sql: string;
103
105
  parameters?: Record<string, string | number | boolean | null>;
106
+ projects?: string[] | string;
107
+ sources?: string[];
104
108
  }): Promise<QueryRunResponse> {
105
109
  return makeRequest("POST", "/api/v1/query", {
106
110
  sql: params.sql,
107
111
  ...(params.parameters ? { parameters: params.parameters } : {}),
112
+ ...(params.projects ? { projects: params.projects } : {}),
113
+ ...(params.sources ? { sources: params.sources } : {}),
108
114
  }) as Promise<QueryRunResponse>;
109
115
  }
110
116
 
@@ -13,6 +13,12 @@ export const MCP_IDENTITY_HEADERS: Record<string, string> = {
13
13
  "X-LangWatch-SDK-Version": packageJson.version,
14
14
  };
15
15
 
16
+ /** The dated API version every request names (specs/api-reference/client-api-version.feature). */
17
+ export const LANGWATCH_API_VERSION = "2026-10-26";
18
+
19
+ /** Names the hosted MCP server's calls apart from a local server's. */
20
+ export const HOSTED_MCP_HEADER = "X-LangWatch-MCP-Host";
21
+
16
22
  // --- Response types ---
17
23
 
18
24
  export interface TraceSearchResult {
@@ -174,6 +180,15 @@ interface ParsedErrorBody {
174
180
  docsUrl?: string;
175
181
  fault?: HandledErrorFault;
176
182
  reasons?: SerializedReason[];
183
+ /** What the error says beyond its reasons, such as the names it refused. */
184
+ meta?: Record<string, unknown>;
185
+ }
186
+
187
+ /** The error's own facts: `meta` without the reasons (shown apart) and the request echo. */
188
+ function detailsOf(meta: Record<string, unknown>): Record<string, unknown> | undefined {
189
+ const { reasons: _reasons, target: _target, fields: _fields, ...details } = meta;
190
+
191
+ return Object.keys(details).length > 0 ? details : undefined;
177
192
  }
178
193
 
179
194
  const VALID_FAULTS: readonly HandledErrorFault[] = [
@@ -210,11 +225,14 @@ function parseErrorBody(responseBody: string): ParsedErrorBody {
210
225
  const fault = VALID_FAULTS.includes(body.fault as HandledErrorFault)
211
226
  ? (body.fault as HandledErrorFault)
212
227
  : undefined;
228
+ // The v1 envelope carries the per-field failures in `meta.reasons`; older ones at the top.
229
+ const meta = isRecord(body.meta) ? body.meta : {};
230
+ const rawReasons = Array.isArray(body.reasons) ? body.reasons : meta.reasons;
213
231
  const reasons =
214
- Array.isArray(body.reasons) && body.reasons.every((r) => !!r && typeof r === "object")
215
- ? (body.reasons as SerializedReason[])
232
+ Array.isArray(rawReasons) && rawReasons.every((r) => !!r && typeof r === "object")
233
+ ? (rawReasons as SerializedReason[])
216
234
  : undefined;
217
- return { code, message, tips, docsUrl, fault, reasons };
235
+ return { code, message, tips, docsUrl, fault, reasons, meta: detailsOf(meta) };
218
236
  } catch {
219
237
  return {};
220
238
  }
@@ -261,6 +279,39 @@ function describeReason(reason: SerializedReason): string | null {
261
279
  return parts.join(" — ");
262
280
  }
263
281
 
282
+ /** The error an unsuccessful response becomes: its message, code, details, fields and tips. */
283
+ function apiErrorOf({
284
+ status,
285
+ responseBody,
286
+ }: {
287
+ status: number;
288
+ responseBody: string;
289
+ }): LangWatchApiError {
290
+ const parsed = parseErrorBody(responseBody);
291
+ const lines = [`LangWatch API error ${status}: ${parsed.message ?? responseBody}`];
292
+ if (parsed.code) lines.push(`Code: ${parsed.code}`);
293
+ if (parsed.meta) lines.push(`Details: ${JSON.stringify(parsed.meta)}`);
294
+ const reasonLines = (parsed.reasons ?? [])
295
+ .map(describeReason)
296
+ .filter((line): line is string => line !== null);
297
+ if (reasonLines.length > 0) {
298
+ lines.push("Rejected fields:", ...reasonLines);
299
+ }
300
+ if (parsed.tips && parsed.tips.length > 0) {
301
+ lines.push("Tips:", ...parsed.tips.map((tip) => `- ${tip}`));
302
+ }
303
+ if (parsed.docsUrl) {
304
+ lines.push(`Docs: ${parsed.docsUrl}`);
305
+ }
306
+ return new LangWatchApiError(lines.join("\n"), status, responseBody, {
307
+ code: parsed.code,
308
+ tips: parsed.tips,
309
+ docsUrl: parsed.docsUrl,
310
+ fault: parsed.fault,
311
+ reasons: parsed.reasons,
312
+ });
313
+ }
314
+
264
315
  /**
265
316
  * Sends an HTTP request to the LangWatch API. Builds the full URL from the configured endpoint,
266
317
  * adds authentication, and handles JSON serialization/deserialization. @throws
@@ -275,11 +326,15 @@ export async function makeRequest(
275
326
  const url = config.endpoint + path;
276
327
  const headers: Record<string, string> = {
277
328
  ...MCP_IDENTITY_HEADERS,
329
+ "X-API-Version": LANGWATCH_API_VERSION,
278
330
  "X-Auth-Token": requireApiKey(),
279
331
  };
280
332
  if (config.projectId) {
281
333
  headers["X-Project-Id"] = config.projectId;
282
334
  }
335
+ if (config.hosted) {
336
+ headers[HOSTED_MCP_HEADER] = "hosted";
337
+ }
283
338
 
284
339
  if (body !== undefined) {
285
340
  headers["Content-Type"] = "application/json";
@@ -291,30 +346,8 @@ export async function makeRequest(
291
346
  ...(body !== undefined ? { body: JSON.stringify(body) } : {}),
292
347
  });
293
348
 
294
- if (!response.ok) {
295
- const responseBody = await response.text();
296
- const parsed = parseErrorBody(responseBody);
297
- const lines = [`LangWatch API error ${response.status}: ${parsed.message ?? responseBody}`];
298
- const reasonLines = (parsed.reasons ?? [])
299
- .map(describeReason)
300
- .filter((line): line is string => line !== null);
301
- if (reasonLines.length > 0) {
302
- lines.push("Rejected fields:", ...reasonLines);
303
- }
304
- if (parsed.tips && parsed.tips.length > 0) {
305
- lines.push("Tips:", ...parsed.tips.map((tip) => `- ${tip}`));
306
- }
307
- if (parsed.docsUrl) {
308
- lines.push(`Docs: ${parsed.docsUrl}`);
309
- }
310
- throw new LangWatchApiError(lines.join("\n"), response.status, responseBody, {
311
- code: parsed.code,
312
- tips: parsed.tips,
313
- docsUrl: parsed.docsUrl,
314
- fault: parsed.fault,
315
- reasons: parsed.reasons,
316
- });
317
- }
349
+ if (!response.ok)
350
+ throw apiErrorOf({ status: response.status, responseBody: await response.text() });
318
351
 
319
352
  if (response.status === 204 || response.headers?.get("content-length") === "0") {
320
353
  return null;
@@ -0,0 +1,69 @@
1
+ /**
2
+ * The `sources` input of the widget tools: the trace origins a widget's queries count, checked
3
+ * here so an unknown one never reaches the platform. Spec: dashboards-v2.feature AC200j, AC200n.
4
+ */
5
+ import { z } from "zod";
6
+
7
+ const isAllWord = (id: string) => id.trim().toLowerCase() === "all";
8
+
9
+ /** The sources the platform takes, "other" being every origin not listed before it. */
10
+ export const WIDGET_SOURCES = [
11
+ "application",
12
+ "simulation",
13
+ "evaluation",
14
+ "sample",
15
+ "coding_agent",
16
+ "ai_tool",
17
+ "gateway",
18
+ "workflow",
19
+ "playground",
20
+ "langy",
21
+ "other",
22
+ ] as const;
23
+
24
+ /** A trace origin a widget query can count. */
25
+ export type WidgetSource = (typeof WIDGET_SOURCES)[number];
26
+
27
+ /** The tools' `sources` input: refused at the tool when it names anything else. */
28
+ export const widgetSourcesInput = z
29
+ .array(z.enum(WIDGET_SOURCES))
30
+ .max(WIDGET_SOURCES.length)
31
+ .nullable()
32
+ .optional()
33
+ .describe(
34
+ `The trace origins every query of the widget counts: any of ${WIDGET_SOURCES.join(", ")} (other = any origin not listed). A new widget counts ["application"]; add "langy" to count your own conversations, as a widget about Langy's requests needs. null makes it unset again, counting the default.`,
35
+ );
36
+
37
+ /**
38
+ * The tools' `projects` input: the project ids every query of the widget reads. Absent, a query
39
+ * keeps what it stores (a new widget reads its board's project); null makes it unset again.
40
+ */
41
+ const ALL_NOT_STORED = 'projects holds project ids; "all" is not stored in a widget';
42
+ // run_query takes "all"; a widget stores ids. The refine carries the message for "all" as a
43
+ // string or inside the array, and adds nothing to the tool's JSON Schema.
44
+ export const widgetProjectsInput = z
45
+ .array(z.string().min(1), {
46
+ error: (issue) =>
47
+ typeof issue.input === "string" && isAllWord(issue.input) ? ALL_NOT_STORED : undefined,
48
+ })
49
+ .min(1)
50
+ .refine((ids) => !ids.some(isAllWord), { message: ALL_NOT_STORED })
51
+ .nullable()
52
+ .optional()
53
+ .describe(
54
+ "The project ids every query of the widget reads, each one you can read. A new widget reads its board's project. null makes it unset again, reading the board's project.",
55
+ );
56
+
57
+ /**
58
+ * run_query's `projects`: ids, or the lone word "all" in any case. Mirrors holdsAllWord and
59
+ * LWQL_ALL_STANDS_ALONE in analytics-lwql.schemas.ts, which MCP cannot import.
60
+ */
61
+ export const runQueryProjectsInput = z.union([
62
+ z.string().refine(isAllWord),
63
+ z
64
+ .array(z.string().min(1))
65
+ .min(1)
66
+ .refine((ids) => !ids.some(isAllWord), {
67
+ message: '"all" stands alone; send it by itself, or list project ids',
68
+ }),
69
+ ]);
@@ -1,19 +1,14 @@
1
1
  /**
2
- * The `add_dashboard_widget` MCP tool: create, then place, as the platform's own write path
3
- * does. The dashboard is checked first so a typo leaves no unplaced widget behind, and a
4
- * failed placement deletes the widget it just created.
2
+ * `add_dashboard_widget`: one create under the dashboard's path, which also places the widget.
5
3
  */
6
4
 
7
- import {
8
- assignDashboardWidgetToDashboard,
9
- createDashboardWidget,
10
- deleteDashboardWidget,
11
- } from "../langwatch-api-dashboard-widgets.js";
12
- import { getCurrentProject } from "../langwatch-api-projects.js";
13
- import { assertDashboardExists } from "./dashboard-exists.js";
5
+ import { createWidgetOnDashboard } from "../langwatch-api-dashboards.js";
6
+ import { LangWatchApiError } from "../langwatch-api.js";
7
+ import type { WidgetSource } from "../schemas/widget-sources.js";
14
8
  import {
15
9
  type DashboardWidgetQueriesInput,
16
10
  normalizeDashboardWidgetQueries,
11
+ withLists,
17
12
  } from "./dashboard-widget-queries.js";
18
13
 
19
14
  export interface AddDashboardWidgetParams {
@@ -21,37 +16,33 @@ export interface AddDashboardWidgetParams {
21
16
  name: string;
22
17
  code: string;
23
18
  queries: DashboardWidgetQueriesInput;
19
+ /** Set on every query; absent, the platform stores application on each. */
20
+ sources?: WidgetSource[] | null;
21
+ /** Set on every query; absent, the widget reads its board's project. */
22
+ projects?: string[] | null;
24
23
  }
25
24
 
26
25
  export async function handleAddDashboardWidget(params: AddDashboardWidgetParams): Promise<string> {
27
- const queries = normalizeDashboardWidgetQueries({ queries: params.queries });
28
-
29
- const project = await getCurrentProject();
30
- await assertDashboardExists({ projectId: project.id, dashboardId: params.dashboardId });
31
-
32
- const widget = await createDashboardWidget({
33
- projectId: project.id,
34
- name: params.name,
35
- code: params.code,
36
- queries,
26
+ const queries = withLists({
27
+ queries: normalizeDashboardWidgetQueries({ queries: params.queries }),
28
+ sources: params.sources,
29
+ projects: params.projects,
37
30
  });
38
31
 
32
+ let widget;
39
33
  try {
40
- await assignDashboardWidgetToDashboard({
41
- projectId: project.id,
42
- widgetId: widget.id,
34
+ widget = await createWidgetOnDashboard({
43
35
  dashboardId: params.dashboardId,
36
+ name: params.name,
37
+ code: params.code,
38
+ queries,
44
39
  });
45
40
  } catch (error) {
46
- // The widget now exists but is not on the dashboard we promised — never
47
- // leave it dangling because the dashboard vanished between the check
48
- // above and this call.
49
- await deleteDashboardWidget({
50
- projectId: project.id,
51
- widgetId: widget.id,
52
- }).catch(() => {
53
- // Best-effort cleanup; the assign error below is what the caller needs.
54
- });
41
+ if (error instanceof LangWatchApiError && error.status === 404) {
42
+ throw new Error(
43
+ `No dashboard with ID "${params.dashboardId}" was found in this project. Use list_dashboards to find a valid dashboard ID.`,
44
+ );
45
+ }
55
46
  throw error;
56
47
  }
57
48
 
@@ -0,0 +1,7 @@
1
+ import { createAnalyticsReport } from "../langwatch-api-analytics-reports.ts";
2
+
3
+ export async function handleCreateAnalyticsReport(params: { name: string }): Promise<string> {
4
+ const report = await createAnalyticsReport({ name: params.name });
5
+
6
+ return `Analytics Report created successfully!\n\n**Name**: ${report.name}\n**ID**: ${report.id}`;
7
+ }
@@ -1,4 +1,26 @@
1
1
  import type { DashboardWidgetQueryInput } from "../langwatch-api-dashboard-widgets.js";
2
+ import type { WidgetSource } from "../schemas/widget-sources.js";
3
+
4
+ /**
5
+ * Every query with `sources` and `projects` set to the lists given; a list not named is left as
6
+ * the query has it.
7
+ */
8
+ export function withLists({
9
+ queries,
10
+ sources,
11
+ projects,
12
+ }: {
13
+ queries: readonly DashboardWidgetQueryInput[];
14
+ sources: WidgetSource[] | null | undefined;
15
+ projects?: string[] | null | undefined;
16
+ }): DashboardWidgetQueryInput[] {
17
+ if (sources === undefined && projects === undefined) return [...queries];
18
+ return queries.map((query) => ({
19
+ ...query,
20
+ ...(sources === undefined ? {} : { sources }),
21
+ ...(projects === undefined ? {} : { projects }),
22
+ }));
23
+ }
2
24
 
3
25
  /** A widget file rarely needs more than a couple of named queries (server bound). */
4
26
  export const MAX_DASHBOARD_WIDGET_QUERIES = 8;
@@ -0,0 +1,104 @@
1
+ /**
2
+ * The dashboard tools over `/api/v1/dashboards`: read, create, rename and delete a dashboard,
3
+ * list a dashboard's widgets and delete one. Spec: modules/dashboard/specs/dashboards-v2.feature
4
+ * AC199s.
5
+ */
6
+
7
+ import {
8
+ type Dashboard,
9
+ createDashboard,
10
+ deleteDashboard,
11
+ deleteWidgetOnDashboard,
12
+ getDashboard,
13
+ listWidgetsOnDashboard,
14
+ updateDashboard,
15
+ } from "../langwatch-api-dashboards.js";
16
+
17
+ function describeDashboard(dashboard: Dashboard): string[] {
18
+ return [
19
+ `**Name**: ${dashboard.name}`,
20
+ `**ID**: ${dashboard.id}`,
21
+ `**Scope**: ${dashboard.scope}`,
22
+ ...(dashboard.description ? [`**Description**: ${dashboard.description}`] : []),
23
+ `**URL**: ${dashboard.platformUrl}`,
24
+ ];
25
+ }
26
+
27
+ /** Reads only `/api/v1/dashboards`; an Analytics Report's id is not found there. */
28
+ export async function handleGetDashboard({
29
+ dashboardId,
30
+ }: {
31
+ dashboardId: string;
32
+ }): Promise<string> {
33
+ const dashboard = await getDashboard({ dashboardId });
34
+ return [`# ${dashboard.name}\n`, ...describeDashboard(dashboard)].join("\n");
35
+ }
36
+
37
+ export async function handleCreateDashboard({ name }: { name: string }): Promise<string> {
38
+ const dashboard = await createDashboard({ name });
39
+ return [
40
+ "Dashboard created.\n",
41
+ ...describeDashboard(dashboard),
42
+ "",
43
+ "> Pass the ID to `add_dashboard_widget` to add a widget to it.",
44
+ ].join("\n");
45
+ }
46
+
47
+ export async function handleRenameDashboard({
48
+ dashboardId,
49
+ name,
50
+ description,
51
+ }: {
52
+ dashboardId: string;
53
+ name?: string;
54
+ description?: string;
55
+ }): Promise<string> {
56
+ if (name === undefined && description === undefined) {
57
+ throw new Error("Provide at least one of name or description to change.");
58
+ }
59
+ const dashboard = await updateDashboard({
60
+ dashboardId,
61
+ ...(name === undefined ? {} : { name }),
62
+ ...(description === undefined ? {} : { description }),
63
+ });
64
+ return ["Dashboard updated.\n", ...describeDashboard(dashboard)].join("\n");
65
+ }
66
+
67
+ export async function handleDeleteDashboard({
68
+ dashboardId,
69
+ }: {
70
+ dashboardId: string;
71
+ }): Promise<string> {
72
+ const deleted = await deleteDashboard({ dashboardId });
73
+ return `Dashboard "${deleted.name}" deleted with its widgets (ID: ${deleted.id}).`;
74
+ }
75
+
76
+ export async function handleListDashboardWidgets({
77
+ dashboardId,
78
+ }: {
79
+ dashboardId: string;
80
+ }): Promise<string> {
81
+ const { data: widgets } = await listWidgetsOnDashboard({ dashboardId });
82
+ if (widgets.length === 0) return `Dashboard "${dashboardId}" has no widgets.`;
83
+
84
+ return [
85
+ `# Widgets on dashboard ${dashboardId} (${widgets.length} total)\n`,
86
+ ...widgets.flatMap((widget) => [
87
+ `## ${widget.name}`,
88
+ `**ID**: ${widget.id}`,
89
+ `**Queries**: ${widget.definition.queries.map((query) => query.name).join(", ") || "(none)"}`,
90
+ "",
91
+ ]),
92
+ ].join("\n");
93
+ }
94
+
95
+ export async function handleDeleteDashboardWidget({
96
+ dashboardId,
97
+ widgetId,
98
+ }: {
99
+ dashboardId: string;
100
+ widgetId: string;
101
+ }): Promise<string> {
102
+ await deleteWidgetOnDashboard({ dashboardId, widgetId });
103
+ return `Widget "${widgetId}" deleted from dashboard "${dashboardId}".`;
104
+ }
@@ -0,0 +1,7 @@
1
+ import { deleteAnalyticsReport } from "../langwatch-api-analytics-reports.ts";
2
+
3
+ export async function handleDeleteAnalyticsReport(params: { reportId: string }): Promise<string> {
4
+ const result = await deleteAnalyticsReport({ reportId: params.reportId });
5
+
6
+ return `Analytics Report deleted successfully!\n\n**Name**: ${result.name}\n**ID**: ${result.id}`;
7
+ }
@@ -0,0 +1,23 @@
1
+ import { getAnalyticsReport } from "../langwatch-api-analytics-reports.ts";
2
+
3
+ /** Reads only `/api/v1/analytics/reports`; a Dashboards dashboard's id is not found there. */
4
+ export async function handleGetAnalyticsReport(params: { reportId: string }): Promise<string> {
5
+ const report = await getAnalyticsReport({ reportId: params.reportId });
6
+
7
+ const lines: string[] = [];
8
+ lines.push(`# ${report.name}\n`);
9
+ lines.push(`**ID**: ${report.id}`);
10
+ lines.push(`**Order**: ${report.order}`);
11
+ lines.push(`**Graphs**: ${Array.isArray(report.graphs) ? report.graphs.length : 0}`);
12
+ lines.push(`**Created**: ${report.createdAt}`);
13
+ lines.push(`**Updated**: ${report.updatedAt}`);
14
+
15
+ if (Array.isArray(report.graphs) && report.graphs.length > 0) {
16
+ lines.push("\n## Graphs\n");
17
+ lines.push("```json");
18
+ lines.push(JSON.stringify(report.graphs, null, 2));
19
+ lines.push("```");
20
+ }
21
+
22
+ return lines.join("\n");
23
+ }