@langwatch/mcp-server 2.1.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.
- package/.gitignore +7 -0
- package/.npmignore +41 -0
- package/CHANGELOG.md +192 -201
- package/CONTRIBUTING.md +10 -0
- package/README.md +70 -68
- package/dist/add-dashboard-widget-4ZC5UN73.js +50 -0
- package/dist/add-dashboard-widget-ACC6QYBG.js +49 -0
- package/dist/archive-project-KWFM3I5Z.js +19 -0
- package/dist/{archive-project-W3IKI7UL.js → archive-project-SPVHXK6A.js} +4 -4
- package/dist/{archive-run-plan-474OKHHU.js → archive-run-plan-65QN3XRX.js} +4 -4
- package/dist/archive-run-plan-Z4SYE6BP.js +15 -0
- package/dist/{archive-scenario-V5UNYK26.js → archive-scenario-A6QV5LOW.js} +4 -4
- package/dist/archive-scenario-FXEYQNEH.js +19 -0
- package/dist/archive-test-suite-5ADQ3KPQ.js +15 -0
- package/dist/{archive-test-suite-O7FLDMXK.js → archive-test-suite-NKZDZY3D.js} +4 -4
- package/dist/assign-prompt-tag-5IUZXJ2T.js +23 -0
- package/dist/{assign-prompt-tag-Q46WRB6P.js → assign-prompt-tag-HBZLBIFD.js} +8 -4
- package/dist/{chunk-OJLYYJWI.js → chunk-3OCG3QPU.js} +7 -10
- package/dist/chunk-3YLN3ATJ.js +241 -0
- package/dist/chunk-5FNCQRCX.js +91 -0
- package/dist/{chunk-UF6XIGYR.js → chunk-6YZUOD34.js} +2 -5
- package/dist/{chunk-WVI5CJ6S.js → chunk-7AQLPVFL.js} +2 -2
- package/dist/chunk-7VNSRCXO.js +129 -0
- package/dist/{chunk-G4ZAZTZW.js → chunk-B4J3PJLX.js} +11 -10
- package/dist/{chunk-ZXKLPC2E.js → chunk-BIIKE3EI.js} +1 -1
- package/dist/{chunk-37SMPMQS.js → chunk-DMM3JQ42.js} +7 -2
- package/dist/{chunk-NUFPTHKU.js → chunk-FOKVY3BK.js} +1 -1
- package/dist/{chunk-WT4PO4A3.js → chunk-H6WGMG2T.js} +10 -7
- package/dist/{chunk-EYXMLE5X.js → chunk-HGELNIVY.js} +56 -47
- package/dist/{chunk-UJPXFA26.js → chunk-HHMNZAPD.js} +101 -74
- package/dist/{chunk-RVAE2MEA.js → chunk-I7ATIZED.js} +7 -7
- package/dist/{chunk-S4GVX36W.js → chunk-ILZDO25L.js} +7 -10
- package/dist/{chunk-QRO35SOM.js → chunk-J7PQKBLD.js} +652 -528
- package/dist/{chunk-SR6QPRIE.js → chunk-JRJPH75H.js} +7 -13
- package/dist/chunk-K2I7Z3LZ.js +28 -0
- package/dist/{chunk-UFOYFYI7.js → chunk-NKMTIHIJ.js} +6 -9
- package/dist/{chunk-HV4DWKBI.js → chunk-O7EMWEVJ.js} +2 -4
- package/dist/{chunk-56OGTS24.js → chunk-PTDR56Z3.js} +4 -11
- package/dist/{chunk-JR6DJZOU.js → chunk-RABYBFX5.js} +4 -10
- package/dist/chunk-SUPUUC4W.js +64 -0
- package/dist/{chunk-JTQJRNFJ.js → chunk-SXFC3FNH.js} +4 -4
- package/dist/{chunk-CKNAH5TG.js → chunk-U24EACC4.js} +3 -10
- package/dist/chunk-UNJM3BIL.js +21 -0
- package/dist/{chunk-QAMP3CGR.js → chunk-UTJCWXPZ.js} +4 -4
- package/dist/chunk-UWLE5T2F.js +312 -0
- package/dist/{chunk-6DJDEXET.js → chunk-VMWJD732.js} +6 -12
- package/dist/{chunk-7E4FZIYJ.js → chunk-XUIJYNRJ.js} +1 -1
- package/dist/chunk-Y34DHR5K.js +67 -0
- package/dist/chunk-YCARO42Z.js +516 -0
- package/dist/config-EAKW6F26.js +16 -0
- package/dist/config.cjs +109 -0
- package/dist/config.js +5 -4
- package/dist/{create-agent-JFJ2K6X3.js → create-agent-AYZ3LB3V.js} +4 -4
- package/dist/create-agent-S5ZBCEFT.js +23 -0
- package/dist/create-annotation-LHNCLHYP.js +29 -0
- package/dist/{create-annotation-EUXXQ6NS.js → create-annotation-VUSXULQK.js} +10 -5
- package/dist/{create-api-key-BGBB76JX.js → create-api-key-NNYKARMG.js} +5 -7
- package/dist/create-api-key-T4KSNPKB.js +24 -0
- package/dist/create-dashboard-DHVFMEU4.js +18 -0
- package/dist/{create-dashboard-Z76AIPLS.js → create-dashboard-WTKKS5Z6.js} +4 -4
- package/dist/{create-dataset-FD5VAXU4.js → create-dataset-2MC4SD4O.js} +6 -6
- package/dist/create-dataset-LUP5PVDM.js +22 -0
- package/dist/create-dataset-records-NSKBZP3G.js +20 -0
- package/dist/{create-dataset-records-WQUXXOHI.js → create-dataset-records-W4GLN2FV.js} +5 -7
- package/dist/{create-evaluator-6NV33Z52.js → create-evaluator-643G6LXL.js} +4 -4
- package/dist/create-evaluator-HMTYO5SS.js +27 -0
- package/dist/create-mcp-server.cjs +9513 -0
- package/dist/create-mcp-server.js +2647 -10
- package/dist/create-project-6N7PIYRY.js +44 -0
- package/dist/{create-project-ZQ7TFIO2.js → create-project-KAIC46UY.js} +4 -4
- package/dist/{create-prompt-BS6QRCUU.js → create-prompt-E67LXIYT.js} +5 -7
- package/dist/create-prompt-PKJ7EDRR.js +37 -0
- package/dist/create-prompt-tag-4YO3FSJ3.js +17 -0
- package/dist/{create-prompt-tag-FCQ5ELSQ.js → create-prompt-tag-OPQUEXWB.js} +3 -3
- package/dist/create-scenario-5PJBMAXO.js +33 -0
- package/dist/{create-scenario-DRPTPXU3.js → create-scenario-UEM77OE7.js} +5 -5
- package/dist/{create-test-suite-ZIZCCFJ4.js → create-test-suite-4IPXVSFQ.js} +6 -6
- package/dist/create-test-suite-SZEPVXSE.js +36 -0
- package/dist/create-trigger-5HZSCRAN.js +49 -0
- package/dist/create-trigger-PRELMT6J.js +48 -0
- package/dist/delete-agent-JUIZWAXG.js +18 -0
- package/dist/{delete-agent-SA4JMUZF.js → delete-agent-QMEK3XHK.js} +4 -4
- package/dist/delete-annotation-HY3O2OGR.js +17 -0
- package/dist/{delete-annotation-X3KKK7QY.js → delete-annotation-VKIQWUYW.js} +4 -4
- package/dist/delete-dashboard-76N66XXL.js +18 -0
- package/dist/{delete-dashboard-LYMRPF27.js → delete-dashboard-JVIVHNJM.js} +4 -4
- package/dist/delete-dataset-HQCR66MG.js +18 -0
- package/dist/{delete-dataset-W6EZ44HY.js → delete-dataset-WKRUW4FP.js} +5 -7
- package/dist/{delete-dataset-records-7CNOTALB.js → delete-dataset-records-C2IQFFVQ.js} +5 -7
- package/dist/delete-dataset-records-SDUHQLLM.js +19 -0
- package/dist/delete-evaluator-4SNSCLEE.js +16 -0
- package/dist/delete-evaluator-QP3QHTLN.js +15 -0
- package/dist/delete-prompt-tag-NZ4JQMYG.js +17 -0
- package/dist/{delete-prompt-tag-QB3OCZUV.js → delete-prompt-tag-YYQ4VMAD.js} +3 -3
- package/dist/{delete-workflow-NG2VXYYM.js → delete-workflow-5J46T73T.js} +4 -4
- package/dist/delete-workflow-JSWABL5F.js +17 -0
- package/dist/discover-evaluator-schema-UHWA5HVL.js +120 -0
- package/dist/discover-evaluator-schema-XKCLLCB3.js +118 -0
- package/dist/discover-scenario-schema-NOJY6S7E.js +137 -0
- package/dist/{discover-scenario-schema-W7KBXA4J.js → discover-scenario-schema-OOFIQKOG.js} +37 -17
- package/dist/{discover-schema-L6QDPON3.js → discover-schema-55YJBFGQ.js} +181 -186
- package/dist/discover-schema-A33SLMXW.js +442 -0
- package/dist/get-agent-LJQX7OF4.js +69 -0
- package/dist/{get-agent-7THF7HCU.js → get-agent-OTIYUFZA.js} +15 -11
- package/dist/get-analytics-DCS72353.js +80 -0
- package/dist/get-analytics-IQZKJHLW.js +79 -0
- package/dist/get-dashboard-5NYJEIX2.js +29 -0
- package/dist/{get-dashboard-P4WWVHFU.js → get-dashboard-QMTYDQAZ.js} +4 -4
- package/dist/get-dataset-ALSP7RTX.js +64 -0
- package/dist/get-dataset-X4B5JDG2.js +63 -0
- package/dist/{get-evaluator-RZ44UIN6.js → get-evaluator-ISMC4LLI.js} +4 -4
- package/dist/get-evaluator-XEUZGZCH.js +47 -0
- package/dist/{get-project-QSQEAB33.js → get-project-5VKROSDH.js} +4 -4
- package/dist/get-project-RM6FRCBK.js +26 -0
- package/dist/{get-prompt-GVKXF5NL.js → get-prompt-OWXJZHQQ.js} +53 -58
- package/dist/get-prompt-W52DY36E.js +94 -0
- package/dist/{get-run-plan-NY7J5GRE.js → get-run-plan-BE3M2AUX.js} +7 -9
- package/dist/get-run-plan-RUXQ6PAX.js +58 -0
- package/dist/get-scenario-RNM7BAX2.js +37 -0
- package/dist/{get-scenario-Q3LLQE4T.js → get-scenario-YM4ODWW6.js} +5 -5
- package/dist/get-simulation-run-6GIATQE5.js +69 -0
- package/dist/{get-simulation-run-WINEYDMK.js → get-simulation-run-LCFSMPGQ.js} +26 -22
- package/dist/{get-test-suite-4HKA7OKS.js → get-test-suite-GC2O7YH6.js} +5 -5
- package/dist/get-test-suite-P5LJ6VLF.js +48 -0
- package/dist/get-trace-KBRVV4NN.js +45 -0
- package/dist/{get-trace-RCUV7N4O.js → get-trace-SEF3FMR5.js} +11 -13
- package/dist/get-workflow-7PVED7JE.js +25 -0
- package/dist/{get-workflow-EEOC7Y45.js → get-workflow-YXULW4GC.js} +4 -4
- package/dist/{http-security-EU3CHTY7.js → http-security-DNLBNQZL.js} +2 -2
- package/dist/{http-server-WCDUARTH.js → http-server-IR4QOS43.js} +4071 -347
- package/dist/index.js +58671 -37983
- package/dist/langwatch-api-annotations-6SA4OB4C.js +17 -0
- package/dist/{langwatch-api-annotations-6DHVZWUK.js → langwatch-api-annotations-TBHLCQ5R.js} +4 -4
- package/dist/langwatch-api-dashboards-6EO2VVZW.js +17 -0
- package/dist/{langwatch-api-dashboards-2KJL2M42.js → langwatch-api-dashboards-NHU5BZD7.js} +4 -4
- package/dist/langwatch-api-monitors-CBF3FGIM.js +47 -0
- package/dist/{langwatch-api-monitors-6ISFJ7WX.js → langwatch-api-monitors-YNWA2M5Y.js} +11 -16
- package/dist/langwatch-api-secrets-ADTOJELP.js +56 -0
- package/dist/langwatch-api-secrets-RNFO4LF2.js +55 -0
- package/dist/langwatch-api-triggers-KQDQC6L5.js +22 -0
- package/dist/langwatch-api-triggers-QS7HDIVW.js +23 -0
- package/dist/{langwatch-api-workflows-6UJL5U4Z.js → langwatch-api-workflows-OKC4FXIF.js} +4 -4
- package/dist/langwatch-api-workflows-XGJE6SR5.js +15 -0
- package/dist/{list-agents-AMVDQPQL.js → list-agents-HVYWEQMI.js} +4 -4
- package/dist/list-agents-RBAOCF53.js +42 -0
- package/dist/list-annotations-HJH4NBLD.js +38 -0
- package/dist/{list-annotations-6PR5NLIC.js → list-annotations-J4UAHSUN.js} +10 -5
- package/dist/{list-api-keys-GVPNBIHQ.js → list-api-keys-7UTJRZDG.js} +10 -5
- package/dist/list-api-keys-A2PMV435.js +42 -0
- package/dist/list-dashboard-boards-OPWROHMG.js +33 -0
- package/dist/list-dashboard-boards-U2GJ7GC5.js +34 -0
- package/dist/{list-dashboards-Z3BZKDGF.js → list-dashboards-ROSYFLDQ.js} +4 -4
- package/dist/list-dashboards-RQ635ZU7.js +32 -0
- package/dist/{list-dataset-records-O67HZ35Y.js → list-dataset-records-M5TKA6LK.js} +14 -10
- package/dist/list-dataset-records-WFM7F33C.js +43 -0
- package/dist/{list-datasets-WXZL6UMP.js → list-datasets-B5X4P7BQ.js} +9 -13
- package/dist/list-datasets-THUKQHPX.js +56 -0
- package/dist/{list-evaluators-PAX72WCN.js → list-evaluators-MYH2OVCI.js} +5 -7
- package/dist/list-evaluators-NLVWF6K7.js +32 -0
- package/dist/{list-model-providers-VVLZMLCX.js → list-model-providers-3JUGP4YI.js} +4 -4
- package/dist/list-model-providers-H3XKORFO.js +35 -0
- package/dist/{list-projects-AQVI6SUK.js → list-projects-6EJ5YYEW.js} +5 -7
- package/dist/list-projects-YNNSRMLC.js +40 -0
- package/dist/{list-prompt-tags-WZFBJOHG.js → list-prompt-tags-NVFQO6WX.js} +3 -3
- package/dist/list-prompt-tags-XUQTTAH4.js +23 -0
- package/dist/{list-prompts-BQOHRHYT.js → list-prompts-HSIMMHTF.js} +4 -6
- package/dist/list-prompts-IRI6AIXO.js +30 -0
- package/dist/{list-run-plans-UBAU2DGH.js → list-run-plans-PX2XI6EK.js} +5 -5
- package/dist/list-run-plans-QALLCN2K.js +45 -0
- package/dist/{list-scenarios-MS4IUIVM.js → list-scenarios-QZRPVHS4.js} +13 -11
- package/dist/list-scenarios-SSJQEMJP.js +45 -0
- package/dist/list-simulation-runs-KNOLGMDV.js +53 -0
- package/dist/{list-simulation-runs-D6YF4ZOU.js → list-simulation-runs-OEADLLQR.js} +12 -8
- package/dist/list-test-suites-ANAQBLDG.js +34 -0
- package/dist/{list-test-suites-L7R2O6DR.js → list-test-suites-N4WVLBKK.js} +4 -4
- package/dist/list-trigger-fires-JV3WFYYG.js +19 -0
- package/dist/list-trigger-fires-WTW4DVIW.js +20 -0
- package/dist/list-triggers-SQNIG35Q.js +45 -0
- package/dist/list-triggers-V4Y356AK.js +46 -0
- package/dist/{list-workflows-6MV4XJHF.js → list-workflows-IMSX7SXU.js} +5 -7
- package/dist/list-workflows-ZHTX5LCL.js +33 -0
- package/dist/{rename-prompt-tag-K5LQ4CY6.js → rename-prompt-tag-IQI7MHOI.js} +3 -3
- package/dist/rename-prompt-tag-PA2BRIE6.js +18 -0
- package/dist/{rename-test-suite-NTYHAO5X.js → rename-test-suite-4J7UX5S2.js} +4 -4
- package/dist/rename-test-suite-NNVLMLKY.js +20 -0
- package/dist/report-issue-AS34ZMJF.js +898 -0
- package/dist/{report-issue-RHZZ33IS.js → report-issue-DCZFLGDO.js} +81 -67
- package/dist/{rerun-run-plan-MUDWJBE4.js → rerun-run-plan-TG2V4WM4.js} +5 -5
- package/dist/rerun-run-plan-ZI5OY3VA.js +21 -0
- package/dist/revoke-api-key-3J3ZA4UB.js +15 -0
- package/dist/{revoke-api-key-6LAZ3QZZ.js → revoke-api-key-SFMEFWJC.js} +4 -4
- package/dist/run-agent-W4VJP72Z.js +75 -0
- package/dist/run-agent-YNV6ZHW4.js +74 -0
- package/dist/run-plan-6C77GWG4.js +38 -0
- package/dist/{run-plan-T4ZYOZGA.js → run-plan-PAARQSI4.js} +7 -7
- package/dist/run-query-KJDH544C.js +47 -0
- package/dist/run-query-T4QW2Z5O.js +46 -0
- package/dist/{run-test-suite-L4MZ7G4D.js → run-test-suite-SQJELEZX.js} +6 -6
- package/dist/run-test-suite-STB6NUJM.js +25 -0
- package/dist/{run-workflow-DFIS23AP.js → run-workflow-D6PQNBI6.js} +4 -4
- package/dist/run-workflow-SP32SO5M.js +36 -0
- package/dist/search-traces-HCBGOG6R.js +170 -0
- package/dist/search-traces-HSTQ6WTQ.js +171 -0
- package/dist/{set-model-provider-XRNMFOVR.js → set-model-provider-GF7NXUJA.js} +4 -4
- package/dist/set-model-provider-KDQ7C4EZ.js +33 -0
- package/dist/{update-agent-DUWNYBNA.js → update-agent-DWG43T2P.js} +4 -4
- package/dist/update-agent-MXNOBS4H.js +20 -0
- package/dist/update-dashboard-widget-CJKJLCDY.js +71 -0
- package/dist/update-dashboard-widget-CYQDS2NR.js +70 -0
- package/dist/update-dataset-DQH3OHOU.js +22 -0
- package/dist/{update-dataset-YSOMDCOB.js → update-dataset-SQZ6T4WX.js} +6 -6
- package/dist/{update-dataset-record-DEA2ITYR.js → update-dataset-record-3AT4IPBC.js} +4 -4
- package/dist/update-dataset-record-7PLDGTMR.js +19 -0
- package/dist/update-evaluator-4LFTKFPT.js +24 -0
- package/dist/{update-evaluator-NH7Q5GWV.js → update-evaluator-IGTX6PX4.js} +4 -4
- package/dist/{update-project-Q26FBSYH.js → update-project-PLJIOZS6.js} +4 -4
- package/dist/update-project-QVHSJRUP.js +24 -0
- package/dist/update-prompt-GDKRYJI3.js +140 -0
- package/dist/{update-prompt-ZQQ2C3KU.js → update-prompt-MY263DYF.js} +27 -29
- package/dist/update-scenario-7KA3JDXA.js +34 -0
- package/dist/{update-scenario-WUX34JAR.js → update-scenario-MOHRQKAQ.js} +5 -5
- package/package.json +35 -39
- package/pyproject.toml +8 -8
- package/src/config.d.ts +4 -0
- package/src/config.ts +20 -29
- package/src/create-mcp-server.ts +755 -609
- package/src/documentation-fetch.ts +21 -20
- package/src/http-security.ts +166 -135
- package/src/http-server.ts +189 -224
- package/src/index.ts +14 -16
- package/src/langwatch-api-agents.ts +18 -21
- package/src/langwatch-api-annotations.ts +11 -12
- package/src/langwatch-api-api-keys.ts +8 -9
- package/src/langwatch-api-boards.ts +46 -0
- package/src/langwatch-api-dashboard-widgets.ts +112 -0
- package/src/langwatch-api-dashboards.ts +13 -10
- package/src/langwatch-api-datasets.ts +98 -32
- package/src/langwatch-api-evaluators.ts +13 -19
- package/src/langwatch-api-model-providers.ts +4 -4
- package/src/langwatch-api-monitors.ts +14 -18
- package/src/langwatch-api-projects.ts +27 -9
- package/src/langwatch-api-query.ts +114 -0
- package/src/langwatch-api-run-plans.ts +12 -29
- package/src/langwatch-api-scenarios.ts +9 -11
- package/src/langwatch-api-secrets.ts +31 -24
- package/src/langwatch-api-simulation-runs.ts +6 -8
- package/src/langwatch-api-test-suites.ts +14 -33
- package/src/langwatch-api-triggers.ts +96 -34
- package/src/langwatch-api-workflows.ts +9 -9
- package/src/langwatch-api.ts +108 -124
- package/src/public-http-request.ts +21 -12
- package/src/schemas/analytics-metrics.ts +3 -15
- package/src/schemas/create-dataset.ts +3 -4
- package/src/schemas/run-plan.ts +13 -29
- package/src/schemas/suite-fields.ts +6 -23
- package/src/schemas/triggers.ts +365 -0
- package/src/tools/add-dashboard-widget.ts +63 -0
- package/src/tools/archive-project.ts +2 -4
- package/src/tools/archive-run-plan.ts +2 -4
- package/src/tools/archive-scenario.ts +2 -4
- package/src/tools/archive-test-suite.ts +2 -4
- package/src/tools/assign-prompt-tag.ts +6 -2
- package/src/tools/create-agent.ts +1 -1
- package/src/tools/create-annotation.ts +7 -2
- package/src/tools/create-api-key.ts +4 -6
- package/src/tools/create-dashboard.ts +1 -1
- package/src/tools/create-dataset-records.ts +4 -8
- package/src/tools/create-dataset.ts +5 -7
- package/src/tools/create-evaluator.ts +3 -5
- package/src/tools/create-project.ts +2 -2
- package/src/tools/create-prompt-tag.ts +2 -4
- package/src/tools/create-prompt.ts +9 -18
- package/src/tools/create-scenario.ts +5 -7
- package/src/tools/create-test-suite.ts +4 -9
- package/src/tools/create-trigger.ts +55 -0
- package/src/tools/dashboard-exists.ts +25 -0
- package/src/tools/dashboard-widget-queries.ts +32 -0
- package/src/tools/delete-agent.ts +1 -1
- package/src/tools/delete-annotation.ts +1 -1
- package/src/tools/delete-dashboard.ts +1 -1
- package/src/tools/delete-dataset-records.ts +4 -8
- package/src/tools/delete-dataset.ts +3 -7
- package/src/tools/delete-evaluator.ts +4 -6
- package/src/tools/delete-prompt-tag.ts +2 -4
- package/src/tools/delete-workflow.ts +1 -1
- package/src/tools/discover-evaluator-schema.ts +34 -25
- package/src/tools/discover-scenario-schema.ts +41 -21
- package/src/tools/discover-schema.ts +149 -27
- package/src/tools/experiment-run-status.ts +2 -8
- package/src/tools/format-dataset-mutation.ts +5 -10
- package/src/tools/format-run-plan.ts +7 -21
- package/src/tools/format-scenario.ts +2 -4
- package/src/tools/format-suite-details.ts +6 -12
- package/src/tools/get-agent.ts +15 -6
- package/src/tools/get-analytics.ts +52 -46
- package/src/tools/get-dashboard.ts +1 -1
- package/src/tools/get-dataset.ts +34 -16
- package/src/tools/get-evaluator.ts +4 -11
- package/src/tools/get-experiment-results.ts +219 -186
- package/src/tools/get-project.ts +2 -4
- package/src/tools/get-prompt.ts +63 -84
- package/src/tools/get-run-plan.ts +4 -6
- package/src/tools/get-scenario.ts +4 -6
- package/src/tools/get-simulation-run.ts +27 -24
- package/src/tools/get-test-suite.ts +2 -5
- package/src/tools/get-trace.ts +16 -17
- package/src/tools/get-workflow.ts +1 -1
- package/src/tools/list-agents.ts +1 -1
- package/src/tools/list-annotations.ts +8 -5
- package/src/tools/list-api-keys.ts +7 -2
- package/src/tools/list-dashboard-boards.ts +28 -0
- package/src/tools/list-dashboards.ts +1 -1
- package/src/tools/list-dataset-records.ts +8 -6
- package/src/tools/list-datasets.ts +12 -23
- package/src/tools/list-evaluators.ts +4 -8
- package/src/tools/list-experiment-runs.ts +5 -9
- package/src/tools/list-experiments.ts +5 -11
- package/src/tools/list-model-providers.ts +3 -5
- package/src/tools/list-projects.ts +2 -4
- package/src/tools/list-prompt-tags.ts +3 -3
- package/src/tools/list-prompts.ts +4 -8
- package/src/tools/list-run-plans.ts +2 -2
- package/src/tools/list-scenarios.ts +14 -15
- package/src/tools/list-simulation-runs.ts +8 -4
- package/src/tools/list-test-suites.ts +1 -1
- package/src/tools/list-trigger-fires.ts +17 -0
- package/src/tools/list-triggers.ts +39 -0
- package/src/tools/list-workflows.ts +2 -4
- package/src/tools/rename-prompt-tag.ts +1 -1
- package/src/tools/rename-test-suite.ts +2 -5
- package/src/tools/report-issue.ts +5 -9
- package/src/tools/rerun-run-plan.ts +2 -5
- package/src/tools/revoke-api-key.ts +2 -4
- package/src/tools/run-agent.ts +29 -26
- package/src/tools/run-experiment.ts +36 -37
- package/src/tools/run-plan.ts +4 -7
- package/src/tools/run-query.ts +47 -0
- package/src/tools/run-test-suite.ts +4 -7
- package/src/tools/run-workflow.ts +2 -5
- package/src/tools/search-traces.ts +161 -47
- package/src/tools/set-model-provider.ts +4 -6
- package/src/tools/test-agent.ts +2 -2
- package/src/tools/update-agent.ts +1 -1
- package/src/tools/update-dashboard-widget.ts +97 -0
- package/src/tools/update-dataset-record.ts +1 -1
- package/src/tools/update-dataset.ts +5 -7
- package/src/tools/update-evaluator.ts +3 -5
- package/src/tools/update-project.ts +1 -1
- package/src/tools/update-prompt.ts +44 -59
- package/src/tools/update-scenario.ts +5 -7
- package/src/tools/update-test-suite.ts +6 -11
- package/src/utils/date-parsing.ts +1 -1
- package/src/utils/escape-markdown.ts +3 -8
- package/src/utils/format-evaluations.ts +6 -6
- package/src/utils/markdown-table.ts +58 -0
- package/src/utils/trace-id-shape.ts +20 -0
- package/tsconfig.app.json +24 -0
- package/tsconfig.json +14 -12
- package/vitest.integration.config.js +10 -0
- package/vitest.scenario.config.js +9 -0
- package/.eslintrc.cjs +0 -36
- package/dist/chunk-AN4OUA4D.js +0 -86
- package/dist/chunk-GELJ2MQR.js +0 -226
- package/dist/chunk-K37ZNPXK.js +0 -24
- package/dist/config.d.ts +0 -17
- package/dist/create-mcp-server.d.ts +0 -10
- package/dist/delete-evaluator-RKYC4TNB.js +0 -16
- package/dist/discover-evaluator-schema-ESSHQGPY.js +0 -1912
- package/dist/get-analytics-R6AZD3AW.js +0 -73
- package/dist/get-dataset-AKTYSQDI.js +0 -49
- package/dist/index.d.ts +0 -2
- package/dist/langwatch-api-secrets-OEBD6GBU.js +0 -41
- package/dist/langwatch-api-triggers-5E6DDGX6.js +0 -31
- package/dist/run-agent-CAGWGTYT.js +0 -72
- package/dist/search-traces-4XTJYXIK.js +0 -79
- package/src/__tests__/agent-tools.unit.test.ts +0 -257
- package/src/__tests__/all-tools.integration.test.ts +0 -1872
- package/src/__tests__/config.unit.test.ts +0 -202
- package/src/__tests__/datasets.integration.test.ts +0 -620
- package/src/__tests__/datasets.unit.test.ts +0 -244
- package/src/__tests__/date-parsing.unit.test.ts +0 -78
- package/src/__tests__/discover-evaluator-schema.unit.test.ts +0 -89
- package/src/__tests__/discover-schema.unit.test.ts +0 -118
- package/src/__tests__/docker.integration.test.ts +0 -318
- package/src/__tests__/documentation-fetch-security.integration.test.ts +0 -182
- package/src/__tests__/evaluator-tools.unit.test.ts +0 -262
- package/src/__tests__/experiment-list-tools.unit.test.ts +0 -157
- package/src/__tests__/experiment-status.unit.test.ts +0 -194
- package/src/__tests__/feature-map-tool-drift.unit.test.ts +0 -93
- package/src/__tests__/get-experiment-results.unit.test.ts +0 -313
- package/src/__tests__/http-security-origin.unit.test.ts +0 -97
- package/src/__tests__/http-security-sessions.unit.test.ts +0 -209
- package/src/__tests__/http-security-verifier.unit.test.ts +0 -248
- package/src/__tests__/http-server-allocation.integration.test.ts +0 -279
- package/src/__tests__/http-server-origin.integration.test.ts +0 -169
- package/src/__tests__/http-server-session-auth.integration.test.ts +0 -341
- package/src/__tests__/http-transport.integration.test.ts +0 -395
- package/src/__tests__/integration.integration.test.ts +0 -284
- package/src/__tests__/langwatch-api.unit.test.ts +0 -661
- package/src/__tests__/model-provider-tools.unit.test.ts +0 -190
- package/src/__tests__/project-api-key-tools.unit.test.ts +0 -451
- package/src/__tests__/prompt-response-types.unit.test.ts +0 -51
- package/src/__tests__/prompts.integration.test.ts +0 -736
- package/src/__tests__/public-http-request-security.integration.test.ts +0 -118
- package/src/__tests__/report-issue.integration.test.ts +0 -147
- package/src/__tests__/run-plan-tools.unit.test.ts +0 -565
- package/src/__tests__/scenario-tools.integration.test.ts +0 -286
- package/src/__tests__/scenario-tools.unit.test.ts +0 -207
- package/src/__tests__/schemas.unit.test.ts +0 -85
- package/src/__tests__/simulation-run-tools.unit.test.ts +0 -116
- package/src/__tests__/support/http-server-harness.ts +0 -138
- package/src/__tests__/test-suite-tools.unit.test.ts +0 -615
- package/src/__tests__/tools.integration.test.ts +0 -896
- package/src/schemas/filter-fields.ts +0 -119
- package/src/schemas/index.ts +0 -9
|
@@ -1,896 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
-
|
|
3
|
-
vi.mock("../langwatch-api.js", () => ({
|
|
4
|
-
searchTraces: vi.fn(),
|
|
5
|
-
getTraceById: vi.fn(),
|
|
6
|
-
getAnalyticsTimeseries: vi.fn(),
|
|
7
|
-
listPrompts: vi.fn(),
|
|
8
|
-
getPrompt: vi.fn(),
|
|
9
|
-
getPromptVersions: vi.fn(),
|
|
10
|
-
createPrompt: vi.fn(),
|
|
11
|
-
updatePrompt: vi.fn(),
|
|
12
|
-
assignPromptTag: vi.fn(),
|
|
13
|
-
listPromptTags: vi.fn(),
|
|
14
|
-
createPromptTag: vi.fn(),
|
|
15
|
-
renamePromptTag: vi.fn(),
|
|
16
|
-
deletePromptTag: vi.fn(),
|
|
17
|
-
}));
|
|
18
|
-
|
|
19
|
-
import {
|
|
20
|
-
searchTraces,
|
|
21
|
-
getTraceById,
|
|
22
|
-
getAnalyticsTimeseries,
|
|
23
|
-
listPrompts,
|
|
24
|
-
getPrompt,
|
|
25
|
-
createPrompt,
|
|
26
|
-
updatePrompt,
|
|
27
|
-
assignPromptTag,
|
|
28
|
-
listPromptTags,
|
|
29
|
-
createPromptTag,
|
|
30
|
-
renamePromptTag,
|
|
31
|
-
deletePromptTag,
|
|
32
|
-
type PromptSummary,
|
|
33
|
-
} from "../langwatch-api.js";
|
|
34
|
-
|
|
35
|
-
import { handleSearchTraces } from "../tools/search-traces.js";
|
|
36
|
-
import { handleGetTrace } from "../tools/get-trace.js";
|
|
37
|
-
import { handleGetAnalytics } from "../tools/get-analytics.js";
|
|
38
|
-
import { handleListPrompts } from "../tools/list-prompts.js";
|
|
39
|
-
import { handleGetPrompt } from "../tools/get-prompt.js";
|
|
40
|
-
import { handleCreatePrompt } from "../tools/create-prompt.js";
|
|
41
|
-
import { handleUpdatePrompt } from "../tools/update-prompt.js";
|
|
42
|
-
import { handleAssignPromptTag } from "../tools/assign-prompt-tag.js";
|
|
43
|
-
import { handleListPromptTags } from "../tools/list-prompt-tags.js";
|
|
44
|
-
import { handleCreatePromptTag } from "../tools/create-prompt-tag.js";
|
|
45
|
-
import { handleRenamePromptTag } from "../tools/rename-prompt-tag.js";
|
|
46
|
-
import { handleDeletePromptTag } from "../tools/delete-prompt-tag.js";
|
|
47
|
-
|
|
48
|
-
const mockSearchTraces = vi.mocked(searchTraces);
|
|
49
|
-
const mockGetTraceById = vi.mocked(getTraceById);
|
|
50
|
-
const mockGetAnalytics = vi.mocked(getAnalyticsTimeseries);
|
|
51
|
-
const mockListPrompts = vi.mocked(listPrompts);
|
|
52
|
-
const mockGetPrompt = vi.mocked(getPrompt);
|
|
53
|
-
const mockCreatePrompt = vi.mocked(createPrompt);
|
|
54
|
-
const mockUpdatePrompt = vi.mocked(updatePrompt);
|
|
55
|
-
const mockAssignPromptTag = vi.mocked(assignPromptTag);
|
|
56
|
-
const mockListPromptTags = vi.mocked(listPromptTags);
|
|
57
|
-
const mockCreatePromptTag = vi.mocked(createPromptTag);
|
|
58
|
-
const mockRenamePromptTag = vi.mocked(renamePromptTag);
|
|
59
|
-
const mockDeletePromptTag = vi.mocked(deletePromptTag);
|
|
60
|
-
|
|
61
|
-
beforeEach(() => {
|
|
62
|
-
vi.clearAllMocks();
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
describe("handleSearchTraces()", () => {
|
|
66
|
-
describe("when traces are found with formatted_trace (digest mode)", () => {
|
|
67
|
-
it("shows formatted digest per trace", async () => {
|
|
68
|
-
mockSearchTraces.mockResolvedValue({
|
|
69
|
-
traces: [
|
|
70
|
-
{
|
|
71
|
-
trace_id: "trace-1",
|
|
72
|
-
formatted_trace: "LLM Call [llm] 500ms\n Input: Hello\n Output: Hi",
|
|
73
|
-
input: { value: "Hello world" },
|
|
74
|
-
output: { value: "Hi there" },
|
|
75
|
-
timestamps: { started_at: "2024-01-01T00:00:00Z" },
|
|
76
|
-
},
|
|
77
|
-
],
|
|
78
|
-
pagination: { totalHits: 1 },
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
const result = await handleSearchTraces({});
|
|
82
|
-
|
|
83
|
-
expect(result).toContain("Found 1 traces:");
|
|
84
|
-
expect(result).toContain("### Trace: trace-1");
|
|
85
|
-
expect(result).toContain("LLM Call [llm] 500ms");
|
|
86
|
-
expect(result).toContain("**Time**: 2024-01-01T00:00:00Z");
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
describe("when traces have no formatted_trace", () => {
|
|
91
|
-
it("falls back to input/output truncation", async () => {
|
|
92
|
-
mockSearchTraces.mockResolvedValue({
|
|
93
|
-
traces: [
|
|
94
|
-
{
|
|
95
|
-
trace_id: "trace-2",
|
|
96
|
-
input: { value: "Hello world" },
|
|
97
|
-
output: { value: "Hi there" },
|
|
98
|
-
},
|
|
99
|
-
],
|
|
100
|
-
pagination: { totalHits: 1 },
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
const result = await handleSearchTraces({});
|
|
104
|
-
|
|
105
|
-
expect(result).toContain("**Input**: Hello world");
|
|
106
|
-
expect(result).toContain("**Output**: Hi there");
|
|
107
|
-
});
|
|
108
|
-
|
|
109
|
-
it("truncates long input/output to 100 characters", async () => {
|
|
110
|
-
const longText = "x".repeat(150);
|
|
111
|
-
mockSearchTraces.mockResolvedValue({
|
|
112
|
-
traces: [
|
|
113
|
-
{
|
|
114
|
-
trace_id: "trace-2",
|
|
115
|
-
input: { value: longText },
|
|
116
|
-
output: { value: longText },
|
|
117
|
-
},
|
|
118
|
-
],
|
|
119
|
-
pagination: { totalHits: 1 },
|
|
120
|
-
});
|
|
121
|
-
|
|
122
|
-
const result = await handleSearchTraces({});
|
|
123
|
-
|
|
124
|
-
expect(result).toContain("x".repeat(100) + "...");
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
|
|
128
|
-
describe("when format is json", () => {
|
|
129
|
-
it("returns raw JSON string", async () => {
|
|
130
|
-
const responseData = {
|
|
131
|
-
traces: [{ trace_id: "trace-1", input: { value: "Hello" } }],
|
|
132
|
-
pagination: { totalHits: 1 },
|
|
133
|
-
};
|
|
134
|
-
mockSearchTraces.mockResolvedValue(responseData);
|
|
135
|
-
|
|
136
|
-
const result = await handleSearchTraces({ format: "json" });
|
|
137
|
-
|
|
138
|
-
expect(JSON.parse(result)).toEqual(responseData);
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
it("includes scroll ID when more results are available", async () => {
|
|
143
|
-
mockSearchTraces.mockResolvedValue({
|
|
144
|
-
traces: [{ trace_id: "trace-1", input: { value: "" }, output: { value: "" } }],
|
|
145
|
-
pagination: { totalHits: 100, scrollId: "scroll-abc" },
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
const result = await handleSearchTraces({});
|
|
149
|
-
|
|
150
|
-
expect(result).toContain('scrollId: "scroll-abc"');
|
|
151
|
-
});
|
|
152
|
-
|
|
153
|
-
it("shows error information when trace has errors", async () => {
|
|
154
|
-
mockSearchTraces.mockResolvedValue({
|
|
155
|
-
traces: [
|
|
156
|
-
{
|
|
157
|
-
trace_id: "trace-err",
|
|
158
|
-
input: { value: "" },
|
|
159
|
-
output: { value: "" },
|
|
160
|
-
error: { message: "timeout" },
|
|
161
|
-
},
|
|
162
|
-
],
|
|
163
|
-
pagination: { totalHits: 1 },
|
|
164
|
-
});
|
|
165
|
-
|
|
166
|
-
const result = await handleSearchTraces({});
|
|
167
|
-
|
|
168
|
-
expect(result).toContain("**Error**");
|
|
169
|
-
expect(result).toContain("timeout");
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
describe("when a trace has evaluation results", () => {
|
|
173
|
-
it("shows pass/fail status per evaluation without requiring get_trace", async () => {
|
|
174
|
-
mockSearchTraces.mockResolvedValue({
|
|
175
|
-
traces: [
|
|
176
|
-
{
|
|
177
|
-
trace_id: "trace-eval",
|
|
178
|
-
input: { value: "" },
|
|
179
|
-
output: { value: "" },
|
|
180
|
-
evaluations: [
|
|
181
|
-
{ name: "faithfulness", passed: true, score: 0.92 },
|
|
182
|
-
{ evaluator_id: "toxicity-check", passed: false, label: "flagged" },
|
|
183
|
-
],
|
|
184
|
-
},
|
|
185
|
-
],
|
|
186
|
-
pagination: { totalHits: 1 },
|
|
187
|
-
});
|
|
188
|
-
|
|
189
|
-
const result = await handleSearchTraces({});
|
|
190
|
-
|
|
191
|
-
expect(result).toContain("**faithfulness**: PASSED (score: 0.92)");
|
|
192
|
-
expect(result).toContain("**toxicity-check**: FAILED [flagged]");
|
|
193
|
-
});
|
|
194
|
-
});
|
|
195
|
-
|
|
196
|
-
describe("when no traces are found", () => {
|
|
197
|
-
it("returns a no-results message", async () => {
|
|
198
|
-
mockSearchTraces.mockResolvedValue({ traces: [] });
|
|
199
|
-
|
|
200
|
-
const result = await handleSearchTraces({});
|
|
201
|
-
|
|
202
|
-
expect(result).toBe("No traces found matching your query.");
|
|
203
|
-
});
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
describe("when relative dates are provided", () => {
|
|
207
|
-
it("passes parsed timestamps to the API", async () => {
|
|
208
|
-
mockSearchTraces.mockResolvedValue({ traces: [] });
|
|
209
|
-
|
|
210
|
-
await handleSearchTraces({ startDate: "7d", endDate: "1d" });
|
|
211
|
-
|
|
212
|
-
const call = mockSearchTraces.mock.calls[0]![0] as any;
|
|
213
|
-
expect(call.startDate).toBeTypeOf("number");
|
|
214
|
-
expect(call.endDate).toBeTypeOf("number");
|
|
215
|
-
expect(call.startDate).toBeLessThan(call.endDate);
|
|
216
|
-
});
|
|
217
|
-
});
|
|
218
|
-
|
|
219
|
-
describe("when pageSize is specified", () => {
|
|
220
|
-
it("passes pageSize to the API", async () => {
|
|
221
|
-
mockSearchTraces.mockResolvedValue({ traces: [] });
|
|
222
|
-
|
|
223
|
-
await handleSearchTraces({ pageSize: 50 });
|
|
224
|
-
|
|
225
|
-
const call = mockSearchTraces.mock.calls[0]![0] as any;
|
|
226
|
-
expect(call.pageSize).toBe(50);
|
|
227
|
-
});
|
|
228
|
-
});
|
|
229
|
-
|
|
230
|
-
describe("when pageSize is not specified", () => {
|
|
231
|
-
it("defaults to 25", async () => {
|
|
232
|
-
mockSearchTraces.mockResolvedValue({ traces: [] });
|
|
233
|
-
|
|
234
|
-
await handleSearchTraces({});
|
|
235
|
-
|
|
236
|
-
const call = mockSearchTraces.mock.calls[0]![0] as any;
|
|
237
|
-
expect(call.pageSize).toBe(25);
|
|
238
|
-
});
|
|
239
|
-
});
|
|
240
|
-
|
|
241
|
-
it("passes format to the API", async () => {
|
|
242
|
-
mockSearchTraces.mockResolvedValue({ traces: [] });
|
|
243
|
-
|
|
244
|
-
await handleSearchTraces({ format: "json" });
|
|
245
|
-
|
|
246
|
-
const call = mockSearchTraces.mock.calls[0]![0] as any;
|
|
247
|
-
expect(call.format).toBe("json");
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
it("defaults format to digest", async () => {
|
|
251
|
-
mockSearchTraces.mockResolvedValue({ traces: [] });
|
|
252
|
-
|
|
253
|
-
await handleSearchTraces({});
|
|
254
|
-
|
|
255
|
-
const call = mockSearchTraces.mock.calls[0]![0] as any;
|
|
256
|
-
expect(call.format).toBe("digest");
|
|
257
|
-
});
|
|
258
|
-
|
|
259
|
-
it("includes usage tip about get_trace, format, and discover_schema", async () => {
|
|
260
|
-
mockSearchTraces.mockResolvedValue({
|
|
261
|
-
traces: [{ trace_id: "t1", input: { value: "" }, output: { value: "" } }],
|
|
262
|
-
pagination: { totalHits: 1 },
|
|
263
|
-
});
|
|
264
|
-
|
|
265
|
-
const result = await handleSearchTraces({});
|
|
266
|
-
|
|
267
|
-
expect(result).toContain("get_trace");
|
|
268
|
-
expect(result).toContain("discover_schema");
|
|
269
|
-
expect(result).toContain('"json"');
|
|
270
|
-
});
|
|
271
|
-
});
|
|
272
|
-
|
|
273
|
-
describe("handleGetTrace()", () => {
|
|
274
|
-
describe("when trace has formatted_trace (digest mode)", () => {
|
|
275
|
-
it("shows the formatted digest", async () => {
|
|
276
|
-
mockGetTraceById.mockResolvedValue({
|
|
277
|
-
trace_id: "trace-abc",
|
|
278
|
-
formatted_trace: "Root [server] 1200ms\n LLM Call [llm] 800ms\n Input: Hello\n Output: Hi there",
|
|
279
|
-
timestamps: {
|
|
280
|
-
started_at: "2024-01-01T00:00:00Z",
|
|
281
|
-
updated_at: "2024-01-01T00:01:00Z",
|
|
282
|
-
},
|
|
283
|
-
metadata: { user_id: "user-123" },
|
|
284
|
-
evaluations: [
|
|
285
|
-
{ name: "Toxicity", passed: true, score: 0.95 },
|
|
286
|
-
],
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
const result = await handleGetTrace({ traceId: "trace-abc" });
|
|
290
|
-
|
|
291
|
-
expect(result).toContain("# Trace: trace-abc");
|
|
292
|
-
expect(result).toContain("**Started**: 2024-01-01T00:00:00Z");
|
|
293
|
-
expect(result).toContain("**User**: user-123");
|
|
294
|
-
expect(result).toContain("## Evaluations");
|
|
295
|
-
expect(result).toContain("**Toxicity**: PASSED (score: 0.95)");
|
|
296
|
-
expect(result).toContain("## Trace Details");
|
|
297
|
-
expect(result).toContain("Root [server] 1200ms");
|
|
298
|
-
expect(result).toContain("LLM Call [llm] 800ms");
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
it("includes tip about json format", async () => {
|
|
302
|
-
mockGetTraceById.mockResolvedValue({
|
|
303
|
-
trace_id: "trace-abc",
|
|
304
|
-
formatted_trace: "some digest",
|
|
305
|
-
});
|
|
306
|
-
|
|
307
|
-
const result = await handleGetTrace({ traceId: "trace-abc" });
|
|
308
|
-
|
|
309
|
-
expect(result).toContain('"json"');
|
|
310
|
-
expect(result).toContain("get_trace");
|
|
311
|
-
});
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
describe("when format is json", () => {
|
|
315
|
-
it("returns raw JSON string", async () => {
|
|
316
|
-
const responseData = {
|
|
317
|
-
trace_id: "trace-abc",
|
|
318
|
-
spans: [{ span_id: "s1", name: "LLM Call" }],
|
|
319
|
-
evaluations: [],
|
|
320
|
-
metadata: {},
|
|
321
|
-
};
|
|
322
|
-
mockGetTraceById.mockResolvedValue(responseData);
|
|
323
|
-
|
|
324
|
-
const result = await handleGetTrace({ traceId: "trace-abc", format: "json" });
|
|
325
|
-
|
|
326
|
-
expect(JSON.parse(result)).toEqual(responseData);
|
|
327
|
-
});
|
|
328
|
-
|
|
329
|
-
it("passes json format to the API", async () => {
|
|
330
|
-
mockGetTraceById.mockResolvedValue({ trace_id: "trace-abc" });
|
|
331
|
-
|
|
332
|
-
await handleGetTrace({ traceId: "trace-abc", format: "json" });
|
|
333
|
-
|
|
334
|
-
expect(mockGetTraceById).toHaveBeenCalledWith("trace-abc", "json");
|
|
335
|
-
});
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
describe("when trace has metadata fields", () => {
|
|
339
|
-
it("formats metadata fields", async () => {
|
|
340
|
-
mockGetTraceById.mockResolvedValue({
|
|
341
|
-
trace_id: "trace-abc",
|
|
342
|
-
metadata: {
|
|
343
|
-
user_id: "user-123",
|
|
344
|
-
thread_id: "thread-456",
|
|
345
|
-
customer_id: "cust-789",
|
|
346
|
-
labels: ["production", "important"],
|
|
347
|
-
},
|
|
348
|
-
});
|
|
349
|
-
|
|
350
|
-
const result = await handleGetTrace({ traceId: "trace-abc" });
|
|
351
|
-
|
|
352
|
-
expect(result).toContain("**User**: user-123");
|
|
353
|
-
expect(result).toContain("**Thread**: thread-456");
|
|
354
|
-
expect(result).toContain("**Customer**: cust-789");
|
|
355
|
-
expect(result).toContain("**Labels**: production, important");
|
|
356
|
-
});
|
|
357
|
-
});
|
|
358
|
-
|
|
359
|
-
describe("when trace has evaluations", () => {
|
|
360
|
-
it("formats evaluations", async () => {
|
|
361
|
-
mockGetTraceById.mockResolvedValue({
|
|
362
|
-
trace_id: "trace-abc",
|
|
363
|
-
evaluations: [
|
|
364
|
-
{ name: "Toxicity", passed: true, score: 0.95 },
|
|
365
|
-
{ evaluator_id: "eval-2", passed: false, label: "bad" },
|
|
366
|
-
],
|
|
367
|
-
});
|
|
368
|
-
|
|
369
|
-
const result = await handleGetTrace({ traceId: "trace-abc" });
|
|
370
|
-
|
|
371
|
-
expect(result).toContain("## Evaluations");
|
|
372
|
-
expect(result).toContain("**Toxicity**: PASSED (score: 0.95)");
|
|
373
|
-
expect(result).toContain("**eval-2**: FAILED");
|
|
374
|
-
expect(result).toContain("[bad]");
|
|
375
|
-
});
|
|
376
|
-
});
|
|
377
|
-
|
|
378
|
-
describe("when trace has no formatted_trace", () => {
|
|
379
|
-
it("still renders header and metadata", async () => {
|
|
380
|
-
mockGetTraceById.mockResolvedValue({
|
|
381
|
-
trace_id: "trace-abc",
|
|
382
|
-
timestamps: { started_at: "2024-01-01" },
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
const result = await handleGetTrace({ traceId: "trace-abc" });
|
|
386
|
-
|
|
387
|
-
expect(result).toContain("# Trace: trace-abc");
|
|
388
|
-
expect(result).toContain("**Started**: 2024-01-01");
|
|
389
|
-
expect(result).not.toContain("## Trace Details");
|
|
390
|
-
});
|
|
391
|
-
});
|
|
392
|
-
|
|
393
|
-
describe("when digest format is used (default)", () => {
|
|
394
|
-
it("passes digest format to the API", async () => {
|
|
395
|
-
mockGetTraceById.mockResolvedValue({ trace_id: "trace-abc" });
|
|
396
|
-
|
|
397
|
-
await handleGetTrace({ traceId: "trace-abc" });
|
|
398
|
-
|
|
399
|
-
expect(mockGetTraceById).toHaveBeenCalledWith("trace-abc", "digest");
|
|
400
|
-
});
|
|
401
|
-
});
|
|
402
|
-
});
|
|
403
|
-
|
|
404
|
-
describe("handleGetAnalytics()", () => {
|
|
405
|
-
describe("when data is available", () => {
|
|
406
|
-
it("formats a markdown table with date and value", async () => {
|
|
407
|
-
mockGetAnalytics.mockResolvedValue({
|
|
408
|
-
currentPeriod: [
|
|
409
|
-
{ date: "2024-01-01", metric_0: 42 },
|
|
410
|
-
{ date: "2024-01-02", metric_0: 55 },
|
|
411
|
-
],
|
|
412
|
-
previousPeriod: [],
|
|
413
|
-
});
|
|
414
|
-
|
|
415
|
-
const result = await handleGetAnalytics({
|
|
416
|
-
metric: "performance.completion_time",
|
|
417
|
-
});
|
|
418
|
-
|
|
419
|
-
expect(result).toContain(
|
|
420
|
-
"# Analytics: performance.completion_time (avg)"
|
|
421
|
-
);
|
|
422
|
-
expect(result).toContain("| Date | Value |");
|
|
423
|
-
expect(result).toContain("| 2024-01-01 | 42 |");
|
|
424
|
-
expect(result).toContain("| 2024-01-02 | 55 |");
|
|
425
|
-
});
|
|
426
|
-
|
|
427
|
-
it("shows groupBy when provided", async () => {
|
|
428
|
-
mockGetAnalytics.mockResolvedValue({ currentPeriod: [], previousPeriod: [] });
|
|
429
|
-
|
|
430
|
-
const result = await handleGetAnalytics({
|
|
431
|
-
metric: "metadata.trace_id",
|
|
432
|
-
groupBy: "metadata.model",
|
|
433
|
-
});
|
|
434
|
-
|
|
435
|
-
expect(result).toContain("Grouped by: metadata.model");
|
|
436
|
-
});
|
|
437
|
-
|
|
438
|
-
it("formats grouped data with group column", async () => {
|
|
439
|
-
mockGetAnalytics.mockResolvedValue({
|
|
440
|
-
currentPeriod: [
|
|
441
|
-
{
|
|
442
|
-
date: "2024-01-01",
|
|
443
|
-
"sentiment.thumbs_up_down": {
|
|
444
|
-
"Thumbs Up": { "0/metadata.trace_id/cardinality": 10 },
|
|
445
|
-
"Thumbs Down": { "0/metadata.trace_id/cardinality": 5 },
|
|
446
|
-
},
|
|
447
|
-
},
|
|
448
|
-
],
|
|
449
|
-
previousPeriod: [],
|
|
450
|
-
});
|
|
451
|
-
|
|
452
|
-
const result = await handleGetAnalytics({
|
|
453
|
-
metric: "metadata.trace_id",
|
|
454
|
-
aggregation: "cardinality",
|
|
455
|
-
groupBy: "sentiment.thumbs_up_down",
|
|
456
|
-
});
|
|
457
|
-
|
|
458
|
-
expect(result).toContain("| Date | Group | Value |");
|
|
459
|
-
expect(result).toContain("| 2024-01-01 | Thumbs Up | 10 |");
|
|
460
|
-
expect(result).toContain("| 2024-01-01 | Thumbs Down | 5 |");
|
|
461
|
-
});
|
|
462
|
-
|
|
463
|
-
it("uses the specified aggregation", async () => {
|
|
464
|
-
mockGetAnalytics.mockResolvedValue({ currentPeriod: [], previousPeriod: [] });
|
|
465
|
-
|
|
466
|
-
const result = await handleGetAnalytics({
|
|
467
|
-
metric: "performance.total_cost",
|
|
468
|
-
aggregation: "sum",
|
|
469
|
-
});
|
|
470
|
-
|
|
471
|
-
expect(result).toContain("(sum)");
|
|
472
|
-
const call = mockGetAnalytics.mock.calls[0]![0] as any;
|
|
473
|
-
expect(call.series[0].aggregation).toBe("sum");
|
|
474
|
-
});
|
|
475
|
-
});
|
|
476
|
-
|
|
477
|
-
describe("when no data is available", () => {
|
|
478
|
-
it("returns a no-data message", async () => {
|
|
479
|
-
mockGetAnalytics.mockResolvedValue({ currentPeriod: [], previousPeriod: [] });
|
|
480
|
-
|
|
481
|
-
const result = await handleGetAnalytics({
|
|
482
|
-
metric: "performance.completion_time",
|
|
483
|
-
});
|
|
484
|
-
|
|
485
|
-
expect(result).toContain("No data available for this period.");
|
|
486
|
-
});
|
|
487
|
-
});
|
|
488
|
-
|
|
489
|
-
describe("when metric has no dot", () => {
|
|
490
|
-
it("defaults category to metadata", async () => {
|
|
491
|
-
mockGetAnalytics.mockResolvedValue({ currentPeriod: [], previousPeriod: [] });
|
|
492
|
-
|
|
493
|
-
await handleGetAnalytics({ metric: "trace_id" });
|
|
494
|
-
|
|
495
|
-
const call = mockGetAnalytics.mock.calls[0]![0] as any;
|
|
496
|
-
expect(call.series[0].metric).toBe("metadata.trace_id");
|
|
497
|
-
});
|
|
498
|
-
});
|
|
499
|
-
|
|
500
|
-
it("includes discover_schema tip", async () => {
|
|
501
|
-
mockGetAnalytics.mockResolvedValue({ currentPeriod: [], previousPeriod: [] });
|
|
502
|
-
|
|
503
|
-
const result = await handleGetAnalytics({
|
|
504
|
-
metric: "performance.completion_time",
|
|
505
|
-
});
|
|
506
|
-
|
|
507
|
-
expect(result).toContain("discover_schema");
|
|
508
|
-
});
|
|
509
|
-
});
|
|
510
|
-
|
|
511
|
-
describe("handleListPrompts()", () => {
|
|
512
|
-
describe("when prompts exist", () => {
|
|
513
|
-
it("formats a markdown table with prompt details", async () => {
|
|
514
|
-
mockListPrompts.mockResolvedValue([
|
|
515
|
-
{
|
|
516
|
-
handle: "greeting",
|
|
517
|
-
name: "Greeting Prompt",
|
|
518
|
-
latestVersionNumber: 3,
|
|
519
|
-
},
|
|
520
|
-
{
|
|
521
|
-
id: "p2",
|
|
522
|
-
name: "Summary",
|
|
523
|
-
version: 1,
|
|
524
|
-
},
|
|
525
|
-
]);
|
|
526
|
-
|
|
527
|
-
const result = await handleListPrompts();
|
|
528
|
-
|
|
529
|
-
expect(result).toContain("# Prompts (2 total)");
|
|
530
|
-
expect(result).toContain("| Handle | Name | Latest Version |");
|
|
531
|
-
expect(result).toContain("| greeting | Greeting Prompt | v3 |");
|
|
532
|
-
expect(result).toContain("| p2 | Summary | v1 |");
|
|
533
|
-
});
|
|
534
|
-
});
|
|
535
|
-
|
|
536
|
-
describe("when no prompts exist", () => {
|
|
537
|
-
it("returns a no-prompts message", async () => {
|
|
538
|
-
mockListPrompts.mockResolvedValue([]);
|
|
539
|
-
|
|
540
|
-
const result = await handleListPrompts();
|
|
541
|
-
|
|
542
|
-
expect(result).toBe("No prompts found in this project.");
|
|
543
|
-
});
|
|
544
|
-
});
|
|
545
|
-
|
|
546
|
-
describe("when API returns non-array", () => {
|
|
547
|
-
it("returns a no-prompts message", async () => {
|
|
548
|
-
mockListPrompts.mockResolvedValue(null as unknown as PromptSummary[]);
|
|
549
|
-
|
|
550
|
-
const result = await handleListPrompts();
|
|
551
|
-
|
|
552
|
-
expect(result).toBe("No prompts found in this project.");
|
|
553
|
-
});
|
|
554
|
-
});
|
|
555
|
-
|
|
556
|
-
it("includes usage tip about platform_get_prompt", async () => {
|
|
557
|
-
mockListPrompts.mockResolvedValue([
|
|
558
|
-
{ handle: "test", name: "Test", latestVersionNumber: 1 },
|
|
559
|
-
]);
|
|
560
|
-
|
|
561
|
-
const result = await handleListPrompts();
|
|
562
|
-
|
|
563
|
-
expect(result).toContain("platform_get_prompt");
|
|
564
|
-
});
|
|
565
|
-
});
|
|
566
|
-
|
|
567
|
-
describe("handleGetPrompt()", () => {
|
|
568
|
-
describe("when prompt has full details", () => {
|
|
569
|
-
it("formats the prompt header and metadata", async () => {
|
|
570
|
-
mockGetPrompt.mockResolvedValue({
|
|
571
|
-
id: "p1",
|
|
572
|
-
handle: "greeting",
|
|
573
|
-
name: "Greeting Prompt",
|
|
574
|
-
version: 2,
|
|
575
|
-
versionId: "ver_002",
|
|
576
|
-
model: "openai/gpt-4o",
|
|
577
|
-
messages: [
|
|
578
|
-
{ role: "system", content: "You are a greeter." },
|
|
579
|
-
{ role: "user", content: "Hello!" },
|
|
580
|
-
],
|
|
581
|
-
commitMessage: "Updated greeting",
|
|
582
|
-
});
|
|
583
|
-
|
|
584
|
-
const result = await handleGetPrompt({ idOrHandle: "greeting" });
|
|
585
|
-
|
|
586
|
-
expect(result).toContain("# Prompt: Greeting Prompt");
|
|
587
|
-
expect(result).toContain("**Handle**: greeting");
|
|
588
|
-
expect(result).toContain("**ID**: p1");
|
|
589
|
-
expect(result).toContain("**Version**: v2");
|
|
590
|
-
expect(result).toContain("**Model**: openai/gpt-4o");
|
|
591
|
-
expect(result).not.toContain("**Provider**");
|
|
592
|
-
});
|
|
593
|
-
|
|
594
|
-
it("formats messages", async () => {
|
|
595
|
-
mockGetPrompt.mockResolvedValue({
|
|
596
|
-
name: "Test",
|
|
597
|
-
messages: [
|
|
598
|
-
{ role: "system", content: "You are helpful." },
|
|
599
|
-
{ role: "user", content: "Hi there" },
|
|
600
|
-
],
|
|
601
|
-
});
|
|
602
|
-
|
|
603
|
-
const result = await handleGetPrompt({ idOrHandle: "test" });
|
|
604
|
-
|
|
605
|
-
expect(result).toContain("## Messages");
|
|
606
|
-
expect(result).toContain("### system\nYou are helpful.");
|
|
607
|
-
expect(result).toContain("### user\nHi there");
|
|
608
|
-
});
|
|
609
|
-
|
|
610
|
-
});
|
|
611
|
-
|
|
612
|
-
describe("when prompt has no versions", () => {
|
|
613
|
-
it("uses prompt-level model config", async () => {
|
|
614
|
-
mockGetPrompt.mockResolvedValue({
|
|
615
|
-
name: "Simple",
|
|
616
|
-
model: "openai/gpt-3.5-turbo",
|
|
617
|
-
messages: [{ role: "system", content: "Be brief." }],
|
|
618
|
-
});
|
|
619
|
-
|
|
620
|
-
const result = await handleGetPrompt({ idOrHandle: "simple" });
|
|
621
|
-
|
|
622
|
-
expect(result).toContain("**Model**: openai/gpt-3.5-turbo");
|
|
623
|
-
expect(result).not.toContain("**Provider**");
|
|
624
|
-
expect(result).toContain("### system\nBe brief.");
|
|
625
|
-
});
|
|
626
|
-
});
|
|
627
|
-
});
|
|
628
|
-
|
|
629
|
-
describe("handleCreatePrompt()", () => {
|
|
630
|
-
describe("when prompt is created successfully", () => {
|
|
631
|
-
it("formats a success message with details", async () => {
|
|
632
|
-
mockCreatePrompt.mockResolvedValue({
|
|
633
|
-
id: "new-id-123",
|
|
634
|
-
handle: "my-prompt",
|
|
635
|
-
name: "My Prompt",
|
|
636
|
-
latestVersionNumber: 1,
|
|
637
|
-
});
|
|
638
|
-
|
|
639
|
-
const result = await handleCreatePrompt({
|
|
640
|
-
name: "My Prompt",
|
|
641
|
-
handle: "my-prompt",
|
|
642
|
-
messages: [{ role: "system", content: "You are helpful." }],
|
|
643
|
-
model: "openai/gpt-4o",
|
|
644
|
-
});
|
|
645
|
-
|
|
646
|
-
expect(result).toContain("Prompt created successfully!");
|
|
647
|
-
expect(result).toContain("**ID**: new-id-123");
|
|
648
|
-
expect(result).toContain("**Handle**: my-prompt");
|
|
649
|
-
expect(result).toContain("**Name**: My Prompt");
|
|
650
|
-
expect(result).toContain("**Model**: openai/gpt-4o");
|
|
651
|
-
expect(result).toContain("**Version**: v1");
|
|
652
|
-
});
|
|
653
|
-
|
|
654
|
-
it("generates handle from name when handle is not provided", async () => {
|
|
655
|
-
mockCreatePrompt.mockResolvedValue({
|
|
656
|
-
id: "new-id",
|
|
657
|
-
handle: "my-prompt",
|
|
658
|
-
});
|
|
659
|
-
|
|
660
|
-
await handleCreatePrompt({
|
|
661
|
-
name: "My Prompt!",
|
|
662
|
-
messages: [{ role: "system", content: "test" }],
|
|
663
|
-
model: "openai/gpt-4o",
|
|
664
|
-
});
|
|
665
|
-
|
|
666
|
-
expect(mockCreatePrompt).toHaveBeenCalledWith({
|
|
667
|
-
handle: "my-prompt",
|
|
668
|
-
messages: [{ role: "system", content: "test" }],
|
|
669
|
-
model: "openai/gpt-4o",
|
|
670
|
-
});
|
|
671
|
-
});
|
|
672
|
-
|
|
673
|
-
it("uses provided handle instead of generating one", async () => {
|
|
674
|
-
mockCreatePrompt.mockResolvedValue({
|
|
675
|
-
id: "new-id",
|
|
676
|
-
handle: "custom-handle",
|
|
677
|
-
});
|
|
678
|
-
|
|
679
|
-
await handleCreatePrompt({
|
|
680
|
-
name: "My Prompt",
|
|
681
|
-
handle: "custom-handle",
|
|
682
|
-
messages: [{ role: "system", content: "test" }],
|
|
683
|
-
model: "openai/gpt-4o",
|
|
684
|
-
});
|
|
685
|
-
|
|
686
|
-
expect(mockCreatePrompt).toHaveBeenCalledWith({
|
|
687
|
-
handle: "custom-handle",
|
|
688
|
-
messages: [{ role: "system", content: "test" }],
|
|
689
|
-
model: "openai/gpt-4o",
|
|
690
|
-
});
|
|
691
|
-
});
|
|
692
|
-
});
|
|
693
|
-
|
|
694
|
-
describe("when API returns no name", () => {
|
|
695
|
-
it("uses the input name as fallback", async () => {
|
|
696
|
-
mockCreatePrompt.mockResolvedValue({ id: "p1" });
|
|
697
|
-
|
|
698
|
-
const result = await handleCreatePrompt({
|
|
699
|
-
name: "Fallback Name",
|
|
700
|
-
messages: [{ role: "system", content: "test" }],
|
|
701
|
-
model: "openai/gpt-4o",
|
|
702
|
-
});
|
|
703
|
-
|
|
704
|
-
expect(result).toContain("**Name**: Fallback Name");
|
|
705
|
-
});
|
|
706
|
-
});
|
|
707
|
-
});
|
|
708
|
-
|
|
709
|
-
describe("handleUpdatePrompt()", () => {
|
|
710
|
-
describe("when updating a prompt", () => {
|
|
711
|
-
it("formats an update success message", async () => {
|
|
712
|
-
mockUpdatePrompt.mockResolvedValue({
|
|
713
|
-
id: "p1",
|
|
714
|
-
handle: "greeting",
|
|
715
|
-
latestVersionNumber: 2,
|
|
716
|
-
});
|
|
717
|
-
mockGetPrompt.mockResolvedValue({
|
|
718
|
-
id: "p1",
|
|
719
|
-
handle: "greeting",
|
|
720
|
-
version: 2,
|
|
721
|
-
versionId: "ver_002",
|
|
722
|
-
commitMessage: "Update system prompt",
|
|
723
|
-
});
|
|
724
|
-
|
|
725
|
-
const result = await handleUpdatePrompt({
|
|
726
|
-
idOrHandle: "greeting",
|
|
727
|
-
messages: [{ role: "system", content: "Updated content" }],
|
|
728
|
-
commitMessage: "Update system prompt",
|
|
729
|
-
});
|
|
730
|
-
|
|
731
|
-
expect(result).toContain("Prompt updated successfully!");
|
|
732
|
-
expect(result).toContain("**ID**: p1");
|
|
733
|
-
expect(result).toContain("**Handle**: greeting");
|
|
734
|
-
expect(result).toContain("**Version**: v2");
|
|
735
|
-
expect(result).toContain("**Commit**: Update system prompt");
|
|
736
|
-
});
|
|
737
|
-
|
|
738
|
-
it("calls updatePrompt API with correct params", async () => {
|
|
739
|
-
mockUpdatePrompt.mockResolvedValue({});
|
|
740
|
-
|
|
741
|
-
await handleUpdatePrompt({
|
|
742
|
-
idOrHandle: "greeting",
|
|
743
|
-
model: "openai/gpt-4o",
|
|
744
|
-
commitMessage: "Switch model",
|
|
745
|
-
});
|
|
746
|
-
|
|
747
|
-
expect(mockUpdatePrompt).toHaveBeenCalledWith("greeting", {
|
|
748
|
-
model: "openai/gpt-4o",
|
|
749
|
-
commitMessage: "Switch model",
|
|
750
|
-
});
|
|
751
|
-
});
|
|
752
|
-
});
|
|
753
|
-
});
|
|
754
|
-
|
|
755
|
-
describe("handleGetPrompt() with tag options", () => {
|
|
756
|
-
describe("when called with a tag", () => {
|
|
757
|
-
it("passes tag option to the API", async () => {
|
|
758
|
-
mockGetPrompt.mockResolvedValue({ name: "Test" });
|
|
759
|
-
|
|
760
|
-
await handleGetPrompt({ idOrHandle: "pizza-prompt", tag: "production" });
|
|
761
|
-
|
|
762
|
-
expect(mockGetPrompt).toHaveBeenCalledWith("pizza-prompt", { version: undefined, tag: "production" });
|
|
763
|
-
});
|
|
764
|
-
});
|
|
765
|
-
});
|
|
766
|
-
|
|
767
|
-
describe("handleCreatePrompt() with tags", () => {
|
|
768
|
-
describe("when called with tags", () => {
|
|
769
|
-
it("includes tags in the output", async () => {
|
|
770
|
-
mockCreatePrompt.mockResolvedValue({ id: "p1", handle: "test" });
|
|
771
|
-
|
|
772
|
-
const result = await handleCreatePrompt({
|
|
773
|
-
name: "Test",
|
|
774
|
-
messages: [{ role: "system", content: "hi" }],
|
|
775
|
-
model: "openai/gpt-5-mini",
|
|
776
|
-
tags: ["production"],
|
|
777
|
-
});
|
|
778
|
-
|
|
779
|
-
expect(result).toContain("**Tags**: production");
|
|
780
|
-
});
|
|
781
|
-
});
|
|
782
|
-
});
|
|
783
|
-
|
|
784
|
-
describe("handleUpdatePrompt() with tags", () => {
|
|
785
|
-
describe("when called with tags", () => {
|
|
786
|
-
it("includes tags in the output", async () => {
|
|
787
|
-
mockUpdatePrompt.mockResolvedValue({ id: "p1", handle: "test", latestVersionNumber: 2 });
|
|
788
|
-
mockGetPrompt.mockResolvedValue({
|
|
789
|
-
id: "p1",
|
|
790
|
-
handle: "test",
|
|
791
|
-
version: 2,
|
|
792
|
-
versionId: "ver_002",
|
|
793
|
-
commitMessage: "add tags",
|
|
794
|
-
tags: [
|
|
795
|
-
{ name: "staging", versionId: "ver_002" },
|
|
796
|
-
{ name: "latest", versionId: "ver_002" },
|
|
797
|
-
],
|
|
798
|
-
});
|
|
799
|
-
|
|
800
|
-
const result = await handleUpdatePrompt({
|
|
801
|
-
idOrHandle: "test",
|
|
802
|
-
commitMessage: "add tags",
|
|
803
|
-
tags: ["staging"],
|
|
804
|
-
});
|
|
805
|
-
|
|
806
|
-
expect(result).toContain("**Deployed to**: staging");
|
|
807
|
-
});
|
|
808
|
-
});
|
|
809
|
-
});
|
|
810
|
-
|
|
811
|
-
describe("handleAssignPromptTag()", () => {
|
|
812
|
-
describe("when tag is assigned successfully", () => {
|
|
813
|
-
it("returns a confirmation with prompt, tag, and version", async () => {
|
|
814
|
-
mockAssignPromptTag.mockResolvedValue({ success: true });
|
|
815
|
-
|
|
816
|
-
const result = await handleAssignPromptTag({
|
|
817
|
-
idOrHandle: "pizza-prompt",
|
|
818
|
-
tag: "production",
|
|
819
|
-
versionId: "v123",
|
|
820
|
-
});
|
|
821
|
-
|
|
822
|
-
expect(result).toContain("Tag assigned successfully!");
|
|
823
|
-
expect(result).toContain("**Prompt**: pizza-prompt");
|
|
824
|
-
expect(result).toContain("**Tag**: production");
|
|
825
|
-
expect(result).toContain("**Version ID**: v123");
|
|
826
|
-
});
|
|
827
|
-
});
|
|
828
|
-
});
|
|
829
|
-
|
|
830
|
-
describe("handleListPromptTags()", () => {
|
|
831
|
-
describe("when tags exist", () => {
|
|
832
|
-
it("formats tags as a markdown list", async () => {
|
|
833
|
-
mockListPromptTags.mockResolvedValue([
|
|
834
|
-
{ id: "1", name: "production", createdAt: "2024-01-01" },
|
|
835
|
-
{ id: "2", name: "staging" },
|
|
836
|
-
]);
|
|
837
|
-
|
|
838
|
-
const result = await handleListPromptTags();
|
|
839
|
-
|
|
840
|
-
expect(result).toContain("# Prompt Tags");
|
|
841
|
-
expect(result).toContain("**production**");
|
|
842
|
-
expect(result).toContain("**staging**");
|
|
843
|
-
});
|
|
844
|
-
});
|
|
845
|
-
|
|
846
|
-
describe("when no tags exist", () => {
|
|
847
|
-
it("returns an empty-state message mentioning latest", async () => {
|
|
848
|
-
mockListPromptTags.mockResolvedValue([]);
|
|
849
|
-
|
|
850
|
-
const result = await handleListPromptTags();
|
|
851
|
-
|
|
852
|
-
expect(result).toContain("No prompt tags found");
|
|
853
|
-
expect(result).toContain("`latest`");
|
|
854
|
-
});
|
|
855
|
-
});
|
|
856
|
-
});
|
|
857
|
-
|
|
858
|
-
describe("handleCreatePromptTag()", () => {
|
|
859
|
-
describe("when tag is created successfully", () => {
|
|
860
|
-
it("returns a confirmation with the tag name", async () => {
|
|
861
|
-
mockCreatePromptTag.mockResolvedValue({ id: "t1", name: "canary" });
|
|
862
|
-
|
|
863
|
-
const result = await handleCreatePromptTag({ name: "canary" });
|
|
864
|
-
|
|
865
|
-
expect(result).toContain("Tag created successfully!");
|
|
866
|
-
expect(result).toContain("**Name**: canary");
|
|
867
|
-
});
|
|
868
|
-
});
|
|
869
|
-
});
|
|
870
|
-
|
|
871
|
-
describe("handleRenamePromptTag()", () => {
|
|
872
|
-
describe("when tag is renamed successfully", () => {
|
|
873
|
-
it("returns a confirmation with old and new names", async () => {
|
|
874
|
-
mockRenamePromptTag.mockResolvedValue({ id: "t1", name: "preview" });
|
|
875
|
-
|
|
876
|
-
const result = await handleRenamePromptTag({ tag: "canary", name: "preview" });
|
|
877
|
-
|
|
878
|
-
expect(result).toContain("Tag renamed successfully!");
|
|
879
|
-
expect(result).toContain("**Old name**: canary");
|
|
880
|
-
expect(result).toContain("**New name**: preview");
|
|
881
|
-
});
|
|
882
|
-
});
|
|
883
|
-
});
|
|
884
|
-
|
|
885
|
-
describe("handleDeletePromptTag()", () => {
|
|
886
|
-
describe("when tag is deleted successfully", () => {
|
|
887
|
-
it("returns a confirmation with the tag name", async () => {
|
|
888
|
-
mockDeletePromptTag.mockResolvedValue(null);
|
|
889
|
-
|
|
890
|
-
const result = await handleDeletePromptTag({ tag: "canary" });
|
|
891
|
-
|
|
892
|
-
expect(result).toContain("Tag deleted successfully!");
|
|
893
|
-
expect(result).toContain("**Tag**: canary");
|
|
894
|
-
});
|
|
895
|
-
});
|
|
896
|
-
});
|