@langwatch/mcp-server 0.6.1 → 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 +23 -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
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { DatasetMutationResponse } from "../langwatch-api-datasets.js";
|
|
2
|
+
import { escapeMarkdown } from "../utils/escape-markdown.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Formats the common detail lines for a dataset mutation response
|
|
6
|
+
* (name, slug, id, and column types).
|
|
7
|
+
*
|
|
8
|
+
* Used by both create-dataset and update-dataset handlers to avoid
|
|
9
|
+
* duplicating the formatting logic.
|
|
10
|
+
*/
|
|
11
|
+
export function formatDatasetMutationDetails(
|
|
12
|
+
result: DatasetMutationResponse,
|
|
13
|
+
): string[] {
|
|
14
|
+
const lines: string[] = [];
|
|
15
|
+
lines.push(`**Name**: ${escapeMarkdown(result.name)}`);
|
|
16
|
+
lines.push(`**Slug**: ${escapeMarkdown(result.slug)}`);
|
|
17
|
+
lines.push(`**ID**: ${escapeMarkdown(result.id)}`);
|
|
18
|
+
if (Array.isArray(result.columnTypes) && result.columnTypes.length > 0) {
|
|
19
|
+
const colNames = result.columnTypes
|
|
20
|
+
.map((c) => `${escapeMarkdown(c.name)} (${escapeMarkdown(c.type)})`)
|
|
21
|
+
.join(", ");
|
|
22
|
+
lines.push(`**Columns**: ${colNames}`);
|
|
23
|
+
}
|
|
24
|
+
return lines;
|
|
25
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { getAgent as apiGetAgent } from "../langwatch-api-agents.js";
|
|
2
|
+
|
|
3
|
+
export async function handleGetAgent(params: { id: string }): Promise<string> {
|
|
4
|
+
const agent = await apiGetAgent(params.id);
|
|
5
|
+
|
|
6
|
+
const lines: string[] = [];
|
|
7
|
+
lines.push(`# ${agent.name}\n`);
|
|
8
|
+
lines.push(`**ID**: ${agent.id}`);
|
|
9
|
+
lines.push(`**Type**: ${agent.type}`);
|
|
10
|
+
lines.push(`**Created**: ${agent.createdAt}`);
|
|
11
|
+
lines.push(`**Updated**: ${agent.updatedAt}`);
|
|
12
|
+
|
|
13
|
+
if (agent.config && Object.keys(agent.config).length > 0) {
|
|
14
|
+
lines.push("\n## Config\n");
|
|
15
|
+
lines.push("```json");
|
|
16
|
+
lines.push(JSON.stringify(agent.config, null, 2));
|
|
17
|
+
lines.push("```");
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return lines.join("\n");
|
|
21
|
+
}
|
|
@@ -1,6 +1,20 @@
|
|
|
1
|
+
import type { AnalyticsBucket } from "../langwatch-api.js";
|
|
1
2
|
import { getAnalyticsTimeseries as apiGetAnalytics } from "../langwatch-api.js";
|
|
2
3
|
import { parseRelativeDate } from "../utils/date-parsing.js";
|
|
3
4
|
|
|
5
|
+
type GroupedData = Record<string, Record<string, number>>;
|
|
6
|
+
|
|
7
|
+
function getGroupedData(
|
|
8
|
+
bucket: AnalyticsBucket,
|
|
9
|
+
groupBy: string,
|
|
10
|
+
): GroupedData | undefined {
|
|
11
|
+
const data = bucket[groupBy];
|
|
12
|
+
if (typeof data === "object" && data !== null && !Array.isArray(data)) {
|
|
13
|
+
return data as GroupedData;
|
|
14
|
+
}
|
|
15
|
+
return undefined;
|
|
16
|
+
}
|
|
17
|
+
|
|
4
18
|
/**
|
|
5
19
|
* Handles the get_analytics MCP tool invocation.
|
|
6
20
|
*
|
|
@@ -49,17 +63,30 @@ export async function handleGetAnalytics(params: {
|
|
|
49
63
|
const currentPeriod = result.currentPeriod ?? [];
|
|
50
64
|
if (currentPeriod.length === 0) {
|
|
51
65
|
lines.push("No data available for this period.");
|
|
66
|
+
} else if (
|
|
67
|
+
params.groupBy &&
|
|
68
|
+
currentPeriod.some((b) => getGroupedData(b, params.groupBy!) !== undefined)
|
|
69
|
+
) {
|
|
70
|
+
lines.push("| Date | Group | Value |");
|
|
71
|
+
lines.push("|------|-------|-------|");
|
|
72
|
+
for (const bucket of currentPeriod) {
|
|
73
|
+
const groups = getGroupedData(bucket, params.groupBy);
|
|
74
|
+
if (!groups) continue;
|
|
75
|
+
for (const [groupKey, metrics] of Object.entries(groups)) {
|
|
76
|
+
const value =
|
|
77
|
+
Object.values(metrics).find((v) => typeof v === "number") ?? "N/A";
|
|
78
|
+
lines.push(`| ${bucket.date} | ${groupKey} | ${value} |`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
52
81
|
} else {
|
|
53
82
|
lines.push("| Date | Value |");
|
|
54
83
|
lines.push("|------|-------|");
|
|
55
84
|
for (const bucket of currentPeriod) {
|
|
56
|
-
const date = bucket.date;
|
|
57
|
-
// Find the metric value - it's typically keyed by index
|
|
58
85
|
const value =
|
|
59
86
|
Object.entries(bucket).find(
|
|
60
87
|
([k]) => k !== "date" && typeof bucket[k] === "number"
|
|
61
88
|
)?.[1] ?? "N/A";
|
|
62
|
-
lines.push(`| ${date} | ${value} |`);
|
|
89
|
+
lines.push(`| ${bucket.date} | ${value} |`);
|
|
63
90
|
}
|
|
64
91
|
}
|
|
65
92
|
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { getDashboard as apiGetDashboard } from "../langwatch-api-dashboards.js";
|
|
2
|
+
|
|
3
|
+
export async function handleGetDashboard(params: { id: string }): Promise<string> {
|
|
4
|
+
const dashboard = await apiGetDashboard(params.id);
|
|
5
|
+
|
|
6
|
+
const lines: string[] = [];
|
|
7
|
+
lines.push(`# ${dashboard.name}\n`);
|
|
8
|
+
lines.push(`**ID**: ${dashboard.id}`);
|
|
9
|
+
lines.push(`**Order**: ${dashboard.order}`);
|
|
10
|
+
lines.push(`**Graphs**: ${Array.isArray(dashboard.graphs) ? dashboard.graphs.length : 0}`);
|
|
11
|
+
lines.push(`**Created**: ${dashboard.createdAt}`);
|
|
12
|
+
lines.push(`**Updated**: ${dashboard.updatedAt}`);
|
|
13
|
+
|
|
14
|
+
if (Array.isArray(dashboard.graphs) && dashboard.graphs.length > 0) {
|
|
15
|
+
lines.push("\n## Graphs\n");
|
|
16
|
+
lines.push("```json");
|
|
17
|
+
lines.push(JSON.stringify(dashboard.graphs, null, 2));
|
|
18
|
+
lines.push("```");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return lines.join("\n");
|
|
22
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getDataset as apiGetDataset,
|
|
3
|
+
type DatasetDetailResponse,
|
|
4
|
+
} from "../langwatch-api-datasets.js";
|
|
5
|
+
import { escapeMarkdown } from "../utils/escape-markdown.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Formats a dataset detail response into AI-readable markdown.
|
|
9
|
+
*
|
|
10
|
+
* Exported for unit testing.
|
|
11
|
+
*/
|
|
12
|
+
export function formatDatasetResponse(
|
|
13
|
+
dataset: DatasetDetailResponse,
|
|
14
|
+
): string {
|
|
15
|
+
const lines: string[] = [];
|
|
16
|
+
lines.push(`# Dataset: ${escapeMarkdown(dataset.name)}\n`);
|
|
17
|
+
lines.push(`**Slug**: ${escapeMarkdown(dataset.slug)}`);
|
|
18
|
+
lines.push(`**ID**: ${escapeMarkdown(dataset.id)}`);
|
|
19
|
+
|
|
20
|
+
// Column table
|
|
21
|
+
if (
|
|
22
|
+
Array.isArray(dataset.columnTypes) &&
|
|
23
|
+
dataset.columnTypes.length > 0
|
|
24
|
+
) {
|
|
25
|
+
lines.push("\n## Columns\n");
|
|
26
|
+
lines.push("| Name | Type |");
|
|
27
|
+
lines.push("|------|------|");
|
|
28
|
+
for (const col of dataset.columnTypes) {
|
|
29
|
+
lines.push(`| ${escapeMarkdown(col.name)} | ${escapeMarkdown(col.type)} |`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
// Record preview
|
|
34
|
+
if (Array.isArray(dataset.data) && dataset.data.length > 0) {
|
|
35
|
+
lines.push(`\n## Records (${dataset.data.length} shown)\n`);
|
|
36
|
+
for (const record of dataset.data) {
|
|
37
|
+
lines.push(`**${escapeMarkdown(record.id)}**: ${escapeMarkdown(JSON.stringify(record.entry))}`);
|
|
38
|
+
}
|
|
39
|
+
} else {
|
|
40
|
+
lines.push("\nNo records in this dataset.");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return lines.join("\n");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Handles the platform_get_dataset MCP tool invocation.
|
|
48
|
+
*
|
|
49
|
+
* Retrieves a specific dataset by slug or ID and formats it as
|
|
50
|
+
* AI-readable markdown or raw JSON.
|
|
51
|
+
*/
|
|
52
|
+
export async function handleGetDataset(params: {
|
|
53
|
+
slugOrId: string;
|
|
54
|
+
format?: "digest" | "json";
|
|
55
|
+
}): Promise<string> {
|
|
56
|
+
const dataset = await apiGetDataset(params.slugOrId);
|
|
57
|
+
|
|
58
|
+
if (params.format === "json") {
|
|
59
|
+
return JSON.stringify(dataset, null, 2);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
return formatDatasetResponse(dataset);
|
|
63
|
+
}
|
package/src/tools/get-prompt.ts
CHANGED
|
@@ -9,8 +9,9 @@ import { getPrompt as apiGetPrompt } from "../langwatch-api.js";
|
|
|
9
9
|
export async function handleGetPrompt(params: {
|
|
10
10
|
idOrHandle: string;
|
|
11
11
|
version?: number;
|
|
12
|
+
tag?: string;
|
|
12
13
|
}): Promise<string> {
|
|
13
|
-
const prompt = await apiGetPrompt(params.idOrHandle, params.version);
|
|
14
|
+
const prompt = await apiGetPrompt(params.idOrHandle, { version: params.version, tag: params.tag });
|
|
14
15
|
|
|
15
16
|
const lines: string[] = [];
|
|
16
17
|
lines.push(
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { getSimulationRun as apiGetSimulationRun } from "../langwatch-api-simulation-runs.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Handles the platform_get_simulation_run MCP tool invocation.
|
|
5
|
+
*/
|
|
6
|
+
export async function handleGetSimulationRun(params: {
|
|
7
|
+
scenarioRunId: string;
|
|
8
|
+
format?: "digest" | "json";
|
|
9
|
+
}): Promise<string> {
|
|
10
|
+
const run = await apiGetSimulationRun(params.scenarioRunId);
|
|
11
|
+
|
|
12
|
+
if (params.format === "json") {
|
|
13
|
+
return JSON.stringify(run, null, 2);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const lines: string[] = [];
|
|
17
|
+
lines.push(`# Simulation Run: ${run.name ?? run.scenarioRunId}\n`);
|
|
18
|
+
lines.push(`**Run ID**: ${run.scenarioRunId}`);
|
|
19
|
+
lines.push(`**Scenario ID**: ${run.scenarioId}`);
|
|
20
|
+
lines.push(`**Batch ID**: ${run.batchRunId}`);
|
|
21
|
+
lines.push(`**Status**: ${run.status}`);
|
|
22
|
+
|
|
23
|
+
const duration = run.durationInMs > 0 ? `${(run.durationInMs / 1000).toFixed(1)}s` : "—";
|
|
24
|
+
lines.push(`**Duration**: ${duration}`);
|
|
25
|
+
if (run.totalCost) {
|
|
26
|
+
lines.push(`**Cost**: $${run.totalCost.toFixed(4)}`);
|
|
27
|
+
}
|
|
28
|
+
lines.push(`**Started**: ${new Date(run.timestamp).toISOString()}`);
|
|
29
|
+
|
|
30
|
+
if (run.results) {
|
|
31
|
+
lines.push("\n## Results");
|
|
32
|
+
if (run.results.verdict) {
|
|
33
|
+
lines.push(`**Verdict**: ${run.results.verdict}`);
|
|
34
|
+
}
|
|
35
|
+
if (run.results.reasoning) {
|
|
36
|
+
lines.push(`**Reasoning**: ${run.results.reasoning}`);
|
|
37
|
+
}
|
|
38
|
+
if (run.results.metCriteria && run.results.metCriteria.length > 0) {
|
|
39
|
+
lines.push(`**Met Criteria**: ${run.results.metCriteria.join(", ")}`);
|
|
40
|
+
}
|
|
41
|
+
if (run.results.unmetCriteria && run.results.unmetCriteria.length > 0) {
|
|
42
|
+
lines.push(`**Unmet Criteria**: ${run.results.unmetCriteria.join(", ")}`);
|
|
43
|
+
}
|
|
44
|
+
if (run.results.error) {
|
|
45
|
+
lines.push(`**Error**: ${run.results.error}`);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
if (run.messages && run.messages.length > 0) {
|
|
50
|
+
lines.push("\n## Conversation");
|
|
51
|
+
for (const msg of run.messages) {
|
|
52
|
+
const content = msg.content.length > 300
|
|
53
|
+
? msg.content.slice(0, 300) + "..."
|
|
54
|
+
: msg.content;
|
|
55
|
+
lines.push(`**[${msg.role}]**: ${content}`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return lines.join("\n");
|
|
60
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { getSuite as apiGetSuite } from "../langwatch-api-suites.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Handles the platform_get_suite MCP tool invocation.
|
|
5
|
+
*/
|
|
6
|
+
export async function handleGetSuite(params: {
|
|
7
|
+
id: string;
|
|
8
|
+
format?: "digest" | "json";
|
|
9
|
+
}): Promise<string> {
|
|
10
|
+
const suite = await apiGetSuite(params.id);
|
|
11
|
+
|
|
12
|
+
if (params.format === "json") {
|
|
13
|
+
return JSON.stringify(suite, null, 2);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const lines: string[] = [];
|
|
17
|
+
lines.push(`# Suite: ${suite.name}\n`);
|
|
18
|
+
lines.push(`**ID**: ${suite.id}`);
|
|
19
|
+
lines.push(`**Slug**: ${suite.slug}`);
|
|
20
|
+
lines.push(`**Description**: ${suite.description ?? "—"}`);
|
|
21
|
+
lines.push(`**Repeat Count**: ${suite.repeatCount}`);
|
|
22
|
+
lines.push(`**Created**: ${suite.createdAt}`);
|
|
23
|
+
lines.push(`**Updated**: ${suite.updatedAt}`);
|
|
24
|
+
|
|
25
|
+
if (suite.labels.length > 0) {
|
|
26
|
+
lines.push(`**Labels**: ${suite.labels.join(", ")}`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
lines.push("\n## Scenarios");
|
|
30
|
+
for (const id of suite.scenarioIds) {
|
|
31
|
+
lines.push(`- ${id}`);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
lines.push("\n## Targets");
|
|
35
|
+
for (const t of suite.targets) {
|
|
36
|
+
lines.push(`- ${t.type}:${t.referenceId}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
const totalJobs = suite.scenarioIds.length * suite.targets.length * suite.repeatCount;
|
|
40
|
+
lines.push(`\n**Total jobs per run**: ${totalJobs}`);
|
|
41
|
+
|
|
42
|
+
lines.push(
|
|
43
|
+
"\n> Use `platform_run_suite` to trigger a run, or `platform_update_suite` to modify."
|
|
44
|
+
);
|
|
45
|
+
|
|
46
|
+
return lines.join("\n");
|
|
47
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { getWorkflow as apiGetWorkflow } from "../langwatch-api-workflows.js";
|
|
2
|
+
|
|
3
|
+
export async function handleGetWorkflow(params: { id: string }): Promise<string> {
|
|
4
|
+
const workflow = await apiGetWorkflow(params.id);
|
|
5
|
+
|
|
6
|
+
const lines: string[] = [];
|
|
7
|
+
lines.push(`# ${workflow.name}\n`);
|
|
8
|
+
lines.push(`**ID**: ${workflow.id}`);
|
|
9
|
+
if (workflow.description) lines.push(`**Description**: ${workflow.description}`);
|
|
10
|
+
if (workflow.icon) lines.push(`**Icon**: ${workflow.icon}`);
|
|
11
|
+
lines.push(`**Evaluator**: ${workflow.isEvaluator ? "yes" : "no"}`);
|
|
12
|
+
lines.push(`**Component**: ${workflow.isComponent ? "yes" : "no"}`);
|
|
13
|
+
lines.push(`**Created**: ${workflow.createdAt}`);
|
|
14
|
+
lines.push(`**Updated**: ${workflow.updatedAt}`);
|
|
15
|
+
|
|
16
|
+
return lines.join("\n");
|
|
17
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { listAgents as apiListAgents } from "../langwatch-api-agents.js";
|
|
2
|
+
|
|
3
|
+
export async function handleListAgents(): Promise<string> {
|
|
4
|
+
const result = await apiListAgents({ limit: 100 });
|
|
5
|
+
const agents = result.data;
|
|
6
|
+
|
|
7
|
+
if (!Array.isArray(agents) || agents.length === 0) {
|
|
8
|
+
return "No agents found in this project.\n\n> Tip: Use `platform_create_agent` to create your first agent.";
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const lines: string[] = [];
|
|
12
|
+
lines.push(`# Agents (${result.pagination.total} total)\n`);
|
|
13
|
+
|
|
14
|
+
for (const a of agents) {
|
|
15
|
+
lines.push(`## ${a.name}`);
|
|
16
|
+
lines.push(`**ID**: ${a.id}`);
|
|
17
|
+
lines.push(`**Type**: ${a.type}`);
|
|
18
|
+
lines.push(`**Updated**: ${a.updatedAt}`);
|
|
19
|
+
lines.push("");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
lines.push(
|
|
23
|
+
"> Use `platform_get_agent` with the ID to see full agent details including config.",
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
return lines.join("\n");
|
|
27
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import {
|
|
2
|
+
listAnnotations as apiListAnnotations,
|
|
3
|
+
getAnnotationsByTrace as apiGetByTrace,
|
|
4
|
+
} from "../langwatch-api-annotations.js";
|
|
5
|
+
|
|
6
|
+
export async function handleListAnnotations(params: {
|
|
7
|
+
traceId?: string;
|
|
8
|
+
}): Promise<string> {
|
|
9
|
+
const annotations = params.traceId
|
|
10
|
+
? await apiGetByTrace(params.traceId)
|
|
11
|
+
: await apiListAnnotations();
|
|
12
|
+
|
|
13
|
+
if (!Array.isArray(annotations) || annotations.length === 0) {
|
|
14
|
+
return params.traceId
|
|
15
|
+
? `No annotations found for trace "${params.traceId}".\n\n> Tip: Use \`platform_create_annotation\` to annotate a trace.`
|
|
16
|
+
: "No annotations found in this project.\n\n> Tip: Use `platform_create_annotation` to annotate a trace.";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const lines: string[] = [];
|
|
20
|
+
lines.push(`# Annotations (${annotations.length} total)\n`);
|
|
21
|
+
|
|
22
|
+
for (const a of annotations) {
|
|
23
|
+
const rating = a.isThumbsUp === true ? "👍" : a.isThumbsUp === false ? "👎" : "—";
|
|
24
|
+
lines.push(`## Annotation ${a.id ?? "—"}`);
|
|
25
|
+
lines.push(`**Trace ID**: ${a.traceId ?? "—"}`);
|
|
26
|
+
lines.push(`**Rating**: ${rating}`);
|
|
27
|
+
if (a.comment) lines.push(`**Comment**: ${a.comment}`);
|
|
28
|
+
if (a.email) lines.push(`**By**: ${a.email}`);
|
|
29
|
+
lines.push("");
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return lines.join("\n");
|
|
33
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { listDashboards as apiListDashboards } from "../langwatch-api-dashboards.js";
|
|
2
|
+
|
|
3
|
+
export async function handleListDashboards(): Promise<string> {
|
|
4
|
+
const result = await apiListDashboards();
|
|
5
|
+
const dashboards = result.data;
|
|
6
|
+
|
|
7
|
+
if (!Array.isArray(dashboards) || dashboards.length === 0) {
|
|
8
|
+
return "No dashboards found in this project.\n\n> Tip: Use `platform_create_dashboard` to create a new dashboard.";
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const lines: string[] = [];
|
|
12
|
+
lines.push(`# Dashboards (${dashboards.length} total)\n`);
|
|
13
|
+
|
|
14
|
+
for (const d of dashboards) {
|
|
15
|
+
lines.push(`## ${d.name}`);
|
|
16
|
+
lines.push(`**ID**: ${d.id}`);
|
|
17
|
+
lines.push(`**Graphs**: ${d.graphCount}`);
|
|
18
|
+
lines.push(`**Updated**: ${d.updatedAt}`);
|
|
19
|
+
lines.push("");
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
lines.push(
|
|
23
|
+
"> Use `platform_get_dashboard` with the ID to see dashboard details including graphs.",
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
return lines.join("\n");
|
|
27
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import {
|
|
2
|
+
listDatasetRecords as apiListDatasetRecords,
|
|
3
|
+
} from "../langwatch-api-datasets.js";
|
|
4
|
+
import { escapeMarkdown } from "../utils/escape-markdown.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Handles the platform_list_dataset_records MCP tool invocation.
|
|
8
|
+
*
|
|
9
|
+
* Lists records in a dataset with pagination support.
|
|
10
|
+
*/
|
|
11
|
+
export async function handleListDatasetRecords(params: {
|
|
12
|
+
slugOrId: string;
|
|
13
|
+
page?: number;
|
|
14
|
+
limit?: number;
|
|
15
|
+
format?: "digest" | "json";
|
|
16
|
+
}): Promise<string> {
|
|
17
|
+
const response = await apiListDatasetRecords({
|
|
18
|
+
slugOrId: params.slugOrId,
|
|
19
|
+
page: params.page,
|
|
20
|
+
limit: params.limit,
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
if (params.format === "json") {
|
|
24
|
+
return JSON.stringify(response, null, 2);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const { data: records, pagination } = response;
|
|
28
|
+
|
|
29
|
+
if (records.length === 0) {
|
|
30
|
+
return "No records found in this dataset.";
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const lines: string[] = [];
|
|
34
|
+
lines.push(`# Records (page ${pagination.page} of ${pagination.totalPages}, ${pagination.total} total)\n`);
|
|
35
|
+
|
|
36
|
+
for (const record of records) {
|
|
37
|
+
lines.push(`**${escapeMarkdown(record.id)}**: ${escapeMarkdown(JSON.stringify(record.entry))}`);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
if (pagination.page < pagination.totalPages) {
|
|
41
|
+
lines.push("");
|
|
42
|
+
lines.push(`> Use \`platform_list_dataset_records\` with \`page: ${pagination.page + 1}\` to see the next page.`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return lines.join("\n");
|
|
46
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import {
|
|
2
|
+
listDatasets as apiListDatasets,
|
|
3
|
+
type DatasetSummary,
|
|
4
|
+
} from "../langwatch-api-datasets.js";
|
|
5
|
+
import { escapeMarkdown } from "../utils/escape-markdown.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Fetches all datasets by paginating through the API until every page
|
|
9
|
+
* has been retrieved.
|
|
10
|
+
*
|
|
11
|
+
* Returns the accumulated dataset summaries along with the total count
|
|
12
|
+
* reported by the server.
|
|
13
|
+
*/
|
|
14
|
+
async function fetchAllDatasets(): Promise<{
|
|
15
|
+
datasets: DatasetSummary[];
|
|
16
|
+
total: number;
|
|
17
|
+
}> {
|
|
18
|
+
const PAGE_SIZE = 100;
|
|
19
|
+
const datasets: DatasetSummary[] = [];
|
|
20
|
+
let page = 1;
|
|
21
|
+
let total = 0;
|
|
22
|
+
|
|
23
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition -- loop until break
|
|
24
|
+
while (true) {
|
|
25
|
+
const response = await apiListDatasets({ page, limit: PAGE_SIZE });
|
|
26
|
+
total = response.pagination.total;
|
|
27
|
+
datasets.push(...response.data);
|
|
28
|
+
|
|
29
|
+
if (datasets.length >= total || response.data.length === 0) {
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
page++;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return { datasets, total };
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Handles the platform_list_datasets MCP tool invocation.
|
|
40
|
+
*
|
|
41
|
+
* Lists all datasets in the LangWatch project, formatted as an
|
|
42
|
+
* AI-readable digest or raw JSON.
|
|
43
|
+
*/
|
|
44
|
+
export async function handleListDatasets(params: {
|
|
45
|
+
format?: "digest" | "json";
|
|
46
|
+
} = {}): Promise<string> {
|
|
47
|
+
if (params.format === "json") {
|
|
48
|
+
const { datasets, total } = await fetchAllDatasets();
|
|
49
|
+
return JSON.stringify({ data: datasets, total }, null, 2);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const { datasets, total } = await fetchAllDatasets();
|
|
53
|
+
|
|
54
|
+
if (datasets.length === 0) {
|
|
55
|
+
return "No datasets found in this project.\n\n> Tip: Use `platform_create_dataset` to create your first dataset.";
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const lines: string[] = [];
|
|
59
|
+
lines.push(`# Datasets (${total} total)\n`);
|
|
60
|
+
|
|
61
|
+
for (const ds of datasets) {
|
|
62
|
+
lines.push(`## ${escapeMarkdown(ds.name)}`);
|
|
63
|
+
lines.push(`**Slug**: ${escapeMarkdown(ds.slug)}`);
|
|
64
|
+
lines.push(`**ID**: ${ds.id}`);
|
|
65
|
+
if (Array.isArray(ds.columnTypes) && ds.columnTypes.length > 0) {
|
|
66
|
+
const colNames = ds.columnTypes.map((c) => c.name).join(", ");
|
|
67
|
+
lines.push(`**Columns**: ${colNames}`);
|
|
68
|
+
}
|
|
69
|
+
lines.push(
|
|
70
|
+
`**Records**: ${ds.recordCount ?? "unknown"}`,
|
|
71
|
+
);
|
|
72
|
+
lines.push("");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
lines.push(
|
|
76
|
+
"> Use `platform_get_dataset` with the slug to see full dataset details and records.",
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
return lines.join("\n");
|
|
80
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { listPromptTags as apiListPromptTags } from "../langwatch-api.js";
|
|
2
|
+
|
|
3
|
+
export async function handleListPromptTags(): Promise<string> {
|
|
4
|
+
const tags = (await apiListPromptTags()) as Array<{
|
|
5
|
+
id: string;
|
|
6
|
+
name: string;
|
|
7
|
+
createdAt?: string;
|
|
8
|
+
}>;
|
|
9
|
+
|
|
10
|
+
if (!tags || tags.length === 0) {
|
|
11
|
+
return "No prompt tags found. The `latest` tag is always available.";
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const lines: string[] = [];
|
|
15
|
+
lines.push("# Prompt Tags\n");
|
|
16
|
+
for (const tag of tags) {
|
|
17
|
+
const created = tag.createdAt ? ` (created ${tag.createdAt})` : "";
|
|
18
|
+
lines.push(`- **${tag.name}**${created}`);
|
|
19
|
+
}
|
|
20
|
+
return lines.join("\n");
|
|
21
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { listSimulationRuns as apiListSimulationRuns } from "../langwatch-api-simulation-runs.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Handles the platform_list_simulation_runs MCP tool invocation.
|
|
5
|
+
*/
|
|
6
|
+
export async function handleListSimulationRuns(params: {
|
|
7
|
+
scenarioSetId?: string;
|
|
8
|
+
batchRunId?: string;
|
|
9
|
+
limit?: number;
|
|
10
|
+
format?: "digest" | "json";
|
|
11
|
+
}): Promise<string> {
|
|
12
|
+
const result = await apiListSimulationRuns({
|
|
13
|
+
scenarioSetId: params.scenarioSetId,
|
|
14
|
+
batchRunId: params.batchRunId,
|
|
15
|
+
limit: params.limit,
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
if (params.format === "json") {
|
|
19
|
+
return JSON.stringify(result, null, 2);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const { runs } = result;
|
|
23
|
+
|
|
24
|
+
if (runs.length === 0) {
|
|
25
|
+
return "No simulation runs found.\n\n> Run a suite first with `platform_run_suite` to create simulation runs.";
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const lines: string[] = [];
|
|
29
|
+
lines.push(`# Simulation Runs (${runs.length} results${result.hasMore ? ", more available" : ""})\n`);
|
|
30
|
+
|
|
31
|
+
for (const run of runs) {
|
|
32
|
+
const statusIcon = run.status === "SUCCESS" ? "pass" : run.status === "FAILED" ? "FAIL" : run.status;
|
|
33
|
+
const duration = run.durationInMs > 0 ? `${(run.durationInMs / 1000).toFixed(1)}s` : "—";
|
|
34
|
+
const verdict = run.results?.verdict ?? "";
|
|
35
|
+
|
|
36
|
+
lines.push(`## ${run.name ?? run.scenarioId} — ${statusIcon}${verdict ? ` (${verdict})` : ""}`);
|
|
37
|
+
lines.push(`**Run ID**: ${run.scenarioRunId}`);
|
|
38
|
+
lines.push(`**Batch**: ${run.batchRunId}`);
|
|
39
|
+
lines.push(`**Duration**: ${duration}`);
|
|
40
|
+
if (run.totalCost) {
|
|
41
|
+
lines.push(`**Cost**: $${run.totalCost.toFixed(4)}`);
|
|
42
|
+
}
|
|
43
|
+
lines.push("");
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
lines.push("> Use `platform_get_simulation_run` with a run ID to see full details (messages, results).");
|
|
47
|
+
|
|
48
|
+
return lines.join("\n");
|
|
49
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { listSuites as apiListSuites } from "../langwatch-api-suites.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Handles the platform_list_suites MCP tool invocation.
|
|
5
|
+
*/
|
|
6
|
+
export async function handleListSuites(params: {
|
|
7
|
+
format?: "digest" | "json";
|
|
8
|
+
}): Promise<string> {
|
|
9
|
+
const suites = await apiListSuites();
|
|
10
|
+
|
|
11
|
+
if (params.format === "json") {
|
|
12
|
+
return JSON.stringify(suites, null, 2);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
if (!Array.isArray(suites) || suites.length === 0) {
|
|
16
|
+
return "No suites (run plans) found in this project.\n\n> Tip: Use `platform_create_suite` to create your first suite.";
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const lines: string[] = [];
|
|
20
|
+
lines.push(`# Suites / Run Plans (${suites.length} total)\n`);
|
|
21
|
+
|
|
22
|
+
for (const s of suites) {
|
|
23
|
+
lines.push(`## ${s.name}`);
|
|
24
|
+
lines.push(`**ID**: ${s.id}`);
|
|
25
|
+
lines.push(`**Slug**: ${s.slug}`);
|
|
26
|
+
lines.push(`**Scenarios**: ${s.scenarioIds.length}`);
|
|
27
|
+
lines.push(`**Targets**: ${s.targets.length} (${s.targets.map((t) => `${t.type}:${t.referenceId}`).join(", ")})`);
|
|
28
|
+
lines.push(`**Repeat**: ${s.repeatCount}x`);
|
|
29
|
+
if (s.description) {
|
|
30
|
+
lines.push(`**Description**: ${s.description}`);
|
|
31
|
+
}
|
|
32
|
+
if (Array.isArray(s.labels) && s.labels.length > 0) {
|
|
33
|
+
lines.push(`**Labels**: ${s.labels.join(", ")}`);
|
|
34
|
+
}
|
|
35
|
+
lines.push("");
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
lines.push(
|
|
39
|
+
"> Use `platform_get_suite` with the ID to see full details, or `platform_run_suite` to trigger execution."
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
return lines.join("\n");
|
|
43
|
+
}
|