@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.
- package/CHANGELOG.md +33 -0
- package/dist/add-dashboard-widget-3IE3W5RR.js +46 -0
- package/dist/add-dashboard-widget-XNAIGV37.js +45 -0
- package/dist/{archive-project-KWFM3I5Z.js → archive-project-LAWWNKTX.js} +4 -4
- package/dist/{archive-project-SPVHXK6A.js → archive-project-X64627XS.js} +4 -4
- package/dist/{archive-run-plan-Z4SYE6BP.js → archive-run-plan-3HKFL5MS.js} +4 -4
- package/dist/{archive-run-plan-65QN3XRX.js → archive-run-plan-C35EJACZ.js} +4 -4
- package/dist/{archive-scenario-A6QV5LOW.js → archive-scenario-3DOXHOJJ.js} +4 -4
- package/dist/{archive-scenario-FXEYQNEH.js → archive-scenario-7KDGEZM5.js} +4 -4
- package/dist/{archive-test-suite-NKZDZY3D.js → archive-test-suite-KZOESY2Y.js} +4 -4
- package/dist/{archive-test-suite-5ADQ3KPQ.js → archive-test-suite-RPJ6ZKBV.js} +4 -4
- package/dist/{assign-prompt-tag-5IUZXJ2T.js → assign-prompt-tag-2A25CXB7.js} +3 -3
- package/dist/{assign-prompt-tag-HBZLBIFD.js → assign-prompt-tag-TQRV6D6V.js} +3 -3
- package/dist/{chunk-Y34DHR5K.js → chunk-27SS5FBC.js} +2 -2
- package/dist/chunk-2RLDGMPZ.js +79 -0
- package/dist/{chunk-VMWJD732.js → chunk-3GVTJ7NK.js} +2 -2
- package/dist/chunk-6DF65T3B.js +36 -0
- package/dist/{chunk-3OCG3QPU.js → chunk-6OLI3LFY.js} +2 -2
- package/dist/{chunk-B4J3PJLX.js → chunk-7HJSQOSZ.js} +2 -6
- package/dist/{chunk-UWLE5T2F.js → chunk-7MNQDTKJ.js} +46 -27
- package/dist/{chunk-I7ATIZED.js → chunk-BHCYKMRH.js} +2 -2
- package/dist/{chunk-H6WGMG2T.js → chunk-DULFP3MK.js} +1 -1
- package/dist/{chunk-NKMTIHIJ.js → chunk-FSU2ZBUM.js} +2 -2
- package/dist/{chunk-SXFC3FNH.js → chunk-I2Z5CBOU.js} +2 -2
- package/dist/{chunk-J7PQKBLD.js → chunk-JEMUBKLJ.js} +533 -402
- package/dist/{chunk-7VNSRCXO.js → chunk-JOFSQFCN.js} +2 -2
- package/dist/{chunk-HGELNIVY.js → chunk-JQN3VXPH.js} +3 -3
- package/dist/{chunk-UTJCWXPZ.js → chunk-LXBQK3J3.js} +2 -2
- package/dist/{chunk-JRJPH75H.js → chunk-MQRTYXHJ.js} +2 -2
- package/dist/{chunk-YCARO42Z.js → chunk-P2JRKSYI.js} +3 -3
- package/dist/{chunk-PTDR56Z3.js → chunk-QF7ZGYVI.js} +2 -2
- package/dist/{chunk-UNJM3BIL.js → chunk-QTAHHJH3.js} +2 -2
- package/dist/chunk-SLRQHMJZ.js +41 -0
- package/dist/{chunk-SUPUUC4W.js → chunk-YQWZ4CDN.js} +5 -3
- package/dist/{config-EAKW6F26.js → config-2WQGMAEN.js} +2 -2
- package/dist/config.js +1 -1
- package/dist/{create-agent-S5ZBCEFT.js → create-agent-IE7Q2Z4C.js} +4 -4
- package/dist/{create-agent-AYZ3LB3V.js → create-agent-JMCQ5WZC.js} +4 -4
- package/dist/create-analytics-report-4X5N7EOT.js +19 -0
- package/dist/create-analytics-report-IKWZRS2O.js +18 -0
- package/dist/{create-annotation-VUSXULQK.js → create-annotation-IZ53SJOX.js} +4 -4
- package/dist/{create-annotation-LHNCLHYP.js → create-annotation-JR6DBHPW.js} +4 -4
- package/dist/{create-api-key-T4KSNPKB.js → create-api-key-IKMOTWCD.js} +4 -4
- package/dist/{create-api-key-NNYKARMG.js → create-api-key-YUDAGOWL.js} +4 -4
- package/dist/{create-dataset-2MC4SD4O.js → create-dataset-54FJCX45.js} +4 -4
- package/dist/{create-dataset-LUP5PVDM.js → create-dataset-ONX3RADL.js} +4 -4
- package/dist/{create-dataset-records-W4GLN2FV.js → create-dataset-records-HPLMFDJY.js} +4 -4
- package/dist/{create-dataset-records-NSKBZP3G.js → create-dataset-records-QZZZF64Z.js} +4 -4
- package/dist/{create-evaluator-HMTYO5SS.js → create-evaluator-I5I52HOQ.js} +4 -4
- package/dist/{create-evaluator-643G6LXL.js → create-evaluator-L66QGSDX.js} +4 -4
- package/dist/create-mcp-server.cjs +851 -597
- package/dist/create-mcp-server.js +523 -392
- package/dist/{create-project-6N7PIYRY.js → create-project-UPZGETN5.js} +4 -4
- package/dist/{create-project-KAIC46UY.js → create-project-Y5EGJKDG.js} +4 -4
- package/dist/{create-prompt-PKJ7EDRR.js → create-prompt-RNUJOL25.js} +3 -3
- package/dist/{create-prompt-E67LXIYT.js → create-prompt-WGQLJASD.js} +3 -3
- package/dist/{create-prompt-tag-OPQUEXWB.js → create-prompt-tag-3ZCA7M7O.js} +3 -3
- package/dist/{create-prompt-tag-4YO3FSJ3.js → create-prompt-tag-R6KIAZTB.js} +3 -3
- package/dist/{create-scenario-UEM77OE7.js → create-scenario-WIMKZLQO.js} +4 -4
- package/dist/{create-scenario-5PJBMAXO.js → create-scenario-WO5NWXVQ.js} +4 -4
- package/dist/{create-test-suite-4IPXVSFQ.js → create-test-suite-AVSR7IIM.js} +4 -4
- package/dist/{create-test-suite-SZEPVXSE.js → create-test-suite-LRKCNIJA.js} +4 -4
- package/dist/{create-trigger-5HZSCRAN.js → create-trigger-CBO2XDYC.js} +4 -4
- package/dist/{create-trigger-PRELMT6J.js → create-trigger-M3VFK5UH.js} +4 -4
- package/dist/dashboards-4X6QUT3E.js +90 -0
- package/dist/dashboards-CX2T6RKH.js +91 -0
- package/dist/{delete-agent-QMEK3XHK.js → delete-agent-QUVDMSOC.js} +4 -4
- package/dist/{delete-agent-JUIZWAXG.js → delete-agent-Y4QTEQ3B.js} +4 -4
- package/dist/delete-analytics-report-T4GIMEOA.js +18 -0
- package/dist/delete-analytics-report-WIP24EXV.js +19 -0
- package/dist/{delete-annotation-VKIQWUYW.js → delete-annotation-BWO5ZEZY.js} +4 -4
- package/dist/{delete-annotation-HY3O2OGR.js → delete-annotation-ESUH3RWN.js} +4 -4
- package/dist/{delete-dataset-WKRUW4FP.js → delete-dataset-N4AEYIAA.js} +4 -4
- package/dist/{delete-dataset-HQCR66MG.js → delete-dataset-ZRD23FLO.js} +4 -4
- package/dist/{delete-dataset-records-SDUHQLLM.js → delete-dataset-records-HC7VLBT7.js} +4 -4
- package/dist/{delete-dataset-records-C2IQFFVQ.js → delete-dataset-records-XC2DFVXD.js} +4 -4
- package/dist/{delete-evaluator-QP3QHTLN.js → delete-evaluator-27P5XLNV.js} +4 -4
- package/dist/{delete-evaluator-4SNSCLEE.js → delete-evaluator-LJII4YLC.js} +4 -4
- package/dist/{delete-prompt-tag-YYQ4VMAD.js → delete-prompt-tag-DH7IQO4X.js} +3 -3
- package/dist/{delete-prompt-tag-NZ4JQMYG.js → delete-prompt-tag-OC57CN32.js} +3 -3
- package/dist/{delete-workflow-5J46T73T.js → delete-workflow-I4IXK3ZL.js} +4 -4
- package/dist/{delete-workflow-JSWABL5F.js → delete-workflow-JXREDDW7.js} +4 -4
- package/dist/{discover-schema-A33SLMXW.js → discover-schema-ME5BAD2S.js} +4 -4
- package/dist/{discover-schema-55YJBFGQ.js → discover-schema-OHYBG3CY.js} +4 -4
- package/dist/{get-agent-LJQX7OF4.js → get-agent-6GKIKKL7.js} +4 -4
- package/dist/{get-agent-OTIYUFZA.js → get-agent-UKZUBVPB.js} +4 -4
- package/dist/{get-analytics-IQZKJHLW.js → get-analytics-TI2U3JLA.js} +3 -3
- package/dist/{get-analytics-DCS72353.js → get-analytics-ZGQ4LY3I.js} +3 -3
- package/dist/get-analytics-report-PD6XZ4ZA.js +29 -0
- package/dist/get-analytics-report-QMXNQ7VA.js +30 -0
- package/dist/{get-dataset-ALSP7RTX.js → get-dataset-5QORNVOZ.js} +4 -4
- package/dist/{get-dataset-X4B5JDG2.js → get-dataset-E5WLIPNK.js} +4 -4
- package/dist/{get-evaluator-XEUZGZCH.js → get-evaluator-GYQFB4F3.js} +4 -4
- package/dist/{get-evaluator-ISMC4LLI.js → get-evaluator-QQV65MQB.js} +4 -4
- package/dist/{get-project-5VKROSDH.js → get-project-43SGQCAT.js} +4 -4
- package/dist/{get-project-RM6FRCBK.js → get-project-W5DCKXZP.js} +4 -4
- package/dist/{get-prompt-OWXJZHQQ.js → get-prompt-IUTPSRRI.js} +3 -3
- package/dist/{get-prompt-W52DY36E.js → get-prompt-ZTCWGYJV.js} +3 -3
- package/dist/{get-run-plan-BE3M2AUX.js → get-run-plan-M3LVXMGO.js} +4 -4
- package/dist/{get-run-plan-RUXQ6PAX.js → get-run-plan-MEPEU353.js} +4 -4
- package/dist/{get-scenario-RNM7BAX2.js → get-scenario-2DM4XR44.js} +4 -4
- package/dist/{get-scenario-YM4ODWW6.js → get-scenario-D6EPSSPW.js} +4 -4
- package/dist/{get-simulation-run-6GIATQE5.js → get-simulation-run-53WM2XOO.js} +4 -4
- package/dist/{get-simulation-run-LCFSMPGQ.js → get-simulation-run-RKQ52TKP.js} +4 -4
- package/dist/{get-test-suite-P5LJ6VLF.js → get-test-suite-DP2HNOQZ.js} +4 -4
- package/dist/{get-test-suite-GC2O7YH6.js → get-test-suite-MUSY2CDJ.js} +4 -4
- package/dist/{get-trace-SEF3FMR5.js → get-trace-5Z2BIZ3V.js} +3 -3
- package/dist/{get-trace-KBRVV4NN.js → get-trace-THPWSLD3.js} +3 -3
- package/dist/{get-workflow-YXULW4GC.js → get-workflow-63E7BNLY.js} +4 -4
- package/dist/{get-workflow-7PVED7JE.js → get-workflow-R6XUKTZ7.js} +4 -4
- package/dist/{http-server-IR4QOS43.js → http-server-4JHSQN56.js} +245 -45
- package/dist/index.js +1847 -899
- package/dist/langwatch-api-analytics-reports-IIHGTTQA.js +17 -0
- package/dist/langwatch-api-analytics-reports-IQ6CHM5Y.js +18 -0
- package/dist/{langwatch-api-annotations-TBHLCQ5R.js → langwatch-api-annotations-CN2KYV3Z.js} +4 -4
- package/dist/{langwatch-api-annotations-6SA4OB4C.js → langwatch-api-annotations-CRI6JTQR.js} +4 -4
- package/dist/{langwatch-api-monitors-CBF3FGIM.js → langwatch-api-monitors-66O5Z5LB.js} +3 -3
- package/dist/{langwatch-api-monitors-YNWA2M5Y.js → langwatch-api-monitors-GNHQRPMR.js} +3 -3
- package/dist/{langwatch-api-secrets-RNFO4LF2.js → langwatch-api-secrets-B7BURV76.js} +3 -3
- package/dist/{langwatch-api-secrets-ADTOJELP.js → langwatch-api-secrets-P6SHZOHE.js} +3 -3
- package/dist/{langwatch-api-triggers-KQDQC6L5.js → langwatch-api-triggers-6FR4VWDL.js} +4 -4
- package/dist/{langwatch-api-triggers-QS7HDIVW.js → langwatch-api-triggers-VKNGXSJH.js} +4 -4
- package/dist/langwatch-api-workflows-22RQFYO7.js +15 -0
- package/dist/{langwatch-api-workflows-OKC4FXIF.js → langwatch-api-workflows-KDACD36L.js} +4 -4
- package/dist/{list-agents-RBAOCF53.js → list-agents-SVXWLLO7.js} +4 -4
- package/dist/{list-agents-HVYWEQMI.js → list-agents-XM5JNCVK.js} +4 -4
- package/dist/list-analytics-reports-DEKKC6BU.js +32 -0
- package/dist/list-analytics-reports-E7QFC22G.js +33 -0
- package/dist/{list-annotations-J4UAHSUN.js → list-annotations-5CGNOIKI.js} +4 -4
- package/dist/{list-annotations-HJH4NBLD.js → list-annotations-P26ELIAO.js} +4 -4
- package/dist/{list-api-keys-A2PMV435.js → list-api-keys-B4YL7STE.js} +4 -4
- package/dist/{list-api-keys-7UTJRZDG.js → list-api-keys-ZIJJH755.js} +4 -4
- package/dist/list-dashboards-F4YJPDKD.js +29 -0
- package/dist/list-dashboards-XHYTXEQK.js +30 -0
- package/dist/{list-dataset-records-WFM7F33C.js → list-dataset-records-SWCEDRPX.js} +4 -4
- package/dist/{list-dataset-records-M5TKA6LK.js → list-dataset-records-YWGROVKC.js} +4 -4
- package/dist/{list-datasets-B5X4P7BQ.js → list-datasets-32SCF66H.js} +4 -4
- package/dist/{list-datasets-THUKQHPX.js → list-datasets-YYADWT4D.js} +4 -4
- package/dist/{list-evaluators-MYH2OVCI.js → list-evaluators-KKQKBJKN.js} +4 -4
- package/dist/{list-evaluators-NLVWF6K7.js → list-evaluators-V6LP6ZQA.js} +4 -4
- package/dist/{list-model-providers-3JUGP4YI.js → list-model-providers-RCPVT7R4.js} +4 -4
- package/dist/{list-model-providers-H3XKORFO.js → list-model-providers-TMBSB6EE.js} +4 -4
- package/dist/{list-projects-YNNSRMLC.js → list-projects-4Y74TFDZ.js} +4 -4
- package/dist/{list-projects-6EJ5YYEW.js → list-projects-R4MTRF3C.js} +4 -4
- package/dist/{list-prompt-tags-NVFQO6WX.js → list-prompt-tags-C345AGM2.js} +3 -3
- package/dist/{list-prompt-tags-XUQTTAH4.js → list-prompt-tags-RITKQDC5.js} +3 -3
- package/dist/{list-prompts-IRI6AIXO.js → list-prompts-DSJ2LUSU.js} +3 -3
- package/dist/{list-prompts-HSIMMHTF.js → list-prompts-F7C5L5XK.js} +3 -3
- package/dist/{list-run-plans-PX2XI6EK.js → list-run-plans-YPGLC5QG.js} +4 -4
- package/dist/{list-run-plans-QALLCN2K.js → list-run-plans-ZHRZHCDL.js} +4 -4
- package/dist/{list-scenarios-SSJQEMJP.js → list-scenarios-6HN72TMW.js} +4 -4
- package/dist/{list-scenarios-QZRPVHS4.js → list-scenarios-HCYFOTSL.js} +4 -4
- package/dist/{list-simulation-runs-OEADLLQR.js → list-simulation-runs-BKVMQQMT.js} +4 -4
- package/dist/{list-simulation-runs-KNOLGMDV.js → list-simulation-runs-JNST5PQU.js} +4 -4
- package/dist/{list-test-suites-N4WVLBKK.js → list-test-suites-4ZVYYKVB.js} +4 -4
- package/dist/{list-test-suites-ANAQBLDG.js → list-test-suites-YY4J3L7H.js} +4 -4
- package/dist/{list-trigger-fires-WTW4DVIW.js → list-trigger-fires-3XM6YZWG.js} +4 -4
- package/dist/{list-trigger-fires-JV3WFYYG.js → list-trigger-fires-5C5XM2KQ.js} +4 -4
- package/dist/{list-triggers-V4Y356AK.js → list-triggers-DARBIIRA.js} +4 -4
- package/dist/{list-triggers-SQNIG35Q.js → list-triggers-MRSWN7RR.js} +4 -4
- package/dist/{list-workflows-ZHTX5LCL.js → list-workflows-BGUSQUJX.js} +4 -4
- package/dist/{list-workflows-IMSX7SXU.js → list-workflows-NXOWP3XS.js} +4 -4
- package/dist/{rename-prompt-tag-IQI7MHOI.js → rename-prompt-tag-F3WT4FB4.js} +3 -3
- package/dist/{rename-prompt-tag-PA2BRIE6.js → rename-prompt-tag-HR5HZZI2.js} +3 -3
- package/dist/{rename-test-suite-NNVLMLKY.js → rename-test-suite-2ZRXG5O7.js} +4 -4
- package/dist/{rename-test-suite-4J7UX5S2.js → rename-test-suite-PWXKE7Z4.js} +4 -4
- package/dist/{report-issue-AS34ZMJF.js → report-issue-HG7XCPOY.js} +28 -2
- package/dist/{report-issue-DCZFLGDO.js → report-issue-TWRFUPGB.js} +28 -2
- package/dist/{rerun-run-plan-TG2V4WM4.js → rerun-run-plan-BFRZFEJB.js} +4 -4
- package/dist/{rerun-run-plan-ZI5OY3VA.js → rerun-run-plan-LXM3RFZC.js} +4 -4
- package/dist/{revoke-api-key-3J3ZA4UB.js → revoke-api-key-GR55PUP4.js} +4 -4
- package/dist/{revoke-api-key-SFMEFWJC.js → revoke-api-key-KCDOYPUK.js} +4 -4
- package/dist/{run-agent-YNV6ZHW4.js → run-agent-HRVRHRHI.js} +4 -4
- package/dist/{run-agent-W4VJP72Z.js → run-agent-WS6TADJQ.js} +4 -4
- package/dist/{run-plan-6C77GWG4.js → run-plan-G24DBB5D.js} +4 -4
- package/dist/{run-plan-PAARQSI4.js → run-plan-NSXMBEC5.js} +4 -4
- package/dist/{run-query-T4QW2Z5O.js → run-query-6YVOA5NV.js} +19 -5
- package/dist/{run-query-KJDH544C.js → run-query-7QIYSDVI.js} +19 -5
- package/dist/{run-test-suite-STB6NUJM.js → run-test-suite-NTKLJZCJ.js} +4 -4
- package/dist/{run-test-suite-SQJELEZX.js → run-test-suite-P33XFQ6H.js} +4 -4
- package/dist/{run-workflow-D6PQNBI6.js → run-workflow-E5ZRSXUB.js} +4 -4
- package/dist/{run-workflow-SP32SO5M.js → run-workflow-HDF6CRLM.js} +4 -4
- package/dist/{search-traces-HCBGOG6R.js → search-traces-X7NSRTTP.js} +3 -3
- package/dist/{search-traces-HSTQ6WTQ.js → search-traces-XWZYOZOM.js} +3 -3
- package/dist/{set-model-provider-GF7NXUJA.js → set-model-provider-XJF47L6H.js} +4 -4
- package/dist/{set-model-provider-KDQ7C4EZ.js → set-model-provider-YPUCFEXG.js} +4 -4
- package/dist/{update-agent-MXNOBS4H.js → update-agent-6FHGWOO7.js} +4 -4
- package/dist/{update-agent-DWG43T2P.js → update-agent-VEDXQRSM.js} +4 -4
- package/dist/update-dashboard-widget-VOKXN7JA.js +64 -0
- package/dist/update-dashboard-widget-VUIQZ7F5.js +63 -0
- package/dist/{update-dataset-SQZ6T4WX.js → update-dataset-7AQ24NRS.js} +4 -4
- package/dist/{update-dataset-DQH3OHOU.js → update-dataset-GHKDCJJQ.js} +4 -4
- package/dist/{update-dataset-record-3AT4IPBC.js → update-dataset-record-IRD6FH2C.js} +4 -4
- package/dist/{update-dataset-record-7PLDGTMR.js → update-dataset-record-ZZUPG7AS.js} +4 -4
- package/dist/{update-evaluator-4LFTKFPT.js → update-evaluator-O6EJFTQJ.js} +4 -4
- package/dist/{update-evaluator-IGTX6PX4.js → update-evaluator-PUJFU5LT.js} +4 -4
- package/dist/{update-project-PLJIOZS6.js → update-project-HO53IHXC.js} +4 -4
- package/dist/{update-project-QVHSJRUP.js → update-project-VTVU6KNP.js} +4 -4
- package/dist/{update-prompt-GDKRYJI3.js → update-prompt-FABVQCAC.js} +3 -3
- package/dist/{update-prompt-MY263DYF.js → update-prompt-MNRLCLBA.js} +3 -3
- package/dist/{update-scenario-MOHRQKAQ.js → update-scenario-MQZZM5CP.js} +4 -4
- package/dist/{update-scenario-7KA3JDXA.js → update-scenario-XIZNUH4I.js} +4 -4
- package/package.json +2 -2
- package/pyproject.toml +17 -2
- package/src/config.d.ts +2 -0
- package/src/config.ts +2 -0
- package/src/create-mcp-server.ts +165 -41
- package/src/langwatch-api-analytics-reports.ts +62 -0
- package/src/langwatch-api-dashboard-widgets.ts +4 -68
- package/src/langwatch-api-dashboards.ts +110 -28
- package/src/langwatch-api-projects.ts +0 -17
- package/src/langwatch-api-query.ts +6 -0
- package/src/langwatch-api.ts +60 -27
- package/src/schemas/widget-sources.ts +69 -0
- package/src/tools/add-dashboard-widget.ts +23 -32
- package/src/tools/create-analytics-report.ts +7 -0
- package/src/tools/dashboard-widget-queries.ts +22 -0
- package/src/tools/dashboards.ts +104 -0
- package/src/tools/delete-analytics-report.ts +7 -0
- package/src/tools/get-analytics-report.ts +23 -0
- package/src/tools/list-analytics-reports.ts +27 -0
- package/src/tools/list-dashboards.ts +20 -21
- package/src/tools/report-issue.ts +2 -0
- package/src/tools/run-experiment.ts +5 -1
- package/src/tools/run-query.ts +23 -1
- package/src/tools/update-dashboard-widget.ts +32 -40
- package/uv.lock +667 -341
- package/dist/add-dashboard-widget-4ZC5UN73.js +0 -50
- package/dist/add-dashboard-widget-ACC6QYBG.js +0 -49
- package/dist/chunk-5FNCQRCX.js +0 -91
- package/dist/chunk-ILZDO25L.js +0 -36
- package/dist/chunk-K2I7Z3LZ.js +0 -28
- package/dist/create-dashboard-DHVFMEU4.js +0 -18
- package/dist/create-dashboard-WTKKS5Z6.js +0 -19
- package/dist/delete-dashboard-76N66XXL.js +0 -18
- package/dist/delete-dashboard-JVIVHNJM.js +0 -19
- package/dist/get-dashboard-5NYJEIX2.js +0 -29
- package/dist/get-dashboard-QMTYDQAZ.js +0 -30
- package/dist/langwatch-api-dashboards-6EO2VVZW.js +0 -17
- package/dist/langwatch-api-dashboards-NHU5BZD7.js +0 -18
- package/dist/langwatch-api-workflows-XGJE6SR5.js +0 -15
- package/dist/list-dashboard-boards-OPWROHMG.js +0 -33
- package/dist/list-dashboard-boards-U2GJ7GC5.js +0 -34
- package/dist/list-dashboards-ROSYFLDQ.js +0 -33
- package/dist/list-dashboards-RQ635ZU7.js +0 -32
- package/dist/update-dashboard-widget-CJKJLCDY.js +0 -71
- package/dist/update-dashboard-widget-CYQDS2NR.js +0 -70
- package/src/langwatch-api-boards.ts +0 -46
- package/src/tools/create-dashboard.ts +0 -7
- package/src/tools/dashboard-exists.ts +0 -25
- package/src/tools/delete-dashboard.ts +0 -7
- package/src/tools/get-dashboard.ts +0 -22
- package/src/tools/list-dashboard-boards.ts +0 -28
|
@@ -1,51 +1,133 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type {
|
|
2
|
+
DashboardWidget,
|
|
3
|
+
DashboardWidgetQueryInput,
|
|
4
|
+
} from "./langwatch-api-dashboard-widgets.js";
|
|
5
|
+
import { makeRequest } from "./langwatch-api.js";
|
|
2
6
|
|
|
3
|
-
|
|
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
|
-
|
|
7
|
-
|
|
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
|
|
13
|
-
|
|
23
|
+
export interface DashboardListItem extends Dashboard {
|
|
24
|
+
widgetCount: number;
|
|
14
25
|
}
|
|
15
26
|
|
|
16
|
-
|
|
17
|
-
|
|
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
|
-
|
|
21
|
-
|
|
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
|
|
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
|
-
"
|
|
27
|
-
|
|
28
|
-
|
|
89
|
+
"POST",
|
|
90
|
+
`${dashboardPath(dashboardId)}/widgets`,
|
|
91
|
+
data,
|
|
92
|
+
) as Promise<DashboardWidget>;
|
|
29
93
|
}
|
|
30
94
|
|
|
31
|
-
|
|
32
|
-
|
|
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
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
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
|
-
|
|
42
|
-
|
|
43
|
-
) as Promise<
|
|
120
|
+
widgetPath(dashboardId, widgetId),
|
|
121
|
+
changes,
|
|
122
|
+
) as Promise<DashboardWidget>;
|
|
44
123
|
}
|
|
45
124
|
|
|
46
|
-
export async function
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
|
package/src/langwatch-api.ts
CHANGED
|
@@ -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(
|
|
215
|
-
? (
|
|
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
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
9
|
-
|
|
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 =
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
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
|
|
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
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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
|
+
}
|