@langwatch/mcp-server 0.6.0 → 0.7.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 +30 -0
- package/Dockerfile +22 -0
- package/README.md +51 -8
- package/dist/{archive-scenario-YFD5THOR.js → archive-scenario-WJ2A7ETN.js} +4 -4
- package/dist/archive-suite-4JOM4SSL.js +15 -0
- package/dist/archive-suite-4JOM4SSL.js.map +1 -0
- package/dist/assign-prompt-tag-GL7EAAF3.js +19 -0
- package/dist/assign-prompt-tag-GL7EAAF3.js.map +1 -0
- package/dist/{chunk-6U4TCGFC.js → chunk-2GT7IFWK.js} +2 -2
- package/dist/{chunk-LLRQIF52.js → chunk-2WPLXEKF.js} +49 -5
- package/dist/chunk-2WPLXEKF.js.map +1 -0
- package/dist/chunk-4AUB2BIA.js +71 -0
- package/dist/chunk-4AUB2BIA.js.map +1 -0
- package/dist/chunk-BWWY5KEF.js +71 -0
- package/dist/chunk-BWWY5KEF.js.map +1 -0
- package/dist/{chunk-IX6QJKAD.js → chunk-CCWCIJJ3.js} +2 -2
- package/dist/chunk-E5JYYU3J.js +1567 -0
- package/dist/chunk-E5JYYU3J.js.map +1 -0
- package/dist/chunk-EGH5RPXM.js +25 -0
- package/dist/chunk-EGH5RPXM.js.map +1 -0
- package/dist/chunk-EUQDVOSU.js +39 -0
- package/dist/chunk-EUQDVOSU.js.map +1 -0
- package/dist/{chunk-5UOPNRXW.js → chunk-HYMIWO3U.js} +10 -3
- package/dist/{chunk-5UOPNRXW.js.map → chunk-HYMIWO3U.js.map} +1 -1
- package/dist/chunk-IE4M5OGE.js +42 -0
- package/dist/chunk-IE4M5OGE.js.map +1 -0
- package/dist/chunk-LUMEZEHL.js +48 -0
- package/dist/chunk-LUMEZEHL.js.map +1 -0
- package/dist/chunk-NUFPTHKU.js +9 -0
- package/dist/chunk-NUFPTHKU.js.map +1 -0
- package/dist/chunk-WQG2DFHX.js +86 -0
- package/dist/chunk-WQG2DFHX.js.map +1 -0
- package/dist/chunk-WVI5CJ6S.js +21 -0
- package/dist/chunk-WVI5CJ6S.js.map +1 -0
- package/dist/chunk-ZVS4UKN2.js +35 -0
- package/dist/chunk-ZVS4UKN2.js.map +1 -0
- package/dist/config.d.ts +17 -0
- package/dist/config.js +13 -0
- package/dist/create-agent-MBOOT3XK.js +23 -0
- package/dist/create-agent-MBOOT3XK.js.map +1 -0
- package/dist/create-annotation-XMV6A7ED.js +24 -0
- package/dist/create-annotation-XMV6A7ED.js.map +1 -0
- package/dist/create-dashboard-VRKLFVZJ.js +18 -0
- package/dist/create-dashboard-VRKLFVZJ.js.map +1 -0
- package/dist/create-dataset-7HQPZCRE.js +22 -0
- package/dist/create-dataset-7HQPZCRE.js.map +1 -0
- package/dist/create-dataset-records-2NIVFYTV.js +22 -0
- package/dist/create-dataset-records-2NIVFYTV.js.map +1 -0
- package/dist/{create-evaluator-E5X5ZP3B.js → create-evaluator-WYFRFLRC.js} +4 -4
- package/dist/create-mcp-server.d.ts +8 -0
- package/dist/create-mcp-server.js +8 -0
- package/dist/create-mcp-server.js.map +1 -0
- package/dist/{create-prompt-7Z35MIL6.js → create-prompt-IEN7O6JT.js} +7 -4
- package/dist/create-prompt-IEN7O6JT.js.map +1 -0
- package/dist/create-prompt-tag-CAEZ45VO.js +17 -0
- package/dist/create-prompt-tag-CAEZ45VO.js.map +1 -0
- package/dist/{create-scenario-DIMPJRPY.js → create-scenario-6YHSMGLP.js} +4 -4
- package/dist/create-suite-H5XOFDE5.js +38 -0
- package/dist/create-suite-H5XOFDE5.js.map +1 -0
- package/dist/delete-agent-JKTNBWAA.js +18 -0
- package/dist/delete-agent-JKTNBWAA.js.map +1 -0
- package/dist/delete-annotation-ACMDV6QO.js +17 -0
- package/dist/delete-annotation-ACMDV6QO.js.map +1 -0
- package/dist/delete-dashboard-VJSR7CRU.js +18 -0
- package/dist/delete-dashboard-VJSR7CRU.js.map +1 -0
- package/dist/delete-dataset-RTTTWP4D.js +20 -0
- package/dist/delete-dataset-RTTTWP4D.js.map +1 -0
- package/dist/delete-dataset-records-KNQTIPQK.js +21 -0
- package/dist/delete-dataset-records-KNQTIPQK.js.map +1 -0
- package/dist/delete-evaluator-7FVC5WM4.js +15 -0
- package/dist/delete-evaluator-7FVC5WM4.js.map +1 -0
- package/dist/delete-prompt-tag-ZMZUAGFW.js +17 -0
- package/dist/delete-prompt-tag-ZMZUAGFW.js.map +1 -0
- package/dist/delete-workflow-EYQ3T4RQ.js +17 -0
- package/dist/delete-workflow-EYQ3T4RQ.js.map +1 -0
- package/dist/get-agent-E3QSTVKG.js +28 -0
- package/dist/get-agent-E3QSTVKG.js.map +1 -0
- package/dist/{get-analytics-4YJW4S5L.js → get-analytics-2OHV763I.js} +22 -5
- package/dist/get-analytics-2OHV763I.js.map +1 -0
- package/dist/get-dashboard-PC7JDHH6.js +29 -0
- package/dist/get-dashboard-PC7JDHH6.js.map +1 -0
- package/dist/get-dataset-H5IK5FVU.js +48 -0
- package/dist/get-dataset-H5IK5FVU.js.map +1 -0
- package/dist/{get-evaluator-WDEH2F7M.js → get-evaluator-UWVUPYTM.js} +4 -4
- package/dist/{get-prompt-F6PDVC76.js → get-prompt-WZUOLLQC.js} +4 -4
- package/dist/get-prompt-WZUOLLQC.js.map +1 -0
- package/dist/{get-scenario-H24ZYNT5.js → get-scenario-Q6LCNUYN.js} +4 -4
- package/dist/get-simulation-run-Z2XKO256.js +56 -0
- package/dist/get-simulation-run-Z2XKO256.js.map +1 -0
- package/dist/get-suite-BXK5TN7P.js +44 -0
- package/dist/get-suite-BXK5TN7P.js.map +1 -0
- package/dist/{get-trace-27USKGO7.js → get-trace-4EJAYVBG.js} +3 -3
- package/dist/get-workflow-O34QJLHD.js +25 -0
- package/dist/get-workflow-O34QJLHD.js.map +1 -0
- package/dist/http-server-ISHF7NJX.js +224 -0
- package/dist/http-server-ISHF7NJX.js.map +1 -0
- package/dist/index.js +61109 -31519
- package/dist/index.js.map +1 -1
- package/dist/langwatch-api-annotations-ERBG27RF.js +17 -0
- package/dist/langwatch-api-annotations-ERBG27RF.js.map +1 -0
- package/dist/langwatch-api-dashboards-G6TR7VVO.js +17 -0
- package/dist/langwatch-api-dashboards-G6TR7VVO.js.map +1 -0
- package/dist/langwatch-api-monitors-WSXZLS2B.js +52 -0
- package/dist/langwatch-api-monitors-WSXZLS2B.js.map +1 -0
- package/dist/langwatch-api-secrets-RR5DKG2X.js +40 -0
- package/dist/langwatch-api-secrets-RR5DKG2X.js.map +1 -0
- package/dist/langwatch-api-triggers-2RTNSWQY.js +30 -0
- package/dist/langwatch-api-triggers-2RTNSWQY.js.map +1 -0
- package/dist/langwatch-api-workflows-VJRIIDZ7.js +15 -0
- package/dist/langwatch-api-workflows-VJRIIDZ7.js.map +1 -0
- package/dist/list-agents-AW3P6FJV.js +32 -0
- package/dist/list-agents-AW3P6FJV.js.map +1 -0
- package/dist/list-annotations-QNCGWPQ3.js +33 -0
- package/dist/list-annotations-QNCGWPQ3.js.map +1 -0
- package/dist/list-dashboards-R7RK2IXL.js +32 -0
- package/dist/list-dashboards-R7RK2IXL.js.map +1 -0
- package/dist/list-dataset-records-WVCSQP7P.js +39 -0
- package/dist/list-dataset-records-WVCSQP7P.js.map +1 -0
- package/dist/list-datasets-KEXRLDEU.js +60 -0
- package/dist/list-datasets-KEXRLDEU.js.map +1 -0
- package/dist/{list-evaluators-KRGI72EH.js → list-evaluators-7R2LB4JH.js} +4 -4
- package/dist/{list-model-providers-A5YCFTPI.js → list-model-providers-OBYJCKBX.js} +4 -4
- package/dist/list-prompt-tags-6LY3ZPYI.js +23 -0
- package/dist/list-prompt-tags-6LY3ZPYI.js.map +1 -0
- package/dist/{list-prompts-LKJSE7XN.js → list-prompts-VWEZ4CDE.js} +3 -3
- package/dist/{list-scenarios-ZK5CMGC4.js → list-scenarios-TXD4W2ZJ.js} +4 -4
- package/dist/list-simulation-runs-RHPOLMFI.js +43 -0
- package/dist/list-simulation-runs-RHPOLMFI.js.map +1 -0
- package/dist/list-suites-FSGBX27Z.js +42 -0
- package/dist/list-suites-FSGBX27Z.js.map +1 -0
- package/dist/list-workflows-VRGEZ3EN.js +35 -0
- package/dist/list-workflows-VRGEZ3EN.js.map +1 -0
- package/dist/rename-prompt-tag-VOJJLX4M.js +18 -0
- package/dist/rename-prompt-tag-VOJJLX4M.js.map +1 -0
- package/dist/run-agent-KTCC7TB7.js +36 -0
- package/dist/run-agent-KTCC7TB7.js.map +1 -0
- package/dist/run-evaluation-2X3V3Q6L.js +64 -0
- package/dist/run-evaluation-2X3V3Q6L.js.map +1 -0
- package/dist/run-suite-BTMHGI2D.js +29 -0
- package/dist/run-suite-BTMHGI2D.js.map +1 -0
- package/dist/run-workflow-IGAYGKJL.js +36 -0
- package/dist/run-workflow-IGAYGKJL.js.map +1 -0
- package/dist/{search-traces-SOKAAMAR.js → search-traces-VYFUIMXH.js} +3 -3
- package/dist/{set-model-provider-7MGULZDH.js → set-model-provider-W5IUI326.js} +4 -4
- package/dist/update-agent-4BB7EYLR.js +20 -0
- package/dist/update-agent-4BB7EYLR.js.map +1 -0
- package/dist/update-dataset-CXBKZ4W3.js +22 -0
- package/dist/update-dataset-CXBKZ4W3.js.map +1 -0
- package/dist/update-dataset-record-HOHAMHXG.js +19 -0
- package/dist/update-dataset-record-HOHAMHXG.js.map +1 -0
- package/dist/{update-evaluator-A3XINFLJ.js → update-evaluator-IVOR6FTR.js} +4 -4
- package/dist/{update-prompt-IW7X2UQM.js → update-prompt-OWQAKE7K.js} +5 -3
- package/dist/update-prompt-OWQAKE7K.js.map +1 -0
- package/dist/{update-scenario-ZT7TOBFR.js → update-scenario-GDFVILPN.js} +4 -4
- package/dist/update-suite-BXYUYSPT.js +39 -0
- package/dist/update-suite-BXYUYSPT.js.map +1 -0
- package/package.json +17 -3
- package/src/__tests__/all-tools.integration.test.ts +344 -0
- package/src/__tests__/config.unit.test.ts +81 -1
- package/src/__tests__/datasets.integration.test.ts +603 -0
- package/src/__tests__/datasets.unit.test.ts +240 -0
- package/src/__tests__/docker.integration.test.ts +234 -0
- package/src/__tests__/http-transport.integration.test.ts +397 -0
- package/src/__tests__/langwatch-api.unit.test.ts +174 -0
- package/src/__tests__/tools.unit.test.ts +177 -0
- package/src/config.d.ts +15 -0
- package/src/config.ts +83 -7
- package/src/create-mcp-server.d.ts +6 -0
- package/src/create-mcp-server.ts +1799 -0
- package/src/http-server.ts +329 -0
- package/src/index.ts +22 -593
- package/src/langwatch-api-agents.ts +108 -0
- package/src/langwatch-api-annotations.ts +49 -0
- package/src/langwatch-api-dashboards.ts +48 -0
- package/src/langwatch-api-datasets.ts +191 -0
- package/src/langwatch-api-evaluators.ts +10 -0
- package/src/langwatch-api-monitors.ts +82 -0
- package/src/langwatch-api-secrets.ts +48 -0
- package/src/langwatch-api-simulation-runs.ts +51 -0
- package/src/langwatch-api-suites.ts +118 -0
- package/src/langwatch-api-triggers.ts +48 -0
- package/src/langwatch-api-workflows.ts +41 -0
- package/src/langwatch-api.ts +60 -2
- package/src/schemas/create-dataset.ts +48 -0
- package/src/schemas/index.ts +1 -0
- package/src/tools/archive-suite.ts +12 -0
- package/src/tools/assign-prompt-tag.ts +16 -0
- package/src/tools/create-agent.ts +15 -0
- package/src/tools/create-annotation.ts +18 -0
- package/src/tools/create-dashboard.ts +7 -0
- package/src/tools/create-dataset-records.ts +23 -0
- package/src/tools/create-dataset.ts +22 -0
- package/src/tools/create-prompt-tag.ts +12 -0
- package/src/tools/create-prompt.ts +4 -0
- package/src/tools/create-suite.ts +42 -0
- package/src/tools/delete-agent.ts +7 -0
- package/src/tools/delete-annotation.ts +7 -0
- package/src/tools/delete-dashboard.ts +7 -0
- package/src/tools/delete-dataset-records.ts +22 -0
- package/src/tools/delete-dataset.ts +20 -0
- package/src/tools/delete-evaluator.ts +12 -0
- package/src/tools/delete-prompt-tag.ts +12 -0
- package/src/tools/delete-workflow.ts +7 -0
- package/src/tools/format-dataset-mutation.ts +25 -0
- package/src/tools/get-agent.ts +21 -0
- package/src/tools/get-analytics.ts +30 -3
- package/src/tools/get-dashboard.ts +22 -0
- package/src/tools/get-dataset.ts +63 -0
- package/src/tools/get-prompt.ts +2 -1
- package/src/tools/get-simulation-run.ts +60 -0
- package/src/tools/get-suite.ts +47 -0
- package/src/tools/get-workflow.ts +17 -0
- package/src/tools/list-agents.ts +27 -0
- package/src/tools/list-annotations.ts +33 -0
- package/src/tools/list-dashboards.ts +27 -0
- package/src/tools/list-dataset-records.ts +46 -0
- package/src/tools/list-datasets.ts +80 -0
- package/src/tools/list-prompt-tags.ts +21 -0
- package/src/tools/list-simulation-runs.ts +49 -0
- package/src/tools/list-suites.ts +43 -0
- package/src/tools/list-workflows.ts +31 -0
- package/src/tools/rename-prompt-tag.ts +14 -0
- package/src/tools/run-agent.ts +36 -0
- package/src/tools/run-evaluation.ts +87 -0
- package/src/tools/run-suite.ts +28 -0
- package/src/tools/run-workflow.ts +36 -0
- package/src/tools/update-agent.ts +13 -0
- package/src/tools/update-dataset-record.ts +21 -0
- package/src/tools/update-dataset.ts +23 -0
- package/src/tools/update-prompt.ts +3 -0
- package/src/tools/update-suite.ts +44 -0
- package/src/utils/escape-markdown.ts +12 -0
- package/tsup.config.ts +5 -1
- package/dist/chunk-AAQNA53E.js +0 -28
- package/dist/chunk-AAQNA53E.js.map +0 -1
- package/dist/chunk-LLRQIF52.js.map +0 -1
- package/dist/config-FIQWQRUB.js +0 -11
- package/dist/create-prompt-7Z35MIL6.js.map +0 -1
- package/dist/get-analytics-4YJW4S5L.js.map +0 -1
- package/dist/get-prompt-F6PDVC76.js.map +0 -1
- package/dist/update-prompt-IW7X2UQM.js.map +0 -1
- /package/dist/{archive-scenario-YFD5THOR.js.map → archive-scenario-WJ2A7ETN.js.map} +0 -0
- /package/dist/{chunk-6U4TCGFC.js.map → chunk-2GT7IFWK.js.map} +0 -0
- /package/dist/{chunk-IX6QJKAD.js.map → chunk-CCWCIJJ3.js.map} +0 -0
- /package/dist/{config-FIQWQRUB.js.map → config.js.map} +0 -0
- /package/dist/{create-evaluator-E5X5ZP3B.js.map → create-evaluator-WYFRFLRC.js.map} +0 -0
- /package/dist/{create-scenario-DIMPJRPY.js.map → create-scenario-6YHSMGLP.js.map} +0 -0
- /package/dist/{get-evaluator-WDEH2F7M.js.map → get-evaluator-UWVUPYTM.js.map} +0 -0
- /package/dist/{get-scenario-H24ZYNT5.js.map → get-scenario-Q6LCNUYN.js.map} +0 -0
- /package/dist/{get-trace-27USKGO7.js.map → get-trace-4EJAYVBG.js.map} +0 -0
- /package/dist/{list-evaluators-KRGI72EH.js.map → list-evaluators-7R2LB4JH.js.map} +0 -0
- /package/dist/{list-model-providers-A5YCFTPI.js.map → list-model-providers-OBYJCKBX.js.map} +0 -0
- /package/dist/{list-prompts-LKJSE7XN.js.map → list-prompts-VWEZ4CDE.js.map} +0 -0
- /package/dist/{list-scenarios-ZK5CMGC4.js.map → list-scenarios-TXD4W2ZJ.js.map} +0 -0
- /package/dist/{search-traces-SOKAAMAR.js.map → search-traces-VYFUIMXH.js.map} +0 -0
- /package/dist/{set-model-provider-7MGULZDH.js.map → set-model-provider-W5IUI326.js.map} +0 -0
- /package/dist/{update-evaluator-A3XINFLJ.js.map → update-evaluator-IVOR6FTR.js.map} +0 -0
- /package/dist/{update-scenario-ZT7TOBFR.js.map → update-scenario-GDFVILPN.js.map} +0 -0
package/package.json
CHANGED
|
@@ -1,15 +1,27 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@langwatch/mcp-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.7.0",
|
|
4
4
|
"description": "An MCP server for Langwatch.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
|
-
"module": "./dist/index.
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
8
|
"types": "./dist/index.d.ts",
|
|
9
9
|
"exports": {
|
|
10
10
|
".": {
|
|
11
|
-
"import": "./dist/index.
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
12
|
"require": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./create-mcp-server": {
|
|
15
|
+
"types": "./src/create-mcp-server.d.ts",
|
|
16
|
+
"import": "./dist/create-mcp-server.js",
|
|
17
|
+
"require": "./dist/create-mcp-server.js",
|
|
18
|
+
"default": "./dist/create-mcp-server.js"
|
|
19
|
+
},
|
|
20
|
+
"./config": {
|
|
21
|
+
"types": "./src/config.d.ts",
|
|
22
|
+
"import": "./dist/config.js",
|
|
23
|
+
"require": "./dist/config.js",
|
|
24
|
+
"default": "./dist/config.js"
|
|
13
25
|
}
|
|
14
26
|
},
|
|
15
27
|
"repository": {
|
|
@@ -29,6 +41,7 @@
|
|
|
29
41
|
"@langwatch/scenario": "^0.4.6",
|
|
30
42
|
"@types/debug": "^4.1.12",
|
|
31
43
|
"@types/eslint__js": "^8.42.3",
|
|
44
|
+
"@types/express": "^5.0.6",
|
|
32
45
|
"@types/node": "^16.0.0",
|
|
33
46
|
"@types/yargs": "^17.0.33",
|
|
34
47
|
"@typescript/native-preview": "7.0.0-dev.20250911.1",
|
|
@@ -47,6 +60,7 @@
|
|
|
47
60
|
"@opentelemetry/sdk-node": "^0.204.0",
|
|
48
61
|
"chalk": "^5.6.2",
|
|
49
62
|
"date-fns": "^4.1.0",
|
|
63
|
+
"express": "^5.2.1",
|
|
50
64
|
"node-pty": "^1.0.0",
|
|
51
65
|
"vitest": "^3.2.4",
|
|
52
66
|
"yargs": "^17.7.2",
|
|
@@ -278,6 +278,50 @@ const CANNED_MODEL_PROVIDERS_LIST = {
|
|
|
278
278
|
},
|
|
279
279
|
};
|
|
280
280
|
|
|
281
|
+
const CANNED_AGENTS_LIST = {
|
|
282
|
+
data: [
|
|
283
|
+
{ id: "agent_abc", name: "Test Agent", type: "http", config: { url: "http://example.com" }, createdAt: "2024-01-01T00:00:00Z", updatedAt: "2024-01-01T00:00:00Z" },
|
|
284
|
+
],
|
|
285
|
+
pagination: { page: 1, limit: 50, total: 1, totalPages: 1 },
|
|
286
|
+
};
|
|
287
|
+
|
|
288
|
+
const CANNED_AGENT_DETAIL = {
|
|
289
|
+
id: "agent_abc", name: "Test Agent", type: "http", config: { url: "http://example.com" }, createdAt: "2024-01-01T00:00:00Z", updatedAt: "2024-01-01T00:00:00Z",
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
const CANNED_SUITES_LIST = [
|
|
293
|
+
{ id: "suite_abc", name: "Regression Suite", slug: "regression-suite", description: null, scenarioIds: ["scen_abc123"], targets: [{ type: "http", referenceId: "agent_abc" }], repeatCount: 1, labels: [], createdAt: "2024-01-01T00:00:00Z", updatedAt: "2024-01-01T00:00:00Z" },
|
|
294
|
+
];
|
|
295
|
+
|
|
296
|
+
const CANNED_SUITE_DETAIL = {
|
|
297
|
+
id: "suite_abc", name: "Regression Suite", slug: "regression-suite", description: "A test suite", scenarioIds: ["scen_abc123"], targets: [{ type: "http", referenceId: "agent_abc" }], repeatCount: 1, labels: [], createdAt: "2024-01-01T00:00:00Z", updatedAt: "2024-01-01T00:00:00Z",
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
const CANNED_SUITE_CREATED = {
|
|
301
|
+
id: "suite_new", name: "New Suite", slug: "new-suite", description: null, scenarioIds: ["scen_abc123"], targets: [{ type: "http", referenceId: "agent_abc" }], repeatCount: 1, labels: [], createdAt: "2024-01-01T00:00:00Z", updatedAt: "2024-01-01T00:00:00Z",
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
const CANNED_SUITE_RUN = {
|
|
305
|
+
scheduled: true, batchRunId: "batch_123", setId: "set_456", jobCount: 1, skippedArchived: { scenarios: [], targets: [] }, items: [{ scenarioRunId: "run_1", scenarioId: "scen_abc123", target: { type: "http", referenceId: "agent_abc" }, name: "Test" }],
|
|
306
|
+
};
|
|
307
|
+
|
|
308
|
+
const CANNED_SIMULATION_RUNS = {
|
|
309
|
+
runs: [{ scenarioRunId: "run_abc", scenarioId: "scen_abc123", batchRunId: "batch_xyz", name: "Login Flow", status: "SUCCESS", durationInMs: 5200, totalCost: 0.0042, timestamp: 1700000000000, updatedAt: 1700000001000 }],
|
|
310
|
+
hasMore: false,
|
|
311
|
+
};
|
|
312
|
+
|
|
313
|
+
const CANNED_SIMULATION_RUN_DETAIL = {
|
|
314
|
+
scenarioRunId: "run_abc", scenarioId: "scen_abc123", batchRunId: "batch_xyz", name: "Login Flow", status: "SUCCESS", durationInMs: 5200, totalCost: 0.0042, results: { verdict: "passed", reasoning: "All criteria met", metCriteria: ["Greets user"], unmetCriteria: [], error: null }, messages: [{ role: "user", content: "Hello" }, { role: "assistant", content: "Hi there!" }], timestamp: 1700000000000, updatedAt: 1700000001000,
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
const CANNED_DASHBOARDS_LIST = {
|
|
318
|
+
data: [{ id: "dash_abc", name: "Main Dashboard", order: 0, graphCount: 3, createdAt: "2024-01-01T00:00:00Z", updatedAt: "2024-01-01T00:00:00Z" }],
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
const CANNED_WORKFLOWS_LIST = [
|
|
322
|
+
{ id: "wf_abc", name: "Test Workflow", icon: null, description: "A workflow", isEvaluator: false, isComponent: false, createdAt: "2024-01-01T00:00:00Z", updatedAt: "2024-01-01T00:00:00Z" },
|
|
323
|
+
];
|
|
324
|
+
|
|
281
325
|
const CANNED_MODEL_PROVIDER_SET = {
|
|
282
326
|
openai: {
|
|
283
327
|
provider: "openai",
|
|
@@ -436,6 +480,124 @@ function createMockServer(): Server {
|
|
|
436
480
|
res.writeHead(200);
|
|
437
481
|
res.end(JSON.stringify(CANNED_MODEL_PROVIDER_SET));
|
|
438
482
|
}
|
|
483
|
+
// --- Agent endpoints ---
|
|
484
|
+
else if (url === "/api/agents" && method === "GET") {
|
|
485
|
+
res.writeHead(200);
|
|
486
|
+
res.end(JSON.stringify(CANNED_AGENTS_LIST));
|
|
487
|
+
} else if (url === "/api/agents" && method === "POST") {
|
|
488
|
+
res.writeHead(201);
|
|
489
|
+
res.end(JSON.stringify(CANNED_AGENT_DETAIL));
|
|
490
|
+
} else if (url?.match(/^\/api\/agents\/[^/]+$/) && method === "GET") {
|
|
491
|
+
res.writeHead(200);
|
|
492
|
+
res.end(JSON.stringify(CANNED_AGENT_DETAIL));
|
|
493
|
+
} else if (url?.match(/^\/api\/agents\/[^/]+$/) && method === "PATCH") {
|
|
494
|
+
res.writeHead(200);
|
|
495
|
+
res.end(JSON.stringify(CANNED_AGENT_DETAIL));
|
|
496
|
+
} else if (url?.match(/^\/api\/agents\/[^/]+$/) && method === "DELETE") {
|
|
497
|
+
res.writeHead(200);
|
|
498
|
+
res.end(JSON.stringify({ id: "agent_abc", name: "Test Agent" }));
|
|
499
|
+
}
|
|
500
|
+
// --- Suite endpoints ---
|
|
501
|
+
else if (url === "/api/suites" && method === "GET") {
|
|
502
|
+
res.writeHead(200);
|
|
503
|
+
res.end(JSON.stringify(CANNED_SUITES_LIST));
|
|
504
|
+
} else if (url === "/api/suites" && method === "POST") {
|
|
505
|
+
res.writeHead(201);
|
|
506
|
+
res.end(JSON.stringify(CANNED_SUITE_CREATED));
|
|
507
|
+
} else if (url?.match(/^\/api\/suites\/[^/]+\/run$/) && method === "POST") {
|
|
508
|
+
res.writeHead(200);
|
|
509
|
+
res.end(JSON.stringify(CANNED_SUITE_RUN));
|
|
510
|
+
} else if (url?.match(/^\/api\/suites\/[^/]+\/duplicate$/) && method === "POST") {
|
|
511
|
+
res.writeHead(201);
|
|
512
|
+
res.end(JSON.stringify(CANNED_SUITE_CREATED));
|
|
513
|
+
} else if (url?.match(/^\/api\/suites\/[^/]+$/) && method === "GET") {
|
|
514
|
+
res.writeHead(200);
|
|
515
|
+
res.end(JSON.stringify(CANNED_SUITE_DETAIL));
|
|
516
|
+
} else if (url?.match(/^\/api\/suites\/[^/]+$/) && method === "PATCH") {
|
|
517
|
+
res.writeHead(200);
|
|
518
|
+
res.end(JSON.stringify(CANNED_SUITE_DETAIL));
|
|
519
|
+
} else if (url?.match(/^\/api\/suites\/[^/]+$/) && method === "DELETE") {
|
|
520
|
+
res.writeHead(200);
|
|
521
|
+
res.end(JSON.stringify({ id: "suite_abc", archived: true }));
|
|
522
|
+
}
|
|
523
|
+
// --- Simulation Run endpoints ---
|
|
524
|
+
else if (url?.match(/^\/api\/simulation-runs\/[^/]+$/) && method === "GET") {
|
|
525
|
+
res.writeHead(200);
|
|
526
|
+
res.end(JSON.stringify(CANNED_SIMULATION_RUN_DETAIL));
|
|
527
|
+
} else if (url?.match(/^\/api\/simulation-runs/) && method === "GET") {
|
|
528
|
+
res.writeHead(200);
|
|
529
|
+
res.end(JSON.stringify(CANNED_SIMULATION_RUNS));
|
|
530
|
+
}
|
|
531
|
+
// --- Dashboard endpoints ---
|
|
532
|
+
else if (url === "/api/dashboards" && method === "GET") {
|
|
533
|
+
res.writeHead(200);
|
|
534
|
+
res.end(JSON.stringify(CANNED_DASHBOARDS_LIST));
|
|
535
|
+
} else if (url === "/api/dashboards" && method === "POST") {
|
|
536
|
+
res.writeHead(201);
|
|
537
|
+
res.end(JSON.stringify({ id: "dash_new", name: "New Dashboard" }));
|
|
538
|
+
} else if (url?.match(/^\/api\/dashboards\/[^/]+$/) && method === "GET") {
|
|
539
|
+
res.writeHead(200);
|
|
540
|
+
res.end(JSON.stringify(CANNED_DASHBOARDS_LIST.data[0]));
|
|
541
|
+
} else if (url?.match(/^\/api\/dashboards\/[^/]+$/) && method === "DELETE") {
|
|
542
|
+
res.writeHead(200);
|
|
543
|
+
res.end(JSON.stringify({ id: "dash_abc", name: "Main Dashboard" }));
|
|
544
|
+
}
|
|
545
|
+
// --- Workflow endpoints ---
|
|
546
|
+
else if (url === "/api/workflows" && method === "GET") {
|
|
547
|
+
res.writeHead(200);
|
|
548
|
+
res.end(JSON.stringify(CANNED_WORKFLOWS_LIST));
|
|
549
|
+
} else if (url?.match(/^\/api\/workflows\/[^/]+\/run$/) && method === "POST") {
|
|
550
|
+
res.writeHead(200);
|
|
551
|
+
res.end(JSON.stringify({ output: "workflow result" }));
|
|
552
|
+
} else if (url?.match(/^\/api\/workflows\/[^/]+$/) && method === "GET") {
|
|
553
|
+
res.writeHead(200);
|
|
554
|
+
res.end(JSON.stringify(CANNED_WORKFLOWS_LIST[0]));
|
|
555
|
+
} else if (url?.match(/^\/api\/workflows\/[^/]+$/) && method === "DELETE") {
|
|
556
|
+
res.writeHead(200);
|
|
557
|
+
res.end(JSON.stringify({ id: "wf_abc", archived: true }));
|
|
558
|
+
}
|
|
559
|
+
// --- Monitor endpoints ---
|
|
560
|
+
else if (url === "/api/monitors" && method === "GET") {
|
|
561
|
+
res.writeHead(200);
|
|
562
|
+
res.end(JSON.stringify([
|
|
563
|
+
{ id: "mon_abc", name: "Toxicity Check", slug: "toxicity-check-x1y2z", checkType: "ragas/toxicity", enabled: true, executionMode: "ON_MESSAGE", sample: 1.0, level: "trace", evaluatorId: null, preconditions: [], parameters: {}, mappings: {}, threadIdleTimeout: null, createdAt: "2026-01-01T00:00:00Z", updatedAt: "2026-01-01T00:00:00Z" },
|
|
564
|
+
]));
|
|
565
|
+
} else if (url === "/api/monitors" && method === "POST") {
|
|
566
|
+
res.writeHead(201);
|
|
567
|
+
res.end(JSON.stringify({ id: "mon_new", name: "New Monitor", slug: "new-monitor-abc12", checkType: "ragas/toxicity", enabled: true, executionMode: "ON_MESSAGE", sample: 1.0, level: "trace", evaluatorId: null, preconditions: [], parameters: {}, mappings: {}, threadIdleTimeout: null, createdAt: "2026-01-01T00:00:00Z", updatedAt: "2026-01-01T00:00:00Z" }));
|
|
568
|
+
} else if (url?.match(/^\/api\/monitors\/[^/]+\/toggle$/) && method === "POST") {
|
|
569
|
+
const monitorId = url?.split("/")[3];
|
|
570
|
+
res.writeHead(200);
|
|
571
|
+
res.end(JSON.stringify({ id: monitorId, enabled: true }));
|
|
572
|
+
} else if (url?.match(/^\/api\/monitors\/[^/]+$/) && method === "GET") {
|
|
573
|
+
res.writeHead(200);
|
|
574
|
+
res.end(JSON.stringify({ id: "mon_abc", name: "Toxicity Check", slug: "toxicity-check-x1y2z", checkType: "ragas/toxicity", enabled: true, executionMode: "ON_MESSAGE", sample: 1.0, level: "trace", evaluatorId: null, preconditions: [], parameters: {}, mappings: {}, threadIdleTimeout: null, createdAt: "2026-01-01T00:00:00Z", updatedAt: "2026-01-01T00:00:00Z" }));
|
|
575
|
+
} else if (url?.match(/^\/api\/monitors\/[^/]+$/) && method === "PATCH") {
|
|
576
|
+
res.writeHead(200);
|
|
577
|
+
res.end(JSON.stringify({ id: "mon_abc", name: "Updated Monitor", slug: "toxicity-check-x1y2z", checkType: "ragas/toxicity", enabled: false, executionMode: "ON_MESSAGE", sample: 0.5, level: "trace", evaluatorId: null, preconditions: [], parameters: {}, mappings: {}, threadIdleTimeout: null, createdAt: "2026-01-01T00:00:00Z", updatedAt: "2026-01-02T00:00:00Z" }));
|
|
578
|
+
} else if (url?.match(/^\/api\/monitors\/[^/]+$/) && method === "DELETE") {
|
|
579
|
+
const monitorId = url?.split("/").pop();
|
|
580
|
+
res.writeHead(200);
|
|
581
|
+
res.end(JSON.stringify({ id: monitorId, deleted: true }));
|
|
582
|
+
}
|
|
583
|
+
// --- Secret endpoints ---
|
|
584
|
+
else if (url === "/api/secrets" && method === "GET") {
|
|
585
|
+
res.writeHead(200);
|
|
586
|
+
res.end(JSON.stringify([
|
|
587
|
+
{ id: "secret_abc", projectId: "proj_123", name: "MY_API_KEY", createdAt: "2026-01-01T00:00:00Z", updatedAt: "2026-01-01T00:00:00Z" },
|
|
588
|
+
{ id: "secret_def", projectId: "proj_123", name: "DB_PASSWORD", createdAt: "2026-01-02T00:00:00Z", updatedAt: "2026-01-02T00:00:00Z" },
|
|
589
|
+
]));
|
|
590
|
+
} else if (url === "/api/secrets" && method === "POST") {
|
|
591
|
+
res.writeHead(201);
|
|
592
|
+
res.end(JSON.stringify({ id: "secret_new", projectId: "proj_123", name: "NEW_SECRET", createdAt: "2026-01-03T00:00:00Z", updatedAt: "2026-01-03T00:00:00Z" }));
|
|
593
|
+
} else if (url?.match(/^\/api\/secrets\/[^/]+$/) && method === "PUT") {
|
|
594
|
+
res.writeHead(200);
|
|
595
|
+
res.end(JSON.stringify({ id: "secret_abc", projectId: "proj_123", name: "MY_API_KEY", createdAt: "2026-01-01T00:00:00Z", updatedAt: "2026-01-03T00:00:00Z" }));
|
|
596
|
+
} else if (url?.match(/^\/api\/secrets\/[^/]+$/) && method === "DELETE") {
|
|
597
|
+
const secretId = url?.split("/").pop();
|
|
598
|
+
res.writeHead(200);
|
|
599
|
+
res.end(JSON.stringify({ id: secretId, deleted: true }));
|
|
600
|
+
}
|
|
439
601
|
// --- Fallback ---
|
|
440
602
|
else {
|
|
441
603
|
res.writeHead(404);
|
|
@@ -1334,4 +1496,186 @@ describe("All MCP tools integration", () => {
|
|
|
1334
1496
|
await expect(handleListModelProviders()).rejects.toThrow("401");
|
|
1335
1497
|
});
|
|
1336
1498
|
});
|
|
1499
|
+
|
|
1500
|
+
// =====================
|
|
1501
|
+
// Suite Tools
|
|
1502
|
+
// =====================
|
|
1503
|
+
describe("platform_list_suites", () => {
|
|
1504
|
+
it("returns formatted suite list", async () => {
|
|
1505
|
+
const { handleListSuites } = await import("../tools/list-suites.js");
|
|
1506
|
+
const result = await handleListSuites({});
|
|
1507
|
+
|
|
1508
|
+
expect(result).toContain("Suites / Run Plans (1 total)");
|
|
1509
|
+
expect(result).toContain("Regression Suite");
|
|
1510
|
+
});
|
|
1511
|
+
});
|
|
1512
|
+
|
|
1513
|
+
describe("platform_get_suite", () => {
|
|
1514
|
+
it("returns suite details", async () => {
|
|
1515
|
+
const { handleGetSuite } = await import("../tools/get-suite.js");
|
|
1516
|
+
const result = await handleGetSuite({ id: "suite_abc" });
|
|
1517
|
+
|
|
1518
|
+
expect(result).toContain("Regression Suite");
|
|
1519
|
+
expect(result).toContain("suite_abc");
|
|
1520
|
+
});
|
|
1521
|
+
});
|
|
1522
|
+
|
|
1523
|
+
describe("platform_create_suite", () => {
|
|
1524
|
+
it("creates a suite and returns confirmation", async () => {
|
|
1525
|
+
const { handleCreateSuite } = await import("../tools/create-suite.js");
|
|
1526
|
+
const result = await handleCreateSuite({
|
|
1527
|
+
name: "New Suite",
|
|
1528
|
+
scenarioIds: ["scen_abc123"],
|
|
1529
|
+
targets: JSON.stringify([{ type: "http", referenceId: "agent_abc" }]),
|
|
1530
|
+
});
|
|
1531
|
+
|
|
1532
|
+
expect(result).toContain("created successfully");
|
|
1533
|
+
expect(result).toContain("New Suite");
|
|
1534
|
+
});
|
|
1535
|
+
});
|
|
1536
|
+
|
|
1537
|
+
describe("platform_run_suite", () => {
|
|
1538
|
+
it("triggers a suite run and returns batch info", async () => {
|
|
1539
|
+
const { handleRunSuite } = await import("../tools/run-suite.js");
|
|
1540
|
+
const result = await handleRunSuite({ id: "suite_abc" });
|
|
1541
|
+
|
|
1542
|
+
expect(result).toContain("scheduled successfully");
|
|
1543
|
+
expect(result).toContain("batch_123");
|
|
1544
|
+
});
|
|
1545
|
+
});
|
|
1546
|
+
|
|
1547
|
+
describe("platform_archive_suite", () => {
|
|
1548
|
+
it("archives the suite", async () => {
|
|
1549
|
+
const { handleArchiveSuite } = await import("../tools/archive-suite.js");
|
|
1550
|
+
const result = await handleArchiveSuite({ id: "suite_abc" });
|
|
1551
|
+
|
|
1552
|
+
expect(result).toContain("archived");
|
|
1553
|
+
});
|
|
1554
|
+
});
|
|
1555
|
+
|
|
1556
|
+
// =====================
|
|
1557
|
+
// Simulation Run Tools
|
|
1558
|
+
// =====================
|
|
1559
|
+
describe("platform_list_simulation_runs", () => {
|
|
1560
|
+
it("returns formatted run list", async () => {
|
|
1561
|
+
const { handleListSimulationRuns } = await import("../tools/list-simulation-runs.js");
|
|
1562
|
+
const result = await handleListSimulationRuns({});
|
|
1563
|
+
|
|
1564
|
+
expect(result).toContain("Simulation Runs");
|
|
1565
|
+
expect(result).toContain("Login Flow");
|
|
1566
|
+
});
|
|
1567
|
+
});
|
|
1568
|
+
|
|
1569
|
+
describe("platform_get_simulation_run", () => {
|
|
1570
|
+
it("returns run details with conversation", async () => {
|
|
1571
|
+
const { handleGetSimulationRun } = await import("../tools/get-simulation-run.js");
|
|
1572
|
+
const result = await handleGetSimulationRun({ scenarioRunId: "run_abc" });
|
|
1573
|
+
|
|
1574
|
+
expect(result).toContain("Login Flow");
|
|
1575
|
+
expect(result).toContain("passed");
|
|
1576
|
+
expect(result).toContain("Hello");
|
|
1577
|
+
});
|
|
1578
|
+
});
|
|
1579
|
+
|
|
1580
|
+
// =====================
|
|
1581
|
+
// Monitor Tools
|
|
1582
|
+
// =====================
|
|
1583
|
+
describe("platform_list_monitors", () => {
|
|
1584
|
+
it("returns formatted monitor list", async () => {
|
|
1585
|
+
const { listMonitors } = await import("../langwatch-api-monitors.js");
|
|
1586
|
+
const monitors = await listMonitors();
|
|
1587
|
+
expect(monitors).toHaveLength(1);
|
|
1588
|
+
expect(monitors[0]!.name).toBe("Toxicity Check");
|
|
1589
|
+
expect(monitors[0]!.checkType).toBe("ragas/toxicity");
|
|
1590
|
+
});
|
|
1591
|
+
});
|
|
1592
|
+
|
|
1593
|
+
describe("platform_get_monitor", () => {
|
|
1594
|
+
it("returns monitor details", async () => {
|
|
1595
|
+
const { getMonitor } = await import("../langwatch-api-monitors.js");
|
|
1596
|
+
const monitor = await getMonitor("mon_abc");
|
|
1597
|
+
expect(monitor.id).toBe("mon_abc");
|
|
1598
|
+
expect(monitor.name).toBe("Toxicity Check");
|
|
1599
|
+
expect(monitor.enabled).toBe(true);
|
|
1600
|
+
});
|
|
1601
|
+
});
|
|
1602
|
+
|
|
1603
|
+
describe("platform_create_monitor", () => {
|
|
1604
|
+
it("creates a monitor and returns metadata", async () => {
|
|
1605
|
+
const { createMonitor } = await import("../langwatch-api-monitors.js");
|
|
1606
|
+
const monitor = await createMonitor({ name: "New Monitor", checkType: "ragas/toxicity" });
|
|
1607
|
+
expect(monitor.id).toBe("mon_new");
|
|
1608
|
+
expect(monitor.name).toBe("New Monitor");
|
|
1609
|
+
});
|
|
1610
|
+
});
|
|
1611
|
+
|
|
1612
|
+
describe("platform_update_monitor", () => {
|
|
1613
|
+
it("updates a monitor", async () => {
|
|
1614
|
+
const { updateMonitor } = await import("../langwatch-api-monitors.js");
|
|
1615
|
+
const monitor = await updateMonitor({ id: "mon_abc", enabled: false });
|
|
1616
|
+
expect(monitor.id).toBe("mon_abc");
|
|
1617
|
+
expect(monitor.enabled).toBe(false);
|
|
1618
|
+
});
|
|
1619
|
+
});
|
|
1620
|
+
|
|
1621
|
+
describe("platform_delete_monitor", () => {
|
|
1622
|
+
it("deletes a monitor", async () => {
|
|
1623
|
+
const { deleteMonitor } = await import("../langwatch-api-monitors.js");
|
|
1624
|
+
const result = await deleteMonitor("mon_abc");
|
|
1625
|
+
expect(result.id).toBe("mon_abc");
|
|
1626
|
+
expect(result.deleted).toBe(true);
|
|
1627
|
+
});
|
|
1628
|
+
});
|
|
1629
|
+
|
|
1630
|
+
// =====================
|
|
1631
|
+
// Secret Tools
|
|
1632
|
+
// =====================
|
|
1633
|
+
describe("platform_list_secrets", () => {
|
|
1634
|
+
it("returns formatted secret list", async () => {
|
|
1635
|
+
const { listSecrets } = await import("../langwatch-api-secrets.js");
|
|
1636
|
+
const secrets = await listSecrets();
|
|
1637
|
+
expect(secrets).toHaveLength(2);
|
|
1638
|
+
expect(secrets[0]!.name).toBe("MY_API_KEY");
|
|
1639
|
+
});
|
|
1640
|
+
});
|
|
1641
|
+
|
|
1642
|
+
describe("platform_create_secret", () => {
|
|
1643
|
+
it("creates a secret and returns metadata", async () => {
|
|
1644
|
+
const { createSecret } = await import("../langwatch-api-secrets.js");
|
|
1645
|
+
const secret = await createSecret({ name: "NEW_SECRET", value: "sk-123" });
|
|
1646
|
+
expect(secret.id).toBe("secret_new");
|
|
1647
|
+
expect(secret.name).toBe("NEW_SECRET");
|
|
1648
|
+
});
|
|
1649
|
+
});
|
|
1650
|
+
|
|
1651
|
+
describe("platform_update_secret", () => {
|
|
1652
|
+
it("updates a secret value", async () => {
|
|
1653
|
+
const { updateSecret } = await import("../langwatch-api-secrets.js");
|
|
1654
|
+
const secret = await updateSecret({ id: "secret_abc", value: "new-val" });
|
|
1655
|
+
expect(secret.id).toBe("secret_abc");
|
|
1656
|
+
expect(secret.name).toBe("MY_API_KEY");
|
|
1657
|
+
});
|
|
1658
|
+
});
|
|
1659
|
+
|
|
1660
|
+
describe("platform_delete_secret", () => {
|
|
1661
|
+
it("deletes a secret", async () => {
|
|
1662
|
+
const { deleteSecret } = await import("../langwatch-api-secrets.js");
|
|
1663
|
+
const result = await deleteSecret("secret_abc");
|
|
1664
|
+
expect(result.id).toBe("secret_abc");
|
|
1665
|
+
expect(result.deleted).toBe(true);
|
|
1666
|
+
});
|
|
1667
|
+
});
|
|
1668
|
+
|
|
1669
|
+
// =====================
|
|
1670
|
+
// Agent Run Tool
|
|
1671
|
+
// =====================
|
|
1672
|
+
describe("platform_run_workflow", () => {
|
|
1673
|
+
it("executes a workflow and returns result", async () => {
|
|
1674
|
+
const { handleRunWorkflow } = await import("../tools/run-workflow.js");
|
|
1675
|
+
const result = await handleRunWorkflow({ id: "wf_abc" });
|
|
1676
|
+
|
|
1677
|
+
expect(result).toContain("executed successfully");
|
|
1678
|
+
expect(result).toContain("workflow result");
|
|
1679
|
+
});
|
|
1680
|
+
});
|
|
1337
1681
|
});
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { describe, it, expect, beforeEach, afterEach, vi } from "vitest";
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
initConfig,
|
|
4
|
+
getConfig,
|
|
5
|
+
requireApiKey,
|
|
6
|
+
runWithConfig,
|
|
7
|
+
} from "../config.js";
|
|
3
8
|
|
|
4
9
|
describe("config", () => {
|
|
5
10
|
let originalApiKey: string | undefined;
|
|
@@ -81,9 +86,84 @@ describe("config", () => {
|
|
|
81
86
|
|
|
82
87
|
describe("getConfig", () => {
|
|
83
88
|
it("throws when config has not been initialized", async () => {
|
|
89
|
+
// globalThis survives vi.resetModules(), so clear it explicitly
|
|
90
|
+
delete (globalThis as Record<string, unknown>).__langwatch_mcp_config;
|
|
91
|
+
delete (globalThis as Record<string, unknown>).__langwatch_mcp_config_storage;
|
|
84
92
|
vi.resetModules();
|
|
85
93
|
const freshConfig = await import("../config.js");
|
|
86
94
|
expect(() => freshConfig.getConfig()).toThrow("Config not initialized");
|
|
87
95
|
});
|
|
88
96
|
});
|
|
97
|
+
|
|
98
|
+
describe("runWithConfig()", () => {
|
|
99
|
+
it("overrides global config within the callback", () => {
|
|
100
|
+
initConfig({ apiKey: "global-key" });
|
|
101
|
+
|
|
102
|
+
runWithConfig(
|
|
103
|
+
{ apiKey: "session-key", endpoint: "https://session.example.com" },
|
|
104
|
+
() => {
|
|
105
|
+
expect(getConfig().apiKey).toBe("session-key");
|
|
106
|
+
expect(getConfig().endpoint).toBe("https://session.example.com");
|
|
107
|
+
}
|
|
108
|
+
);
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("restores global config after the callback completes", () => {
|
|
112
|
+
initConfig({ apiKey: "global-key" });
|
|
113
|
+
|
|
114
|
+
runWithConfig(
|
|
115
|
+
{ apiKey: "session-key", endpoint: "https://session.example.com" },
|
|
116
|
+
() => {
|
|
117
|
+
// inside: session config
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
expect(getConfig().apiKey).toBe("global-key");
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it("isolates concurrent async contexts", async () => {
|
|
125
|
+
initConfig({ apiKey: "global-key" });
|
|
126
|
+
|
|
127
|
+
const results: string[] = [];
|
|
128
|
+
|
|
129
|
+
await Promise.all([
|
|
130
|
+
runWithConfig(
|
|
131
|
+
{ apiKey: "key-a", endpoint: "https://a.example.com" },
|
|
132
|
+
async () => {
|
|
133
|
+
await new Promise((r) => setTimeout(r, 10));
|
|
134
|
+
results.push(requireApiKey());
|
|
135
|
+
}
|
|
136
|
+
),
|
|
137
|
+
runWithConfig(
|
|
138
|
+
{ apiKey: "key-b", endpoint: "https://b.example.com" },
|
|
139
|
+
async () => {
|
|
140
|
+
await new Promise((r) => setTimeout(r, 5));
|
|
141
|
+
results.push(requireApiKey());
|
|
142
|
+
}
|
|
143
|
+
),
|
|
144
|
+
]);
|
|
145
|
+
|
|
146
|
+
expect(results).toContain("key-a");
|
|
147
|
+
expect(results).toContain("key-b");
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it("returns the callback result", () => {
|
|
151
|
+
initConfig({});
|
|
152
|
+
const result = runWithConfig(
|
|
153
|
+
{ apiKey: "key", endpoint: "https://example.com" },
|
|
154
|
+
() => 42
|
|
155
|
+
);
|
|
156
|
+
expect(result).toBe(42);
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it("makes requireApiKey() use the scoped key", () => {
|
|
160
|
+
initConfig({});
|
|
161
|
+
runWithConfig(
|
|
162
|
+
{ apiKey: "scoped-key", endpoint: "https://example.com" },
|
|
163
|
+
() => {
|
|
164
|
+
expect(requireApiKey()).toBe("scoped-key");
|
|
165
|
+
}
|
|
166
|
+
);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
89
169
|
});
|