@langwatch/mcp-server 0.8.0 → 0.10.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 +40 -0
- package/LICENSE +7 -0
- package/dist/archive-project-HZBRPR2S.js +19 -0
- package/dist/{archive-scenario-YKGLJ4MZ.js → archive-scenario-P5RRITRM.js} +3 -3
- package/dist/{archive-suite-QFNDO3Y3.js → archive-suite-NUUFD2EM.js} +3 -3
- package/dist/{assign-prompt-tag-Y2B4CBBT.js → assign-prompt-tag-FKCCZPML.js} +2 -2
- package/dist/{chunk-YH2IBTEL.js → chunk-42ZHHHIJ.js} +14 -3
- package/dist/chunk-ADSJ2FDA.js +44 -0
- package/dist/{chunk-L6QENXYA.js → chunk-BB7EOKHR.js} +2 -2
- package/dist/chunk-BBJ5WAJB.js +24 -0
- package/dist/{chunk-PZUWCWOS.js → chunk-BYWYM2RP.js} +2 -2
- package/dist/{chunk-NACSR6B7.js → chunk-CCM4ZFGF.js} +2 -2
- package/dist/{chunk-FBRKHHJV.js → chunk-CHKCEZBP.js} +2 -2
- package/dist/{chunk-B57MZ4WI.js → chunk-FVDAZ4XG.js} +763 -90
- package/dist/{chunk-PO7FM7IX.js → chunk-HKY3GW45.js} +2 -2
- package/dist/{chunk-KZNBCKWG.js → chunk-JHOSVOHT.js} +2 -2
- package/dist/{chunk-HDJDFKZR.js → chunk-R7C7OUVG.js} +2 -2
- package/dist/{chunk-OVQF3D5R.js → chunk-TROIWSEQ.js} +2 -2
- package/dist/{chunk-CPUPGDNA.js → chunk-X2SEURT2.js} +2 -2
- package/dist/{chunk-YI3OG4PI.js → chunk-XC62KJIT.js} +3 -3
- package/dist/{create-agent-YRSDH7P7.js → create-agent-K5Q7BFGZ.js} +3 -3
- package/dist/{create-annotation-FYQNKMVJ.js → create-annotation-KN3GE3DK.js} +3 -3
- package/dist/create-api-key-OQI5PUNQ.js +26 -0
- package/dist/{create-dashboard-CORBR4YQ.js → create-dashboard-G4QA5AXP.js} +3 -3
- package/dist/{create-dataset-ZC63T6BB.js → create-dataset-WQSC37N7.js} +3 -3
- package/dist/{create-dataset-records-ILVNVKVR.js → create-dataset-records-B4RL3FLC.js} +3 -3
- package/dist/{create-evaluator-2AU3PXFB.js → create-evaluator-YFFQIR7E.js} +3 -3
- package/dist/create-mcp-server.d.ts +3 -1
- package/dist/create-mcp-server.js +2 -1
- package/dist/create-project-CUVQ67VN.js +44 -0
- package/dist/{create-prompt-NKRJ47YY.js → create-prompt-NGXKSP4X.js} +2 -2
- package/dist/{create-prompt-tag-S4JX3ULL.js → create-prompt-tag-IUKYPVHH.js} +2 -2
- package/dist/{create-scenario-BPRF75KF.js → create-scenario-FNBXALH3.js} +3 -3
- package/dist/{create-suite-4YN7D6K2.js → create-suite-DJEPD4ZB.js} +3 -3
- package/dist/{delete-agent-Y72R2YQA.js → delete-agent-TJI5XBBM.js} +3 -3
- package/dist/{delete-annotation-UHWDMHSH.js → delete-annotation-KRP53TUU.js} +3 -3
- package/dist/{delete-dashboard-LPWT36KN.js → delete-dashboard-N5SZJIR3.js} +3 -3
- package/dist/{delete-dataset-GGPQRHKX.js → delete-dataset-KDUOHL2P.js} +3 -3
- package/dist/{delete-dataset-records-LTG5LT26.js → delete-dataset-records-DM4W3PAW.js} +3 -3
- package/dist/{delete-evaluator-F7QLXDHU.js → delete-evaluator-7ZATLJOA.js} +3 -3
- package/dist/{delete-prompt-tag-B5UKZL45.js → delete-prompt-tag-I6HNMSVJ.js} +2 -2
- package/dist/{delete-workflow-4DGUDIDE.js → delete-workflow-QEO74JQR.js} +3 -3
- package/dist/{get-agent-YEVICUX4.js → get-agent-3KDWCP5N.js} +3 -3
- package/dist/{get-analytics-3W5CMU3F.js → get-analytics-GPVJX7SF.js} +2 -2
- package/dist/{get-dashboard-NCQHN6MW.js → get-dashboard-YPTIE5YY.js} +3 -3
- package/dist/{get-dataset-KBK6PH36.js → get-dataset-6DQFYITM.js} +3 -3
- package/dist/{get-evaluator-QDUL5LXR.js → get-evaluator-PCM6XQAU.js} +3 -3
- package/dist/get-project-JCMWXVLU.js +26 -0
- package/dist/{get-prompt-XCSSNRKR.js → get-prompt-5XAGWWBG.js} +2 -2
- package/dist/{get-scenario-FNRKOY7E.js → get-scenario-7XBCDZWX.js} +3 -3
- package/dist/{get-simulation-run-WOEKUF7K.js → get-simulation-run-AV24FJWI.js} +3 -3
- package/dist/{get-suite-U5AOD5TC.js → get-suite-4DBVHFEM.js} +3 -3
- package/dist/{get-trace-MUWEJM2Z.js → get-trace-MRBDS3HJ.js} +2 -2
- package/dist/{get-workflow-SOA7MT7L.js → get-workflow-UR4Y6UFX.js} +3 -3
- package/dist/{http-server-7DMOCB75.js → http-server-XUQLIFE7.js} +5 -3
- package/dist/index.js +1175 -222
- package/dist/{langwatch-api-annotations-Q57NDUVR.js → langwatch-api-annotations-ZJDRB4JH.js} +3 -3
- package/dist/{langwatch-api-dashboards-VBWWXV3Y.js → langwatch-api-dashboards-WARLI6NF.js} +3 -3
- package/dist/{langwatch-api-monitors-L3IY7FDT.js → langwatch-api-monitors-4XKXHYCG.js} +2 -2
- package/dist/{langwatch-api-secrets-S5HHF3XR.js → langwatch-api-secrets-6SHK5G7Q.js} +2 -2
- package/dist/{langwatch-api-triggers-ME33QE26.js → langwatch-api-triggers-5SX6R2WU.js} +2 -2
- package/dist/{langwatch-api-workflows-4CJQAYP2.js → langwatch-api-workflows-NLJENNXE.js} +3 -3
- package/dist/{list-agents-3HGIBJFM.js → list-agents-NECO7MPI.js} +3 -3
- package/dist/{list-annotations-KWXYVEPI.js → list-annotations-3OJEO774.js} +3 -3
- package/dist/list-api-keys-AWW7ROLB.js +37 -0
- package/dist/{list-dashboards-VQ2LH666.js → list-dashboards-DVPVVVKW.js} +3 -3
- package/dist/{list-dataset-records-RNRGROJP.js → list-dataset-records-I4BYORF5.js} +3 -3
- package/dist/{list-datasets-I4A2LT2S.js → list-datasets-WUAE5HGX.js} +3 -3
- package/dist/{list-evaluators-AKKRJ5MX.js → list-evaluators-B6OSVAM2.js} +3 -3
- package/dist/{list-model-providers-DVFEHFHZ.js → list-model-providers-NL6IP4UZ.js} +3 -3
- package/dist/list-projects-5FHMJ4PQ.js +42 -0
- package/dist/{list-prompt-tags-PL5OISUA.js → list-prompt-tags-Z2DD6FLQ.js} +2 -2
- package/dist/{list-prompts-7VTFWE2Z.js → list-prompts-VNXKHK7T.js} +2 -2
- package/dist/{list-scenarios-5BZWZ6ZN.js → list-scenarios-CFZHXL76.js} +3 -3
- package/dist/{list-simulation-runs-WCZ6RLPE.js → list-simulation-runs-AM2BXLBW.js} +3 -3
- package/dist/{list-suites-RRQ2JX5Y.js → list-suites-ZDOHAAXF.js} +3 -3
- package/dist/{list-workflows-UQB5FCX5.js → list-workflows-WBRBKLIT.js} +3 -3
- package/dist/{rename-prompt-tag-TURD6KYU.js → rename-prompt-tag-A4RJUK7Z.js} +2 -2
- package/dist/revoke-api-key-ZSPSPF5G.js +15 -0
- package/dist/{run-agent-BEJ4K4CM.js → run-agent-JFNDY7MR.js} +3 -3
- package/dist/{run-suite-U7V432G2.js → run-suite-TH7LO5TJ.js} +3 -3
- package/dist/{run-workflow-5WX7DK5T.js → run-workflow-CK3JP5U2.js} +3 -3
- package/dist/{search-traces-ZCHNOMTX.js → search-traces-3BBVYPC3.js} +2 -2
- package/dist/{set-model-provider-6CFHMCNE.js → set-model-provider-WOC5FNMV.js} +3 -3
- package/dist/{update-agent-UE6UWLZP.js → update-agent-YMEV5MTL.js} +3 -3
- package/dist/{update-dataset-4XQZZE4S.js → update-dataset-EYT5POFM.js} +3 -3
- package/dist/{update-dataset-record-GNNM5TKM.js → update-dataset-record-VFF5JTX4.js} +3 -3
- package/dist/{update-evaluator-LHVDXIZD.js → update-evaluator-6IJHFG2E.js} +3 -3
- package/dist/update-project-OIT4WPFI.js +24 -0
- package/dist/{update-prompt-3XEHECJ7.js → update-prompt-ZU2DD6KM.js} +2 -2
- package/dist/{update-scenario-DFPREYCD.js → update-scenario-3VUTPDRU.js} +3 -3
- package/dist/{update-suite-RATU5THO.js → update-suite-C6JFDQHL.js} +3 -3
- package/package.json +2 -2
- package/pnpm-workspace.yaml +7 -0
- package/pyproject.toml +3 -0
- package/src/__tests__/experiment-list-tools.unit.test.ts +157 -0
- package/src/__tests__/experiment-status.unit.test.ts +194 -0
- package/src/__tests__/get-experiment-results.unit.test.ts +313 -0
- package/src/__tests__/project-api-key-tools.unit.test.ts +451 -0
- package/src/create-mcp-server.d.ts +3 -1
- package/src/create-mcp-server.ts +263 -13
- package/src/http-server.ts +5 -0
- package/src/langwatch-api-api-keys.ts +54 -0
- package/src/langwatch-api-projects.ts +82 -0
- package/src/langwatch-api.ts +17 -3
- package/src/tools/archive-project.ts +14 -0
- package/src/tools/create-api-key.ts +29 -0
- package/src/tools/create-project.ts +45 -0
- package/src/tools/experiment-run-status.ts +36 -0
- package/src/tools/get-experiment-results.ts +306 -0
- package/src/tools/get-project.ts +20 -0
- package/src/tools/list-api-keys.ts +33 -0
- package/src/tools/list-experiment-runs.ts +142 -0
- package/src/tools/list-experiments.ts +95 -0
- package/src/tools/list-projects.ts +41 -0
- package/src/tools/revoke-api-key.ts +9 -0
- package/src/tools/run-experiment.ts +182 -0
- package/src/tools/update-project.ts +22 -0
- package/uv.lock +7 -3
- package/dist/run-evaluation-AJ7WZNQD.js +0 -64
- package/src/tools/run-evaluation.ts +0 -87
package/dist/index.js
CHANGED
|
@@ -31109,7 +31109,7 @@ var init_package = __esm({
|
|
|
31109
31109
|
"package.json"() {
|
|
31110
31110
|
package_default = {
|
|
31111
31111
|
name: "@langwatch/mcp-server",
|
|
31112
|
-
version: "0.
|
|
31112
|
+
version: "0.10.0",
|
|
31113
31113
|
description: "An MCP server for Langwatch.",
|
|
31114
31114
|
type: "module",
|
|
31115
31115
|
main: "./dist/index.js",
|
|
@@ -31160,7 +31160,7 @@ var init_package = __esm({
|
|
|
31160
31160
|
"@types/node": "^25.6.0",
|
|
31161
31161
|
"@types/yargs": "^17.0.33",
|
|
31162
31162
|
"@typescript/native-preview": "7.0.0-dev.20250911.1",
|
|
31163
|
-
ai: "^6.0.
|
|
31163
|
+
ai: "^6.0.161",
|
|
31164
31164
|
dotenv: "^17.2.2",
|
|
31165
31165
|
esbuild: "^0.25.0",
|
|
31166
31166
|
eslint: "^10.2.1",
|
|
@@ -31187,8 +31187,7 @@ var init_package = __esm({
|
|
|
31187
31187
|
},
|
|
31188
31188
|
pnpm: {
|
|
31189
31189
|
overrides: {
|
|
31190
|
-
|
|
31191
|
-
"fast-uri@<3.1.2": "3.1.2"
|
|
31190
|
+
liquidjs: ">=10.26.0"
|
|
31192
31191
|
}
|
|
31193
31192
|
}
|
|
31194
31193
|
};
|
|
@@ -31227,6 +31226,644 @@ var init_create_dataset = __esm({
|
|
|
31227
31226
|
}
|
|
31228
31227
|
});
|
|
31229
31228
|
|
|
31229
|
+
// src/langwatch-api.ts
|
|
31230
|
+
async function makeRequest(method, path, body) {
|
|
31231
|
+
const config2 = getConfig();
|
|
31232
|
+
const url2 = config2.endpoint + path;
|
|
31233
|
+
const headers = {
|
|
31234
|
+
"X-Auth-Token": requireApiKey()
|
|
31235
|
+
};
|
|
31236
|
+
if (config2.projectId) {
|
|
31237
|
+
headers["X-Project-Id"] = config2.projectId;
|
|
31238
|
+
}
|
|
31239
|
+
if (body !== void 0) {
|
|
31240
|
+
headers["Content-Type"] = "application/json";
|
|
31241
|
+
}
|
|
31242
|
+
const response = await fetch(url2, {
|
|
31243
|
+
method,
|
|
31244
|
+
headers,
|
|
31245
|
+
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
31246
|
+
});
|
|
31247
|
+
if (!response.ok) {
|
|
31248
|
+
const responseBody = await response.text();
|
|
31249
|
+
throw new LangWatchApiError(
|
|
31250
|
+
`LangWatch API error ${response.status}: ${responseBody}`,
|
|
31251
|
+
response.status,
|
|
31252
|
+
responseBody
|
|
31253
|
+
);
|
|
31254
|
+
}
|
|
31255
|
+
if (response.status === 204 || response.headers?.get("content-length") === "0") {
|
|
31256
|
+
return null;
|
|
31257
|
+
}
|
|
31258
|
+
return response.json();
|
|
31259
|
+
}
|
|
31260
|
+
async function searchTraces(params) {
|
|
31261
|
+
const { format: format3 = "digest", ...rest } = params;
|
|
31262
|
+
return makeRequest("POST", "/api/traces/search", {
|
|
31263
|
+
...rest,
|
|
31264
|
+
format: format3
|
|
31265
|
+
});
|
|
31266
|
+
}
|
|
31267
|
+
async function getTraceById(traceId, format3 = "digest") {
|
|
31268
|
+
return makeRequest(
|
|
31269
|
+
"GET",
|
|
31270
|
+
`/api/traces/${encodeURIComponent(traceId)}?format=${format3}`
|
|
31271
|
+
);
|
|
31272
|
+
}
|
|
31273
|
+
async function getAnalyticsTimeseries(params) {
|
|
31274
|
+
return makeRequest(
|
|
31275
|
+
"POST",
|
|
31276
|
+
"/api/analytics/timeseries",
|
|
31277
|
+
params
|
|
31278
|
+
);
|
|
31279
|
+
}
|
|
31280
|
+
async function listPrompts() {
|
|
31281
|
+
return makeRequest("GET", "/api/prompts");
|
|
31282
|
+
}
|
|
31283
|
+
async function getPrompt(idOrHandle, options) {
|
|
31284
|
+
const params = new URLSearchParams();
|
|
31285
|
+
if (options?.version != null) params.set("version", String(options.version));
|
|
31286
|
+
if (options?.tag) params.set("tag", options.tag);
|
|
31287
|
+
const query = params.toString() ? `?${params}` : "";
|
|
31288
|
+
return makeRequest(
|
|
31289
|
+
"GET",
|
|
31290
|
+
`/api/prompts/${encodeURIComponent(idOrHandle)}${query}`
|
|
31291
|
+
);
|
|
31292
|
+
}
|
|
31293
|
+
async function createPrompt(data) {
|
|
31294
|
+
return makeRequest(
|
|
31295
|
+
"POST",
|
|
31296
|
+
"/api/prompts",
|
|
31297
|
+
data
|
|
31298
|
+
);
|
|
31299
|
+
}
|
|
31300
|
+
async function updatePrompt(idOrHandle, data) {
|
|
31301
|
+
return makeRequest(
|
|
31302
|
+
"PUT",
|
|
31303
|
+
`/api/prompts/${encodeURIComponent(idOrHandle)}`,
|
|
31304
|
+
data
|
|
31305
|
+
);
|
|
31306
|
+
}
|
|
31307
|
+
async function assignPromptTag({
|
|
31308
|
+
idOrHandle,
|
|
31309
|
+
tag,
|
|
31310
|
+
versionId
|
|
31311
|
+
}) {
|
|
31312
|
+
return makeRequest(
|
|
31313
|
+
"PUT",
|
|
31314
|
+
`/api/prompts/${encodeURIComponent(idOrHandle)}/tags/${encodeURIComponent(tag)}`,
|
|
31315
|
+
{ versionId }
|
|
31316
|
+
);
|
|
31317
|
+
}
|
|
31318
|
+
async function listPromptTags() {
|
|
31319
|
+
return makeRequest("GET", "/api/prompts/tags");
|
|
31320
|
+
}
|
|
31321
|
+
async function createPromptTag(name) {
|
|
31322
|
+
return makeRequest("POST", "/api/prompts/tags", { name });
|
|
31323
|
+
}
|
|
31324
|
+
async function renamePromptTag({
|
|
31325
|
+
tag,
|
|
31326
|
+
name
|
|
31327
|
+
}) {
|
|
31328
|
+
return makeRequest(
|
|
31329
|
+
"PUT",
|
|
31330
|
+
`/api/prompts/tags/${encodeURIComponent(tag)}`,
|
|
31331
|
+
{ name }
|
|
31332
|
+
);
|
|
31333
|
+
}
|
|
31334
|
+
async function deletePromptTag(tag) {
|
|
31335
|
+
return makeRequest(
|
|
31336
|
+
"DELETE",
|
|
31337
|
+
`/api/prompts/tags/${encodeURIComponent(tag)}`
|
|
31338
|
+
);
|
|
31339
|
+
}
|
|
31340
|
+
var LangWatchApiError;
|
|
31341
|
+
var init_langwatch_api = __esm({
|
|
31342
|
+
"src/langwatch-api.ts"() {
|
|
31343
|
+
"use strict";
|
|
31344
|
+
init_config();
|
|
31345
|
+
LangWatchApiError = class extends Error {
|
|
31346
|
+
constructor(message, status, responseBody) {
|
|
31347
|
+
super(message);
|
|
31348
|
+
this.status = status;
|
|
31349
|
+
this.responseBody = responseBody;
|
|
31350
|
+
this.name = "LangWatchApiError";
|
|
31351
|
+
}
|
|
31352
|
+
};
|
|
31353
|
+
}
|
|
31354
|
+
});
|
|
31355
|
+
|
|
31356
|
+
// src/tools/experiment-run-status.ts
|
|
31357
|
+
var INTERRUPTED_THRESHOLD_MS, deriveRunStatus, isTerminalStatus;
|
|
31358
|
+
var init_experiment_run_status = __esm({
|
|
31359
|
+
"src/tools/experiment-run-status.ts"() {
|
|
31360
|
+
"use strict";
|
|
31361
|
+
INTERRUPTED_THRESHOLD_MS = 5 * 60 * 1e3;
|
|
31362
|
+
deriveRunStatus = (timestamps, now = Date.now()) => {
|
|
31363
|
+
if (timestamps.stoppedAt != null) return "stopped";
|
|
31364
|
+
if (timestamps.finishedAt != null) return "completed";
|
|
31365
|
+
if (timestamps.updatedAt != null && now - timestamps.updatedAt > INTERRUPTED_THRESHOLD_MS) {
|
|
31366
|
+
return "interrupted";
|
|
31367
|
+
}
|
|
31368
|
+
return "running";
|
|
31369
|
+
};
|
|
31370
|
+
isTerminalStatus = (status) => status === "completed" || status === "stopped";
|
|
31371
|
+
}
|
|
31372
|
+
});
|
|
31373
|
+
|
|
31374
|
+
// src/tools/get-experiment-results.ts
|
|
31375
|
+
async function handleExperimentResults(params) {
|
|
31376
|
+
const filter = params.filter ?? "all";
|
|
31377
|
+
const evaluatorFilter = params.evaluator?.trim();
|
|
31378
|
+
const limit = typeof params.limit === "number" && params.limit > 0 ? Math.min(params.limit, DEFAULT_ROW_CAP) : DEFAULT_ROW_CAP;
|
|
31379
|
+
const search = new URLSearchParams();
|
|
31380
|
+
if (params.experimentSlug) search.set("experimentSlug", params.experimentSlug);
|
|
31381
|
+
const qs = search.toString() ? `?${search.toString()}` : "";
|
|
31382
|
+
let results;
|
|
31383
|
+
try {
|
|
31384
|
+
results = await makeRequest(
|
|
31385
|
+
"GET",
|
|
31386
|
+
`/api/experiments/runs/${encodeURIComponent(params.runId)}/results${qs}`
|
|
31387
|
+
);
|
|
31388
|
+
} catch (error48) {
|
|
31389
|
+
const message = error48 instanceof Error ? error48.message : String(error48);
|
|
31390
|
+
const status = error48 instanceof LangWatchApiError ? error48.status : error48 && typeof error48 === "object" && "status" in error48 && typeof error48.status === "number" ? error48.status : void 0;
|
|
31391
|
+
if (status === 404 || status === void 0 && /404|not found/i.test(message)) {
|
|
31392
|
+
return [
|
|
31393
|
+
`# Evaluation Results: ${params.runId}`,
|
|
31394
|
+
"",
|
|
31395
|
+
"**Status**: not found",
|
|
31396
|
+
"",
|
|
31397
|
+
`Could not load results for run \`${params.runId}\`. The run id may be incorrect, or its run state may have expired (Redis keeps it for 24h).`,
|
|
31398
|
+
"",
|
|
31399
|
+
"> Pass `experimentSlug` to load results for runs older than 24h. Discover the slug with `platform_experiment_list`, then `platform_experiment_list_runs` for the run ids."
|
|
31400
|
+
].join("\n");
|
|
31401
|
+
}
|
|
31402
|
+
throw error48;
|
|
31403
|
+
}
|
|
31404
|
+
if (!results) {
|
|
31405
|
+
return [
|
|
31406
|
+
`# Evaluation Results: ${params.runId}`,
|
|
31407
|
+
"",
|
|
31408
|
+
"**Status**: not found",
|
|
31409
|
+
"",
|
|
31410
|
+
`Could not load results for run \`${params.runId}\`.`,
|
|
31411
|
+
"",
|
|
31412
|
+
"> Pass `experimentSlug` if the run is older than 24h. Discover the slug with `platform_experiment_list`, then `platform_experiment_list_runs` to confirm the run id."
|
|
31413
|
+
].join("\n");
|
|
31414
|
+
}
|
|
31415
|
+
const runStatus2 = deriveRunStatus(results.timestamps);
|
|
31416
|
+
const partial2 = !isTerminalStatus(runStatus2);
|
|
31417
|
+
const evaluationsByRow = /* @__PURE__ */ new Map();
|
|
31418
|
+
for (const evaluation of results.evaluations) {
|
|
31419
|
+
if (evaluatorFilter && evaluation.evaluator !== evaluatorFilter) continue;
|
|
31420
|
+
const key = rowKey(evaluation.index, evaluation.targetId);
|
|
31421
|
+
const list = evaluationsByRow.get(key) ?? [];
|
|
31422
|
+
list.push(evaluation);
|
|
31423
|
+
evaluationsByRow.set(key, list);
|
|
31424
|
+
}
|
|
31425
|
+
const evaluatorNames = Array.from(
|
|
31426
|
+
new Set(
|
|
31427
|
+
(evaluatorFilter ? results.evaluations.filter((e) => e.evaluator === evaluatorFilter) : results.evaluations).map((e) => e.evaluator)
|
|
31428
|
+
)
|
|
31429
|
+
);
|
|
31430
|
+
let rows = results.dataset.map((entry) => ({
|
|
31431
|
+
entry,
|
|
31432
|
+
evaluations: evaluationsByRow.get(rowKey(entry.index, entry.targetId)) ?? []
|
|
31433
|
+
}));
|
|
31434
|
+
if (filter === "failed") {
|
|
31435
|
+
rows = rows.filter(
|
|
31436
|
+
(r) => isFailedRow({ entry: r.entry, evaluations: r.evaluations })
|
|
31437
|
+
);
|
|
31438
|
+
}
|
|
31439
|
+
const totalMatching = rows.length;
|
|
31440
|
+
const rowsForSummary = rows;
|
|
31441
|
+
const truncated = rows.length > limit;
|
|
31442
|
+
rows = rows.slice(0, limit);
|
|
31443
|
+
const evaluatorAverages = /* @__PURE__ */ new Map();
|
|
31444
|
+
for (const r of rowsForSummary) {
|
|
31445
|
+
for (const e of r.evaluations) {
|
|
31446
|
+
const stats = evaluatorAverages.get(e.evaluator) ?? {
|
|
31447
|
+
sum: 0,
|
|
31448
|
+
count: 0,
|
|
31449
|
+
passed: 0,
|
|
31450
|
+
failed: 0,
|
|
31451
|
+
errored: 0
|
|
31452
|
+
};
|
|
31453
|
+
if (typeof e.score === "number") {
|
|
31454
|
+
stats.sum += e.score;
|
|
31455
|
+
stats.count += 1;
|
|
31456
|
+
}
|
|
31457
|
+
if (e.status === "error") stats.errored += 1;
|
|
31458
|
+
else if (e.passed === true) stats.passed += 1;
|
|
31459
|
+
else if (e.passed === false) stats.failed += 1;
|
|
31460
|
+
evaluatorAverages.set(e.evaluator, stats);
|
|
31461
|
+
}
|
|
31462
|
+
}
|
|
31463
|
+
const lines = [];
|
|
31464
|
+
lines.push(`# Evaluation Results: ${results.runId}`);
|
|
31465
|
+
lines.push("");
|
|
31466
|
+
lines.push(`**Experiment**: ${results.experimentId}`);
|
|
31467
|
+
lines.push(`**Status**: ${runStatus2}`);
|
|
31468
|
+
if (typeof results.total === "number" && results.total > 0) {
|
|
31469
|
+
lines.push(
|
|
31470
|
+
`**Progress**: ${results.progress ?? results.dataset.length}/${results.total} rows`
|
|
31471
|
+
);
|
|
31472
|
+
}
|
|
31473
|
+
lines.push(`**Total rows**: ${results.dataset.length}`);
|
|
31474
|
+
lines.push(`**Total evaluations**: ${results.evaluations.length}`);
|
|
31475
|
+
if (filter === "failed") {
|
|
31476
|
+
lines.push(`**Filter**: failed only`);
|
|
31477
|
+
}
|
|
31478
|
+
if (evaluatorFilter) {
|
|
31479
|
+
lines.push(`**Evaluator filter**: ${evaluatorFilter}`);
|
|
31480
|
+
}
|
|
31481
|
+
if (partial2) {
|
|
31482
|
+
lines.push("");
|
|
31483
|
+
lines.push(
|
|
31484
|
+
runStatus2 === "interrupted" ? "> These are partial results. The run never sent a finished/stopped marker and has had no updates recently, so it likely was interrupted before completing. The rows below are everything recorded so far." : "> These are partial results. The run is still in progress, so more rows may appear on a later call."
|
|
31485
|
+
);
|
|
31486
|
+
}
|
|
31487
|
+
lines.push("");
|
|
31488
|
+
if (evaluatorAverages.size > 0) {
|
|
31489
|
+
lines.push("## Evaluator Summary");
|
|
31490
|
+
lines.push("");
|
|
31491
|
+
lines.push("| Evaluator | Avg Score | Passed | Failed | Errored |");
|
|
31492
|
+
lines.push("| --- | --- | --- | --- | --- |");
|
|
31493
|
+
for (const [name, stats] of evaluatorAverages) {
|
|
31494
|
+
const avg = stats.count > 0 ? (stats.sum / stats.count).toFixed(3) : "\u2014";
|
|
31495
|
+
lines.push(
|
|
31496
|
+
`| ${name} | ${avg} | ${stats.passed} | ${stats.failed} | ${stats.errored} |`
|
|
31497
|
+
);
|
|
31498
|
+
}
|
|
31499
|
+
lines.push("");
|
|
31500
|
+
}
|
|
31501
|
+
if (rows.length === 0) {
|
|
31502
|
+
if (filter === "failed") {
|
|
31503
|
+
lines.push("_No rows matched the filter._");
|
|
31504
|
+
} else if (runStatus2 === "running") {
|
|
31505
|
+
lines.push(
|
|
31506
|
+
"_No rows recorded yet. The run is still in progress; call again shortly._"
|
|
31507
|
+
);
|
|
31508
|
+
} else if (runStatus2 === "interrupted") {
|
|
31509
|
+
lines.push("_No rows were recorded before the run was interrupted._");
|
|
31510
|
+
} else {
|
|
31511
|
+
lines.push("_No rows recorded for this run._");
|
|
31512
|
+
}
|
|
31513
|
+
return lines.join("\n");
|
|
31514
|
+
}
|
|
31515
|
+
lines.push(
|
|
31516
|
+
`## Rows (${rows.length}${truncated ? ` of ${totalMatching}` : ""})`
|
|
31517
|
+
);
|
|
31518
|
+
lines.push("");
|
|
31519
|
+
for (const { entry, evaluations } of rows) {
|
|
31520
|
+
const summary = summarizeEntry(entry.entry);
|
|
31521
|
+
lines.push(`### Row #${entry.index}${summary ? ` \u2014 ${summary}` : ""}`);
|
|
31522
|
+
if (entry.error) {
|
|
31523
|
+
lines.push(`- **Error**: ${entry.error}`);
|
|
31524
|
+
}
|
|
31525
|
+
if (entry.traceId) {
|
|
31526
|
+
lines.push(`- **Trace ID**: \`${entry.traceId}\``);
|
|
31527
|
+
}
|
|
31528
|
+
if (evaluations.length === 0) {
|
|
31529
|
+
lines.push(
|
|
31530
|
+
evaluatorNames.length === 0 ? "- _No evaluations recorded_" : "- _No evaluations recorded for this row_"
|
|
31531
|
+
);
|
|
31532
|
+
}
|
|
31533
|
+
for (const e of evaluations) {
|
|
31534
|
+
const parts = [`**${e.evaluator}**`];
|
|
31535
|
+
if (e.status === "error") parts.push("status=error");
|
|
31536
|
+
else if (typeof e.score === "number") parts.push(`score=${e.score.toFixed(3)}`);
|
|
31537
|
+
if (typeof e.passed === "boolean") {
|
|
31538
|
+
parts.push(`passed=${e.passed ? "yes" : "no"}`);
|
|
31539
|
+
}
|
|
31540
|
+
if (e.label) parts.push(`label=${e.label}`);
|
|
31541
|
+
lines.push(`- ${parts.join(" \xB7 ")}`);
|
|
31542
|
+
if (e.details) {
|
|
31543
|
+
lines.push(` - details: ${e.details}`);
|
|
31544
|
+
}
|
|
31545
|
+
}
|
|
31546
|
+
lines.push("");
|
|
31547
|
+
}
|
|
31548
|
+
if (truncated) {
|
|
31549
|
+
lines.push(
|
|
31550
|
+
`> Output truncated to ${limit} rows of ${totalMatching} matching to protect the agent's context window. Pass \`limit\` to expand or filter further.`
|
|
31551
|
+
);
|
|
31552
|
+
}
|
|
31553
|
+
return lines.join("\n");
|
|
31554
|
+
}
|
|
31555
|
+
var DEFAULT_ROW_CAP, rowKey, summarizeEntry, isFailedEvaluation, isFailedRow;
|
|
31556
|
+
var init_get_experiment_results = __esm({
|
|
31557
|
+
"src/tools/get-experiment-results.ts"() {
|
|
31558
|
+
"use strict";
|
|
31559
|
+
init_langwatch_api();
|
|
31560
|
+
init_experiment_run_status();
|
|
31561
|
+
DEFAULT_ROW_CAP = 50;
|
|
31562
|
+
rowKey = (index, targetId) => `${index}:${targetId ?? ""}`;
|
|
31563
|
+
summarizeEntry = (entry) => {
|
|
31564
|
+
const candidates = ["input", "question", "query", "prompt", "user"];
|
|
31565
|
+
for (const key of candidates) {
|
|
31566
|
+
const value = entry[key];
|
|
31567
|
+
if (typeof value === "string" && value.length > 0) {
|
|
31568
|
+
return value.length > 80 ? `${value.slice(0, 77)}...` : value;
|
|
31569
|
+
}
|
|
31570
|
+
}
|
|
31571
|
+
return "";
|
|
31572
|
+
};
|
|
31573
|
+
isFailedEvaluation = (e) => e.status === "error" || e.passed === false;
|
|
31574
|
+
isFailedRow = ({
|
|
31575
|
+
entry,
|
|
31576
|
+
evaluations
|
|
31577
|
+
}) => Boolean(entry.error) || evaluations.some(isFailedEvaluation);
|
|
31578
|
+
}
|
|
31579
|
+
});
|
|
31580
|
+
|
|
31581
|
+
// src/tools/list-experiment-runs.ts
|
|
31582
|
+
async function handleExperimentListRuns(params) {
|
|
31583
|
+
const requested = typeof params.limit === "number" && params.limit > 0 ? params.limit : DEFAULT_LIMIT;
|
|
31584
|
+
const effectiveLimit = Math.min(requested, MAX_LIMIT);
|
|
31585
|
+
const search = new URLSearchParams();
|
|
31586
|
+
search.set("experimentSlug", params.experimentSlug);
|
|
31587
|
+
search.set("pageSize", String(effectiveLimit));
|
|
31588
|
+
let result;
|
|
31589
|
+
try {
|
|
31590
|
+
result = await makeRequest(
|
|
31591
|
+
"GET",
|
|
31592
|
+
`/api/experiments/runs?${search.toString()}`
|
|
31593
|
+
);
|
|
31594
|
+
} catch (error48) {
|
|
31595
|
+
const message = error48 instanceof Error ? error48.message : String(error48);
|
|
31596
|
+
if (/404|not found/i.test(message)) {
|
|
31597
|
+
return [
|
|
31598
|
+
`# Evaluation Runs: ${params.experimentSlug}`,
|
|
31599
|
+
"",
|
|
31600
|
+
"**Status**: experiment not found",
|
|
31601
|
+
"",
|
|
31602
|
+
`No experiment with slug \`${params.experimentSlug}\` exists in this project.`,
|
|
31603
|
+
"",
|
|
31604
|
+
"> Run `platform_experiment_list` to discover available experiment slugs."
|
|
31605
|
+
].join("\n");
|
|
31606
|
+
}
|
|
31607
|
+
throw error48;
|
|
31608
|
+
}
|
|
31609
|
+
if (result.runs.length === 0) {
|
|
31610
|
+
return [
|
|
31611
|
+
`# Evaluation Runs: ${result.experimentSlug}`,
|
|
31612
|
+
"",
|
|
31613
|
+
"_This experiment has no runs yet._",
|
|
31614
|
+
"",
|
|
31615
|
+
`> Trigger a run with \`platform_run_experiment\` (slug: \`${result.experimentSlug}\`) to populate this list.`
|
|
31616
|
+
].join("\n");
|
|
31617
|
+
}
|
|
31618
|
+
const lines = [];
|
|
31619
|
+
lines.push(`# Evaluation Runs: ${result.experimentSlug}`);
|
|
31620
|
+
lines.push("");
|
|
31621
|
+
lines.push(
|
|
31622
|
+
`Showing ${result.runs.length} of ${result.pagination.totalHits} run${result.pagination.totalHits === 1 ? "" : "s"}.`
|
|
31623
|
+
);
|
|
31624
|
+
if (result.pagination.hasMore) {
|
|
31625
|
+
lines.push(
|
|
31626
|
+
`> More runs exist beyond this limit. Re-run with a higher \`limit\` (max ${MAX_LIMIT}) if needed.`
|
|
31627
|
+
);
|
|
31628
|
+
}
|
|
31629
|
+
lines.push("");
|
|
31630
|
+
lines.push("| Run ID | Status | Started | Finished | Result |");
|
|
31631
|
+
lines.push("|--------|--------|---------|----------|--------|");
|
|
31632
|
+
for (const run of result.runs) {
|
|
31633
|
+
lines.push(
|
|
31634
|
+
`| \`${run.runId}\` | ${runStatus(run)} | ${formatEpoch(run.timestamps.createdAt)} | ${formatEpoch(run.timestamps.finishedAt ?? null)} | ${passRate(run.summary?.evaluations ?? {})} |`
|
|
31635
|
+
);
|
|
31636
|
+
}
|
|
31637
|
+
lines.push("");
|
|
31638
|
+
lines.push(
|
|
31639
|
+
"> Use `platform_experiment_status <runId>` for live progress, or `platform_experiment_results <runId>` for per-row results."
|
|
31640
|
+
);
|
|
31641
|
+
return lines.join("\n");
|
|
31642
|
+
}
|
|
31643
|
+
var DEFAULT_LIMIT, MAX_LIMIT, formatEpoch, passRate, runStatus;
|
|
31644
|
+
var init_list_experiment_runs = __esm({
|
|
31645
|
+
"src/tools/list-experiment-runs.ts"() {
|
|
31646
|
+
"use strict";
|
|
31647
|
+
init_langwatch_api();
|
|
31648
|
+
DEFAULT_LIMIT = 25;
|
|
31649
|
+
MAX_LIMIT = 100;
|
|
31650
|
+
formatEpoch = (epoch) => {
|
|
31651
|
+
if (!epoch || !Number.isFinite(epoch)) return "\u2014";
|
|
31652
|
+
return new Date(epoch).toISOString().replace("T", " ").slice(0, 19) + " UTC";
|
|
31653
|
+
};
|
|
31654
|
+
passRate = (evaluations) => {
|
|
31655
|
+
const entries = Object.values(evaluations ?? {});
|
|
31656
|
+
if (entries.length === 0) return "\u2014";
|
|
31657
|
+
const passed = entries.filter((e) => typeof e.averagePassed === "number");
|
|
31658
|
+
if (passed.length === 0) {
|
|
31659
|
+
const scored = entries.filter((e) => typeof e.averageScore === "number");
|
|
31660
|
+
if (scored.length === 0) return "\u2014";
|
|
31661
|
+
const avg2 = scored.reduce((sum, e) => sum + (e.averageScore ?? 0), 0) / scored.length;
|
|
31662
|
+
return `${avg2.toFixed(2)} avg`;
|
|
31663
|
+
}
|
|
31664
|
+
const avg = passed.reduce((sum, e) => sum + (e.averagePassed ?? 0), 0) / passed.length;
|
|
31665
|
+
return `${(avg * 100).toFixed(0)}% pass`;
|
|
31666
|
+
};
|
|
31667
|
+
runStatus = (run) => {
|
|
31668
|
+
if (run.timestamps.stoppedAt) return "stopped";
|
|
31669
|
+
if (run.timestamps.finishedAt) return "completed";
|
|
31670
|
+
return "running";
|
|
31671
|
+
};
|
|
31672
|
+
}
|
|
31673
|
+
});
|
|
31674
|
+
|
|
31675
|
+
// src/tools/list-experiments.ts
|
|
31676
|
+
async function handleExperimentList(params) {
|
|
31677
|
+
const requested = typeof params.limit === "number" && params.limit > 0 ? params.limit : DEFAULT_LIMIT2;
|
|
31678
|
+
const effectiveLimit = Math.min(requested, MAX_LIMIT2);
|
|
31679
|
+
const search = new URLSearchParams();
|
|
31680
|
+
search.set("pageSize", String(effectiveLimit));
|
|
31681
|
+
const result = await makeRequest(
|
|
31682
|
+
"GET",
|
|
31683
|
+
`/api/experiments?${search.toString()}`
|
|
31684
|
+
);
|
|
31685
|
+
if (result.experiments.length === 0) {
|
|
31686
|
+
return [
|
|
31687
|
+
"# Experiments",
|
|
31688
|
+
"",
|
|
31689
|
+
"_No experiments found in this project._",
|
|
31690
|
+
"",
|
|
31691
|
+
"> Create an experiment in the LangWatch dashboard, then re-run this tool to discover its slug."
|
|
31692
|
+
].join("\n");
|
|
31693
|
+
}
|
|
31694
|
+
const lines = [];
|
|
31695
|
+
lines.push("# Experiments");
|
|
31696
|
+
lines.push("");
|
|
31697
|
+
lines.push(
|
|
31698
|
+
`Showing ${result.experiments.length} of ${result.pagination.totalHits} experiment${result.pagination.totalHits === 1 ? "" : "s"}.`
|
|
31699
|
+
);
|
|
31700
|
+
if (result.pagination.hasMore) {
|
|
31701
|
+
lines.push(
|
|
31702
|
+
`> More experiments exist beyond this limit. Re-run with a higher \`limit\` (max ${MAX_LIMIT2}) if needed.`
|
|
31703
|
+
);
|
|
31704
|
+
}
|
|
31705
|
+
lines.push("");
|
|
31706
|
+
lines.push("| Slug | Name | Runs | Last Run |");
|
|
31707
|
+
lines.push("|------|------|------|----------|");
|
|
31708
|
+
for (const exp of result.experiments) {
|
|
31709
|
+
const name = escapeMarkdownTableCell(exp.name ?? exp.slug);
|
|
31710
|
+
lines.push(
|
|
31711
|
+
`| ${formatInlineCode(exp.slug)} | ${name} | ${exp.runsCount} | ${formatTimestamp(exp.lastRunAt)} |`
|
|
31712
|
+
);
|
|
31713
|
+
}
|
|
31714
|
+
lines.push("");
|
|
31715
|
+
lines.push(
|
|
31716
|
+
"> Use `platform_experiment_list_runs` with one of these slugs to see its runs."
|
|
31717
|
+
);
|
|
31718
|
+
return lines.join("\n");
|
|
31719
|
+
}
|
|
31720
|
+
var DEFAULT_LIMIT2, MAX_LIMIT2, formatTimestamp, escapeMarkdownTableCell, formatInlineCode;
|
|
31721
|
+
var init_list_experiments = __esm({
|
|
31722
|
+
"src/tools/list-experiments.ts"() {
|
|
31723
|
+
"use strict";
|
|
31724
|
+
init_langwatch_api();
|
|
31725
|
+
DEFAULT_LIMIT2 = 25;
|
|
31726
|
+
MAX_LIMIT2 = 100;
|
|
31727
|
+
formatTimestamp = (iso) => {
|
|
31728
|
+
if (!iso) return "\u2014";
|
|
31729
|
+
const d = new Date(iso);
|
|
31730
|
+
if (Number.isNaN(d.getTime())) return iso;
|
|
31731
|
+
return d.toISOString().replace("T", " ").slice(0, 19) + " UTC";
|
|
31732
|
+
};
|
|
31733
|
+
escapeMarkdownTableCell = (value) => value.replace(/[\\|]/g, (c) => `\\${c}`).replace(/\n/g, " ");
|
|
31734
|
+
formatInlineCode = (value) => `\`${value.replace(/[\\`|]/g, (c) => `\\${c}`).replace(/\n/g, " ")}\``;
|
|
31735
|
+
}
|
|
31736
|
+
});
|
|
31737
|
+
|
|
31738
|
+
// src/tools/run-experiment.ts
|
|
31739
|
+
async function handleRunExperiment(params) {
|
|
31740
|
+
const result = await makeRequest(
|
|
31741
|
+
"POST",
|
|
31742
|
+
`/api/experiments/${encodeURIComponent(params.slug)}/run`
|
|
31743
|
+
);
|
|
31744
|
+
const lines = [];
|
|
31745
|
+
lines.push(`Evaluation started!
|
|
31746
|
+
`);
|
|
31747
|
+
lines.push(`**Run ID**: ${result.runId}`);
|
|
31748
|
+
lines.push(`**Status**: ${result.status}`);
|
|
31749
|
+
lines.push(`**Total cells**: ${result.total}`);
|
|
31750
|
+
if (result.runUrl) lines.push(`**View at**: ${result.runUrl}`);
|
|
31751
|
+
lines.push("");
|
|
31752
|
+
lines.push(
|
|
31753
|
+
`> Use \`platform_experiment_status\` with run ID "${result.runId}" to check progress.`
|
|
31754
|
+
);
|
|
31755
|
+
return lines.join("\n");
|
|
31756
|
+
}
|
|
31757
|
+
async function statusFromResults(params) {
|
|
31758
|
+
const search = new URLSearchParams();
|
|
31759
|
+
if (params.experimentSlug) search.set("experimentSlug", params.experimentSlug);
|
|
31760
|
+
const qs = search.toString() ? `?${search.toString()}` : "";
|
|
31761
|
+
let results;
|
|
31762
|
+
try {
|
|
31763
|
+
results = await makeRequest(
|
|
31764
|
+
"GET",
|
|
31765
|
+
`/api/experiments/runs/${encodeURIComponent(params.runId)}/results${qs}`
|
|
31766
|
+
);
|
|
31767
|
+
} catch (error48) {
|
|
31768
|
+
const code = error48 instanceof LangWatchApiError ? error48.status : void 0;
|
|
31769
|
+
const message = error48 instanceof Error ? error48.message : String(error48);
|
|
31770
|
+
if (code === 404 || code === void 0 && /404|not found/i.test(message)) {
|
|
31771
|
+
return null;
|
|
31772
|
+
}
|
|
31773
|
+
throw error48;
|
|
31774
|
+
}
|
|
31775
|
+
const status = deriveRunStatus(results.timestamps);
|
|
31776
|
+
const total = results.total ?? results.dataset?.length ?? 0;
|
|
31777
|
+
const progress = results.progress ?? results.dataset?.length ?? 0;
|
|
31778
|
+
const lines = [];
|
|
31779
|
+
lines.push(`# Evaluation Run ${params.runId}
|
|
31780
|
+
`);
|
|
31781
|
+
lines.push(`**Status**: ${status}`);
|
|
31782
|
+
lines.push(`**Progress**: ${progress}/${total} cells`);
|
|
31783
|
+
if (results.timestamps.createdAt) {
|
|
31784
|
+
lines.push(
|
|
31785
|
+
`**Started**: ${new Date(results.timestamps.createdAt).toISOString()}`
|
|
31786
|
+
);
|
|
31787
|
+
}
|
|
31788
|
+
if (results.timestamps.finishedAt) {
|
|
31789
|
+
lines.push(
|
|
31790
|
+
`**Finished**: ${new Date(results.timestamps.finishedAt).toISOString()}`
|
|
31791
|
+
);
|
|
31792
|
+
}
|
|
31793
|
+
if (results.timestamps.stoppedAt) {
|
|
31794
|
+
lines.push(
|
|
31795
|
+
`**Stopped**: ${new Date(results.timestamps.stoppedAt).toISOString()}`
|
|
31796
|
+
);
|
|
31797
|
+
}
|
|
31798
|
+
lines.push("");
|
|
31799
|
+
lines.push(
|
|
31800
|
+
"> Use `platform_experiment_results` to fetch the per-row scores (partial results are available even while running)."
|
|
31801
|
+
);
|
|
31802
|
+
return lines.join("\n");
|
|
31803
|
+
}
|
|
31804
|
+
async function handleExperimentStatus(params) {
|
|
31805
|
+
let status;
|
|
31806
|
+
try {
|
|
31807
|
+
status = await makeRequest(
|
|
31808
|
+
"GET",
|
|
31809
|
+
`/api/experiments/runs/${encodeURIComponent(params.runId)}`
|
|
31810
|
+
);
|
|
31811
|
+
} catch (error48) {
|
|
31812
|
+
const code = error48 instanceof LangWatchApiError ? error48.status : void 0;
|
|
31813
|
+
const message = error48 instanceof Error ? error48.message : String(error48);
|
|
31814
|
+
if (code === 404 || /404|not found/i.test(message)) {
|
|
31815
|
+
const fallback = await statusFromResults(params);
|
|
31816
|
+
if (fallback) return fallback;
|
|
31817
|
+
return [
|
|
31818
|
+
`# Evaluation Run ${params.runId}`,
|
|
31819
|
+
"",
|
|
31820
|
+
"**Status**: not found",
|
|
31821
|
+
"",
|
|
31822
|
+
`Could not find run \`${params.runId}\`. SDK-logged runs and runs older than 24h are not in the live run-state and must be resolved by experiment slug.`,
|
|
31823
|
+
"",
|
|
31824
|
+
"> Pass `experimentSlug`: discover it with `platform_experiment_list`, then use `platform_experiment_list_runs` for the run ids. Or fetch the rows directly with `platform_experiment_results`."
|
|
31825
|
+
].join("\n");
|
|
31826
|
+
}
|
|
31827
|
+
throw error48;
|
|
31828
|
+
}
|
|
31829
|
+
const lines = [];
|
|
31830
|
+
lines.push(`# Evaluation Run ${status.runId}
|
|
31831
|
+
`);
|
|
31832
|
+
lines.push(`**Status**: ${status.status}`);
|
|
31833
|
+
lines.push(`**Progress**: ${status.progress}/${status.total} cells`);
|
|
31834
|
+
if (status.startedAt) {
|
|
31835
|
+
lines.push(`**Started**: ${new Date(status.startedAt).toISOString()}`);
|
|
31836
|
+
}
|
|
31837
|
+
if (status.finishedAt) {
|
|
31838
|
+
lines.push(`**Finished**: ${new Date(status.finishedAt).toISOString()}`);
|
|
31839
|
+
}
|
|
31840
|
+
if (status.summary) {
|
|
31841
|
+
lines.push("\n## Summary\n");
|
|
31842
|
+
if (status.summary.completedCells !== void 0) {
|
|
31843
|
+
lines.push(`**Completed**: ${status.summary.completedCells}`);
|
|
31844
|
+
}
|
|
31845
|
+
if (status.summary.failedCells) {
|
|
31846
|
+
lines.push(`**Failed**: ${status.summary.failedCells}`);
|
|
31847
|
+
}
|
|
31848
|
+
if (status.summary.duration) {
|
|
31849
|
+
lines.push(
|
|
31850
|
+
`**Duration**: ${(status.summary.duration / 1e3).toFixed(1)}s`
|
|
31851
|
+
);
|
|
31852
|
+
}
|
|
31853
|
+
if (status.summary.runUrl) {
|
|
31854
|
+
lines.push(`**View results**: ${status.summary.runUrl}`);
|
|
31855
|
+
}
|
|
31856
|
+
}
|
|
31857
|
+
return lines.join("\n");
|
|
31858
|
+
}
|
|
31859
|
+
var init_run_experiment = __esm({
|
|
31860
|
+
"src/tools/run-experiment.ts"() {
|
|
31861
|
+
"use strict";
|
|
31862
|
+
init_langwatch_api();
|
|
31863
|
+
init_experiment_run_status();
|
|
31864
|
+
}
|
|
31865
|
+
});
|
|
31866
|
+
|
|
31230
31867
|
// src/tools/discover-scenario-schema.ts
|
|
31231
31868
|
var discover_scenario_schema_exports = {};
|
|
31232
31869
|
__export(discover_scenario_schema_exports, {
|
|
@@ -33185,122 +33822,6 @@ var init_discover_schema = __esm({
|
|
|
33185
33822
|
}
|
|
33186
33823
|
});
|
|
33187
33824
|
|
|
33188
|
-
// src/langwatch-api.ts
|
|
33189
|
-
async function makeRequest(method, path, body) {
|
|
33190
|
-
const config2 = getConfig();
|
|
33191
|
-
const url2 = config2.endpoint + path;
|
|
33192
|
-
const headers = {
|
|
33193
|
-
"X-Auth-Token": requireApiKey()
|
|
33194
|
-
};
|
|
33195
|
-
if (config2.projectId) {
|
|
33196
|
-
headers["X-Project-Id"] = config2.projectId;
|
|
33197
|
-
}
|
|
33198
|
-
if (body !== void 0) {
|
|
33199
|
-
headers["Content-Type"] = "application/json";
|
|
33200
|
-
}
|
|
33201
|
-
const response = await fetch(url2, {
|
|
33202
|
-
method,
|
|
33203
|
-
headers,
|
|
33204
|
-
...body !== void 0 ? { body: JSON.stringify(body) } : {}
|
|
33205
|
-
});
|
|
33206
|
-
if (!response.ok) {
|
|
33207
|
-
const responseBody = await response.text();
|
|
33208
|
-
throw new Error(
|
|
33209
|
-
`LangWatch API error ${response.status}: ${responseBody}`
|
|
33210
|
-
);
|
|
33211
|
-
}
|
|
33212
|
-
if (response.status === 204 || response.headers?.get("content-length") === "0") {
|
|
33213
|
-
return null;
|
|
33214
|
-
}
|
|
33215
|
-
return response.json();
|
|
33216
|
-
}
|
|
33217
|
-
async function searchTraces(params) {
|
|
33218
|
-
const { format: format3 = "digest", ...rest } = params;
|
|
33219
|
-
return makeRequest("POST", "/api/traces/search", {
|
|
33220
|
-
...rest,
|
|
33221
|
-
format: format3
|
|
33222
|
-
});
|
|
33223
|
-
}
|
|
33224
|
-
async function getTraceById(traceId, format3 = "digest") {
|
|
33225
|
-
return makeRequest(
|
|
33226
|
-
"GET",
|
|
33227
|
-
`/api/traces/${encodeURIComponent(traceId)}?format=${format3}`
|
|
33228
|
-
);
|
|
33229
|
-
}
|
|
33230
|
-
async function getAnalyticsTimeseries(params) {
|
|
33231
|
-
return makeRequest(
|
|
33232
|
-
"POST",
|
|
33233
|
-
"/api/analytics/timeseries",
|
|
33234
|
-
params
|
|
33235
|
-
);
|
|
33236
|
-
}
|
|
33237
|
-
async function listPrompts() {
|
|
33238
|
-
return makeRequest("GET", "/api/prompts");
|
|
33239
|
-
}
|
|
33240
|
-
async function getPrompt(idOrHandle, options) {
|
|
33241
|
-
const params = new URLSearchParams();
|
|
33242
|
-
if (options?.version != null) params.set("version", String(options.version));
|
|
33243
|
-
if (options?.tag) params.set("tag", options.tag);
|
|
33244
|
-
const query = params.toString() ? `?${params}` : "";
|
|
33245
|
-
return makeRequest(
|
|
33246
|
-
"GET",
|
|
33247
|
-
`/api/prompts/${encodeURIComponent(idOrHandle)}${query}`
|
|
33248
|
-
);
|
|
33249
|
-
}
|
|
33250
|
-
async function createPrompt(data) {
|
|
33251
|
-
return makeRequest(
|
|
33252
|
-
"POST",
|
|
33253
|
-
"/api/prompts",
|
|
33254
|
-
data
|
|
33255
|
-
);
|
|
33256
|
-
}
|
|
33257
|
-
async function updatePrompt(idOrHandle, data) {
|
|
33258
|
-
return makeRequest(
|
|
33259
|
-
"PUT",
|
|
33260
|
-
`/api/prompts/${encodeURIComponent(idOrHandle)}`,
|
|
33261
|
-
data
|
|
33262
|
-
);
|
|
33263
|
-
}
|
|
33264
|
-
async function assignPromptTag({
|
|
33265
|
-
idOrHandle,
|
|
33266
|
-
tag,
|
|
33267
|
-
versionId
|
|
33268
|
-
}) {
|
|
33269
|
-
return makeRequest(
|
|
33270
|
-
"PUT",
|
|
33271
|
-
`/api/prompts/${encodeURIComponent(idOrHandle)}/tags/${encodeURIComponent(tag)}`,
|
|
33272
|
-
{ versionId }
|
|
33273
|
-
);
|
|
33274
|
-
}
|
|
33275
|
-
async function listPromptTags() {
|
|
33276
|
-
return makeRequest("GET", "/api/prompts/tags");
|
|
33277
|
-
}
|
|
33278
|
-
async function createPromptTag(name) {
|
|
33279
|
-
return makeRequest("POST", "/api/prompts/tags", { name });
|
|
33280
|
-
}
|
|
33281
|
-
async function renamePromptTag({
|
|
33282
|
-
tag,
|
|
33283
|
-
name
|
|
33284
|
-
}) {
|
|
33285
|
-
return makeRequest(
|
|
33286
|
-
"PUT",
|
|
33287
|
-
`/api/prompts/tags/${encodeURIComponent(tag)}`,
|
|
33288
|
-
{ name }
|
|
33289
|
-
);
|
|
33290
|
-
}
|
|
33291
|
-
async function deletePromptTag(tag) {
|
|
33292
|
-
return makeRequest(
|
|
33293
|
-
"DELETE",
|
|
33294
|
-
`/api/prompts/tags/${encodeURIComponent(tag)}`
|
|
33295
|
-
);
|
|
33296
|
-
}
|
|
33297
|
-
var init_langwatch_api = __esm({
|
|
33298
|
-
"src/langwatch-api.ts"() {
|
|
33299
|
-
"use strict";
|
|
33300
|
-
init_config();
|
|
33301
|
-
}
|
|
33302
|
-
});
|
|
33303
|
-
|
|
33304
33825
|
// src/utils/date-parsing.ts
|
|
33305
33826
|
function parseRelativeDate(input) {
|
|
33306
33827
|
if (input === "now") return Date.now();
|
|
@@ -35356,96 +35877,30 @@ async function listSecrets() {
|
|
|
35356
35877
|
return makeRequest("GET", "/api/secrets");
|
|
35357
35878
|
}
|
|
35358
35879
|
async function getSecret(id) {
|
|
35359
|
-
return makeRequest(
|
|
35360
|
-
"GET",
|
|
35361
|
-
`/api/secrets/${encodeURIComponent(id)}`
|
|
35362
|
-
);
|
|
35363
|
-
}
|
|
35364
|
-
async function createSecret(data) {
|
|
35365
|
-
return makeRequest("POST", "/api/secrets", data);
|
|
35366
|
-
}
|
|
35367
|
-
async function updateSecret(params) {
|
|
35368
|
-
const { id, value } = params;
|
|
35369
|
-
return makeRequest(
|
|
35370
|
-
"PUT",
|
|
35371
|
-
`/api/secrets/${encodeURIComponent(id)}`,
|
|
35372
|
-
{ value }
|
|
35373
|
-
);
|
|
35374
|
-
}
|
|
35375
|
-
async function deleteSecret(id) {
|
|
35376
|
-
return makeRequest(
|
|
35377
|
-
"DELETE",
|
|
35378
|
-
`/api/secrets/${encodeURIComponent(id)}`
|
|
35379
|
-
);
|
|
35380
|
-
}
|
|
35381
|
-
var init_langwatch_api_secrets = __esm({
|
|
35382
|
-
"src/langwatch-api-secrets.ts"() {
|
|
35383
|
-
"use strict";
|
|
35384
|
-
init_langwatch_api();
|
|
35385
|
-
}
|
|
35386
|
-
});
|
|
35387
|
-
|
|
35388
|
-
// src/tools/run-evaluation.ts
|
|
35389
|
-
var run_evaluation_exports = {};
|
|
35390
|
-
__export(run_evaluation_exports, {
|
|
35391
|
-
handleEvaluationStatus: () => handleEvaluationStatus,
|
|
35392
|
-
handleRunEvaluation: () => handleRunEvaluation
|
|
35393
|
-
});
|
|
35394
|
-
async function handleRunEvaluation(params) {
|
|
35395
|
-
const result = await makeRequest(
|
|
35396
|
-
"POST",
|
|
35397
|
-
`/api/evaluations/v3/${encodeURIComponent(params.slug)}/run`
|
|
35398
|
-
);
|
|
35399
|
-
const lines = [];
|
|
35400
|
-
lines.push(`Evaluation started!
|
|
35401
|
-
`);
|
|
35402
|
-
lines.push(`**Run ID**: ${result.runId}`);
|
|
35403
|
-
lines.push(`**Status**: ${result.status}`);
|
|
35404
|
-
lines.push(`**Total cells**: ${result.total}`);
|
|
35405
|
-
if (result.runUrl) lines.push(`**View at**: ${result.runUrl}`);
|
|
35406
|
-
lines.push("");
|
|
35407
|
-
lines.push(
|
|
35408
|
-
`> Use \`platform_evaluation_status\` with run ID "${result.runId}" to check progress.`
|
|
35409
|
-
);
|
|
35410
|
-
return lines.join("\n");
|
|
35411
|
-
}
|
|
35412
|
-
async function handleEvaluationStatus(params) {
|
|
35413
|
-
const status = await makeRequest(
|
|
35414
|
-
"GET",
|
|
35415
|
-
`/api/evaluations/v3/runs/${encodeURIComponent(params.runId)}`
|
|
35416
|
-
);
|
|
35417
|
-
const lines = [];
|
|
35418
|
-
lines.push(`# Evaluation Run ${status.runId}
|
|
35419
|
-
`);
|
|
35420
|
-
lines.push(`**Status**: ${status.status}`);
|
|
35421
|
-
lines.push(`**Progress**: ${status.progress}/${status.total} cells`);
|
|
35422
|
-
if (status.startedAt) {
|
|
35423
|
-
lines.push(`**Started**: ${new Date(status.startedAt).toISOString()}`);
|
|
35424
|
-
}
|
|
35425
|
-
if (status.finishedAt) {
|
|
35426
|
-
lines.push(`**Finished**: ${new Date(status.finishedAt).toISOString()}`);
|
|
35427
|
-
}
|
|
35428
|
-
if (status.summary) {
|
|
35429
|
-
lines.push("\n## Summary\n");
|
|
35430
|
-
if (status.summary.completedCells !== void 0) {
|
|
35431
|
-
lines.push(`**Completed**: ${status.summary.completedCells}`);
|
|
35432
|
-
}
|
|
35433
|
-
if (status.summary.failedCells) {
|
|
35434
|
-
lines.push(`**Failed**: ${status.summary.failedCells}`);
|
|
35435
|
-
}
|
|
35436
|
-
if (status.summary.duration) {
|
|
35437
|
-
lines.push(
|
|
35438
|
-
`**Duration**: ${(status.summary.duration / 1e3).toFixed(1)}s`
|
|
35439
|
-
);
|
|
35440
|
-
}
|
|
35441
|
-
if (status.summary.runUrl) {
|
|
35442
|
-
lines.push(`**View results**: ${status.summary.runUrl}`);
|
|
35443
|
-
}
|
|
35444
|
-
}
|
|
35445
|
-
return lines.join("\n");
|
|
35880
|
+
return makeRequest(
|
|
35881
|
+
"GET",
|
|
35882
|
+
`/api/secrets/${encodeURIComponent(id)}`
|
|
35883
|
+
);
|
|
35884
|
+
}
|
|
35885
|
+
async function createSecret(data) {
|
|
35886
|
+
return makeRequest("POST", "/api/secrets", data);
|
|
35887
|
+
}
|
|
35888
|
+
async function updateSecret(params) {
|
|
35889
|
+
const { id, value } = params;
|
|
35890
|
+
return makeRequest(
|
|
35891
|
+
"PUT",
|
|
35892
|
+
`/api/secrets/${encodeURIComponent(id)}`,
|
|
35893
|
+
{ value }
|
|
35894
|
+
);
|
|
35895
|
+
}
|
|
35896
|
+
async function deleteSecret(id) {
|
|
35897
|
+
return makeRequest(
|
|
35898
|
+
"DELETE",
|
|
35899
|
+
`/api/secrets/${encodeURIComponent(id)}`
|
|
35900
|
+
);
|
|
35446
35901
|
}
|
|
35447
|
-
var
|
|
35448
|
-
"src/
|
|
35902
|
+
var init_langwatch_api_secrets = __esm({
|
|
35903
|
+
"src/langwatch-api-secrets.ts"() {
|
|
35449
35904
|
"use strict";
|
|
35450
35905
|
init_langwatch_api();
|
|
35451
35906
|
}
|
|
@@ -35826,6 +36281,305 @@ var init_delete_dataset_records = __esm({
|
|
|
35826
36281
|
}
|
|
35827
36282
|
});
|
|
35828
36283
|
|
|
36284
|
+
// src/langwatch-api-projects.ts
|
|
36285
|
+
async function listProjects(params) {
|
|
36286
|
+
const query = new URLSearchParams();
|
|
36287
|
+
if (params?.page) query.set("page", String(params.page));
|
|
36288
|
+
if (params?.limit) query.set("limit", String(params.limit));
|
|
36289
|
+
const qs = query.toString() ? `?${query}` : "";
|
|
36290
|
+
return makeRequest("GET", `/api/projects${qs}`);
|
|
36291
|
+
}
|
|
36292
|
+
async function getProject(id) {
|
|
36293
|
+
return makeRequest(
|
|
36294
|
+
"GET",
|
|
36295
|
+
`/api/projects/${encodeURIComponent(id)}`
|
|
36296
|
+
);
|
|
36297
|
+
}
|
|
36298
|
+
async function createProject(data) {
|
|
36299
|
+
return makeRequest("POST", "/api/projects", data);
|
|
36300
|
+
}
|
|
36301
|
+
async function updateProject(params) {
|
|
36302
|
+
const { id, ...data } = params;
|
|
36303
|
+
return makeRequest(
|
|
36304
|
+
"PATCH",
|
|
36305
|
+
`/api/projects/${encodeURIComponent(id)}`,
|
|
36306
|
+
data
|
|
36307
|
+
);
|
|
36308
|
+
}
|
|
36309
|
+
async function archiveProject(id) {
|
|
36310
|
+
return makeRequest(
|
|
36311
|
+
"DELETE",
|
|
36312
|
+
`/api/projects/${encodeURIComponent(id)}`
|
|
36313
|
+
);
|
|
36314
|
+
}
|
|
36315
|
+
var init_langwatch_api_projects = __esm({
|
|
36316
|
+
"src/langwatch-api-projects.ts"() {
|
|
36317
|
+
"use strict";
|
|
36318
|
+
init_langwatch_api();
|
|
36319
|
+
}
|
|
36320
|
+
});
|
|
36321
|
+
|
|
36322
|
+
// src/tools/list-projects.ts
|
|
36323
|
+
var list_projects_exports = {};
|
|
36324
|
+
__export(list_projects_exports, {
|
|
36325
|
+
handleListProjects: () => handleListProjects
|
|
36326
|
+
});
|
|
36327
|
+
async function handleListProjects(params) {
|
|
36328
|
+
const result = await listProjects({
|
|
36329
|
+
page: params?.page,
|
|
36330
|
+
limit: params?.limit ?? 100
|
|
36331
|
+
});
|
|
36332
|
+
const projects = result.data;
|
|
36333
|
+
if (!Array.isArray(projects) || projects.length === 0) {
|
|
36334
|
+
return "No projects found in this organization.\n\n> Tip: Use `platform_create_project` to create your first project.";
|
|
36335
|
+
}
|
|
36336
|
+
const lines = [];
|
|
36337
|
+
lines.push(`# Projects (${result.pagination.total} total)
|
|
36338
|
+
`);
|
|
36339
|
+
for (const p of projects) {
|
|
36340
|
+
lines.push(`## ${p.name}`);
|
|
36341
|
+
lines.push(`**ID**: ${p.id}`);
|
|
36342
|
+
lines.push(`**Slug**: ${p.slug}`);
|
|
36343
|
+
lines.push(`**Language**: ${p.language}`);
|
|
36344
|
+
lines.push(`**Framework**: ${p.framework}`);
|
|
36345
|
+
lines.push(`**Updated**: ${p.updatedAt}`);
|
|
36346
|
+
lines.push("");
|
|
36347
|
+
}
|
|
36348
|
+
if (result.pagination.totalPages > 1) {
|
|
36349
|
+
lines.push(
|
|
36350
|
+
`> Showing page ${result.pagination.page} of ${result.pagination.totalPages}. Use \`page\` parameter to navigate.`
|
|
36351
|
+
);
|
|
36352
|
+
}
|
|
36353
|
+
lines.push(
|
|
36354
|
+
"> Use `platform_get_project` with the ID to see full project details."
|
|
36355
|
+
);
|
|
36356
|
+
return lines.join("\n");
|
|
36357
|
+
}
|
|
36358
|
+
var init_list_projects = __esm({
|
|
36359
|
+
"src/tools/list-projects.ts"() {
|
|
36360
|
+
"use strict";
|
|
36361
|
+
init_langwatch_api_projects();
|
|
36362
|
+
}
|
|
36363
|
+
});
|
|
36364
|
+
|
|
36365
|
+
// src/tools/get-project.ts
|
|
36366
|
+
var get_project_exports = {};
|
|
36367
|
+
__export(get_project_exports, {
|
|
36368
|
+
handleGetProject: () => handleGetProject
|
|
36369
|
+
});
|
|
36370
|
+
async function handleGetProject(params) {
|
|
36371
|
+
const project = await getProject(params.id);
|
|
36372
|
+
const lines = [];
|
|
36373
|
+
lines.push(`# ${project.name}
|
|
36374
|
+
`);
|
|
36375
|
+
lines.push(`**ID**: ${project.id}`);
|
|
36376
|
+
lines.push(`**Slug**: ${project.slug}`);
|
|
36377
|
+
lines.push(`**Language**: ${project.language}`);
|
|
36378
|
+
lines.push(`**Framework**: ${project.framework}`);
|
|
36379
|
+
lines.push(`**Team ID**: ${project.teamId}`);
|
|
36380
|
+
lines.push(`**PII Redaction**: ${project.piiRedactionLevel}`);
|
|
36381
|
+
lines.push(`**Created**: ${project.createdAt}`);
|
|
36382
|
+
lines.push(`**Updated**: ${project.updatedAt}`);
|
|
36383
|
+
return lines.join("\n");
|
|
36384
|
+
}
|
|
36385
|
+
var init_get_project = __esm({
|
|
36386
|
+
"src/tools/get-project.ts"() {
|
|
36387
|
+
"use strict";
|
|
36388
|
+
init_langwatch_api_projects();
|
|
36389
|
+
}
|
|
36390
|
+
});
|
|
36391
|
+
|
|
36392
|
+
// src/tools/create-project.ts
|
|
36393
|
+
var create_project_exports = {};
|
|
36394
|
+
__export(create_project_exports, {
|
|
36395
|
+
handleCreateProject: () => handleCreateProject
|
|
36396
|
+
});
|
|
36397
|
+
async function handleCreateProject(params) {
|
|
36398
|
+
if (!params.teamId && !params.newTeamName) {
|
|
36399
|
+
return "Error: You must provide either `teamId` (to add to an existing team) or `newTeamName` (to create a new team for this project).";
|
|
36400
|
+
}
|
|
36401
|
+
const result = await createProject({
|
|
36402
|
+
name: params.name,
|
|
36403
|
+
language: params.language,
|
|
36404
|
+
framework: params.framework,
|
|
36405
|
+
teamId: params.teamId,
|
|
36406
|
+
newTeamName: params.newTeamName
|
|
36407
|
+
});
|
|
36408
|
+
if (!result.serviceApiKey) {
|
|
36409
|
+
throw new Error(
|
|
36410
|
+
"API did not return a service API key. The project was created but the key is missing \u2014 check the LangWatch UI."
|
|
36411
|
+
);
|
|
36412
|
+
}
|
|
36413
|
+
const lines = [];
|
|
36414
|
+
lines.push(`Project created successfully!
|
|
36415
|
+
`);
|
|
36416
|
+
lines.push(`**Name**: ${result.name}`);
|
|
36417
|
+
lines.push(`**ID**: ${result.id}`);
|
|
36418
|
+
lines.push(`**Slug**: ${result.slug}`);
|
|
36419
|
+
lines.push(`**Language**: ${result.language}`);
|
|
36420
|
+
lines.push(`**Framework**: ${result.framework}`);
|
|
36421
|
+
lines.push("");
|
|
36422
|
+
lines.push(`**Service API Key**: \`${result.serviceApiKey}\``);
|
|
36423
|
+
lines.push(`**Service API Key ID**: ${result.serviceApiKeyId}`);
|
|
36424
|
+
lines.push("");
|
|
36425
|
+
lines.push(
|
|
36426
|
+
"> \u26A0\uFE0F Save the service API key now \u2014 it will not be shown again. Use it as `LANGWATCH_API_KEY` to authenticate project-scoped operations."
|
|
36427
|
+
);
|
|
36428
|
+
return lines.join("\n");
|
|
36429
|
+
}
|
|
36430
|
+
var init_create_project = __esm({
|
|
36431
|
+
"src/tools/create-project.ts"() {
|
|
36432
|
+
"use strict";
|
|
36433
|
+
init_langwatch_api_projects();
|
|
36434
|
+
}
|
|
36435
|
+
});
|
|
36436
|
+
|
|
36437
|
+
// src/tools/update-project.ts
|
|
36438
|
+
var update_project_exports = {};
|
|
36439
|
+
__export(update_project_exports, {
|
|
36440
|
+
handleUpdateProject: () => handleUpdateProject
|
|
36441
|
+
});
|
|
36442
|
+
async function handleUpdateProject(params) {
|
|
36443
|
+
const project = await updateProject(params);
|
|
36444
|
+
const lines = [];
|
|
36445
|
+
lines.push(`Project updated successfully!
|
|
36446
|
+
`);
|
|
36447
|
+
lines.push(`**Name**: ${project.name}`);
|
|
36448
|
+
lines.push(`**ID**: ${project.id}`);
|
|
36449
|
+
lines.push(`**Slug**: ${project.slug}`);
|
|
36450
|
+
lines.push(`**Language**: ${project.language}`);
|
|
36451
|
+
lines.push(`**Framework**: ${project.framework}`);
|
|
36452
|
+
lines.push(`**PII Redaction**: ${project.piiRedactionLevel}`);
|
|
36453
|
+
return lines.join("\n");
|
|
36454
|
+
}
|
|
36455
|
+
var init_update_project = __esm({
|
|
36456
|
+
"src/tools/update-project.ts"() {
|
|
36457
|
+
"use strict";
|
|
36458
|
+
init_langwatch_api_projects();
|
|
36459
|
+
}
|
|
36460
|
+
});
|
|
36461
|
+
|
|
36462
|
+
// src/tools/archive-project.ts
|
|
36463
|
+
var archive_project_exports = {};
|
|
36464
|
+
__export(archive_project_exports, {
|
|
36465
|
+
handleArchiveProject: () => handleArchiveProject
|
|
36466
|
+
});
|
|
36467
|
+
async function handleArchiveProject(params) {
|
|
36468
|
+
const result = await archiveProject(params.id);
|
|
36469
|
+
return `Project archived successfully.
|
|
36470
|
+
|
|
36471
|
+
**Name**: ${result.name}
|
|
36472
|
+
**ID**: ${result.id}
|
|
36473
|
+
**Archived At**: ${result.archivedAt}`;
|
|
36474
|
+
}
|
|
36475
|
+
var init_archive_project = __esm({
|
|
36476
|
+
"src/tools/archive-project.ts"() {
|
|
36477
|
+
"use strict";
|
|
36478
|
+
init_langwatch_api_projects();
|
|
36479
|
+
}
|
|
36480
|
+
});
|
|
36481
|
+
|
|
36482
|
+
// src/langwatch-api-api-keys.ts
|
|
36483
|
+
async function listApiKeys() {
|
|
36484
|
+
return makeRequest("GET", "/api/api-keys");
|
|
36485
|
+
}
|
|
36486
|
+
async function createApiKey(data) {
|
|
36487
|
+
return makeRequest("POST", "/api/api-keys", data);
|
|
36488
|
+
}
|
|
36489
|
+
async function revokeApiKey(id) {
|
|
36490
|
+
return makeRequest(
|
|
36491
|
+
"DELETE",
|
|
36492
|
+
`/api/api-keys/${encodeURIComponent(id)}`
|
|
36493
|
+
);
|
|
36494
|
+
}
|
|
36495
|
+
var init_langwatch_api_api_keys = __esm({
|
|
36496
|
+
"src/langwatch-api-api-keys.ts"() {
|
|
36497
|
+
"use strict";
|
|
36498
|
+
init_langwatch_api();
|
|
36499
|
+
}
|
|
36500
|
+
});
|
|
36501
|
+
|
|
36502
|
+
// src/tools/list-api-keys.ts
|
|
36503
|
+
var list_api_keys_exports = {};
|
|
36504
|
+
__export(list_api_keys_exports, {
|
|
36505
|
+
handleListApiKeys: () => handleListApiKeys
|
|
36506
|
+
});
|
|
36507
|
+
async function handleListApiKeys() {
|
|
36508
|
+
const result = await listApiKeys();
|
|
36509
|
+
const keys = result.data;
|
|
36510
|
+
if (!Array.isArray(keys) || keys.length === 0) {
|
|
36511
|
+
return "No API keys found.\n\n> Tip: Use `platform_create_api_key` to create a new key.";
|
|
36512
|
+
}
|
|
36513
|
+
const lines = [];
|
|
36514
|
+
lines.push(`# API Keys (${keys.length} total)
|
|
36515
|
+
`);
|
|
36516
|
+
for (const k of keys) {
|
|
36517
|
+
const status = k.revokedAt ? "REVOKED" : k.expiresAt && new Date(k.expiresAt) < /* @__PURE__ */ new Date() ? "EXPIRED" : "ACTIVE";
|
|
36518
|
+
lines.push(`## ${k.name}`);
|
|
36519
|
+
lines.push(`**ID**: ${k.id}`);
|
|
36520
|
+
lines.push(`**Status**: ${status}`);
|
|
36521
|
+
if (k.description) lines.push(`**Description**: ${k.description}`);
|
|
36522
|
+
if (k.expiresAt) lines.push(`**Expires**: ${k.expiresAt}`);
|
|
36523
|
+
if (k.lastUsedAt) lines.push(`**Last Used**: ${k.lastUsedAt}`);
|
|
36524
|
+
lines.push(`**Created**: ${k.createdAt}`);
|
|
36525
|
+
if (k.roleBindings.length > 0) {
|
|
36526
|
+
const bindings = k.roleBindings.map((rb) => `${rb.role} on ${rb.scopeType}:${rb.scopeId}`).join(", ");
|
|
36527
|
+
lines.push(`**Bindings**: ${bindings}`);
|
|
36528
|
+
}
|
|
36529
|
+
lines.push("");
|
|
36530
|
+
}
|
|
36531
|
+
return lines.join("\n");
|
|
36532
|
+
}
|
|
36533
|
+
var init_list_api_keys = __esm({
|
|
36534
|
+
"src/tools/list-api-keys.ts"() {
|
|
36535
|
+
"use strict";
|
|
36536
|
+
init_langwatch_api_api_keys();
|
|
36537
|
+
}
|
|
36538
|
+
});
|
|
36539
|
+
|
|
36540
|
+
// src/tools/create-api-key.ts
|
|
36541
|
+
var create_api_key_exports = {};
|
|
36542
|
+
__export(create_api_key_exports, {
|
|
36543
|
+
handleCreateApiKey: () => handleCreateApiKey
|
|
36544
|
+
});
|
|
36545
|
+
async function handleCreateApiKey(params) {
|
|
36546
|
+
const result = await createApiKey(params);
|
|
36547
|
+
const lines = [];
|
|
36548
|
+
lines.push(`API key created successfully!
|
|
36549
|
+
`);
|
|
36550
|
+
lines.push(`**Name**: ${result.apiKey.name}`);
|
|
36551
|
+
lines.push(`**ID**: ${result.apiKey.id}`);
|
|
36552
|
+
lines.push(`**Token**: \`${result.token}\``);
|
|
36553
|
+
lines.push(`**Created**: ${result.apiKey.createdAt}`);
|
|
36554
|
+
lines.push("");
|
|
36555
|
+
lines.push(
|
|
36556
|
+
"> \u26A0\uFE0F Save this token now \u2014 it will not be shown again."
|
|
36557
|
+
);
|
|
36558
|
+
return lines.join("\n");
|
|
36559
|
+
}
|
|
36560
|
+
var init_create_api_key = __esm({
|
|
36561
|
+
"src/tools/create-api-key.ts"() {
|
|
36562
|
+
"use strict";
|
|
36563
|
+
init_langwatch_api_api_keys();
|
|
36564
|
+
}
|
|
36565
|
+
});
|
|
36566
|
+
|
|
36567
|
+
// src/tools/revoke-api-key.ts
|
|
36568
|
+
var revoke_api_key_exports = {};
|
|
36569
|
+
__export(revoke_api_key_exports, {
|
|
36570
|
+
handleRevokeApiKey: () => handleRevokeApiKey
|
|
36571
|
+
});
|
|
36572
|
+
async function handleRevokeApiKey(params) {
|
|
36573
|
+
await revokeApiKey(params.id);
|
|
36574
|
+
return `API key ${params.id} revoked successfully.`;
|
|
36575
|
+
}
|
|
36576
|
+
var init_revoke_api_key = __esm({
|
|
36577
|
+
"src/tools/revoke-api-key.ts"() {
|
|
36578
|
+
"use strict";
|
|
36579
|
+
init_langwatch_api_api_keys();
|
|
36580
|
+
}
|
|
36581
|
+
});
|
|
36582
|
+
|
|
35829
36583
|
// src/create-mcp-server.ts
|
|
35830
36584
|
function createMcpServer() {
|
|
35831
36585
|
const server = new McpServer({
|
|
@@ -37087,30 +37841,89 @@ ${lines.join("\n")}`
|
|
|
37087
37841
|
})
|
|
37088
37842
|
);
|
|
37089
37843
|
server.tool(
|
|
37090
|
-
"
|
|
37091
|
-
"Start an
|
|
37844
|
+
"platform_run_experiment",
|
|
37845
|
+
"Start an experiment run by slug. Returns a run ID for polling status.",
|
|
37846
|
+
{
|
|
37847
|
+
slug: external_exports.string().describe("The experiment slug to run")
|
|
37848
|
+
},
|
|
37849
|
+
withToolLogging("platform_run_experiment", async (params) => {
|
|
37850
|
+
requireApiKey();
|
|
37851
|
+
return {
|
|
37852
|
+
content: [{ type: "text", text: await handleRunExperiment(params) }]
|
|
37853
|
+
};
|
|
37854
|
+
})
|
|
37855
|
+
);
|
|
37856
|
+
server.tool(
|
|
37857
|
+
"platform_experiment_status",
|
|
37858
|
+
"Check the status of an experiment run (running, completed, stopped, or interrupted) plus its progress. Works for both platform-run and SDK-logged experiments; pass experimentSlug for SDK runs or runs older than 24h.",
|
|
37859
|
+
{
|
|
37860
|
+
runId: external_exports.string().describe("The run ID returned from platform_run_experiment"),
|
|
37861
|
+
experimentSlug: external_exports.string().optional().describe(
|
|
37862
|
+
"Experiment slug \u2014 required for SDK-logged runs and runs older than 24h (the Redis run-state they would otherwise be read from is absent/expired). Use platform_experiment_list_runs to find the slug."
|
|
37863
|
+
)
|
|
37864
|
+
},
|
|
37865
|
+
withToolLogging("platform_experiment_status", async (params) => {
|
|
37866
|
+
requireApiKey();
|
|
37867
|
+
return {
|
|
37868
|
+
content: [{ type: "text", text: await handleExperimentStatus(params) }]
|
|
37869
|
+
};
|
|
37870
|
+
})
|
|
37871
|
+
);
|
|
37872
|
+
server.tool(
|
|
37873
|
+
"platform_experiment_list",
|
|
37874
|
+
"List experiments configured in the LangWatch project. Returns a markdown table with each experiment's slug, name, last-run timestamp, and run count. Use this to discover experiment slugs before drilling into runs with platform_experiment_list_runs. Output is capped (default 25, max 100) to protect the agent's context window.",
|
|
37875
|
+
{
|
|
37876
|
+
limit: external_exports.number().int().positive().max(100).optional().describe(
|
|
37877
|
+
"Maximum number of experiments to include (default 25, hard-capped at 100)"
|
|
37878
|
+
)
|
|
37879
|
+
},
|
|
37880
|
+
withToolLogging("platform_experiment_list", async (params) => {
|
|
37881
|
+
requireApiKey();
|
|
37882
|
+
return {
|
|
37883
|
+
content: [{ type: "text", text: await handleExperimentList(params) }]
|
|
37884
|
+
};
|
|
37885
|
+
})
|
|
37886
|
+
);
|
|
37887
|
+
server.tool(
|
|
37888
|
+
"platform_experiment_list_runs",
|
|
37889
|
+
"List experiment runs for a specific experiment slug. Returns a markdown table with each run's id, status, started/finished timestamps, and pass-rate summary. Use this to discover run ids before calling platform_experiment_results. Output is capped (default 25, max 100) to protect the agent's context window.",
|
|
37092
37890
|
{
|
|
37093
|
-
|
|
37891
|
+
experimentSlug: external_exports.string().describe(
|
|
37892
|
+
"Experiment slug from platform_experiment_list (e.g. 'checkout-flow')"
|
|
37893
|
+
),
|
|
37894
|
+
limit: external_exports.number().int().positive().max(100).optional().describe(
|
|
37895
|
+
"Maximum number of runs to include (default 25, hard-capped at 100)"
|
|
37896
|
+
)
|
|
37094
37897
|
},
|
|
37095
|
-
withToolLogging("
|
|
37898
|
+
withToolLogging("platform_experiment_list_runs", async (params) => {
|
|
37096
37899
|
requireApiKey();
|
|
37097
|
-
const { handleRunEvaluation: handleRunEvaluation2 } = await Promise.resolve().then(() => (init_run_evaluation(), run_evaluation_exports));
|
|
37098
37900
|
return {
|
|
37099
|
-
content: [{ type: "text", text: await
|
|
37901
|
+
content: [{ type: "text", text: await handleExperimentListRuns(params) }]
|
|
37100
37902
|
};
|
|
37101
37903
|
})
|
|
37102
37904
|
);
|
|
37103
37905
|
server.tool(
|
|
37104
|
-
"
|
|
37105
|
-
"
|
|
37906
|
+
"platform_experiment_results",
|
|
37907
|
+
"Fetch per-row results for an experiment run so you can debug evaluator scores and missed rows. Serves partial results for runs that are still running or were interrupted (it does not require a completed run), with the run status noted in the output. Returns a markdown report: per-evaluator averages plus row-by-row scores and failure details. Output is capped at 50 rows to protect the agent's context window \u2014 narrow with `filter: 'failed'` or `evaluator` to see what matters.",
|
|
37106
37908
|
{
|
|
37107
|
-
runId: external_exports.string().describe("The run ID returned from
|
|
37909
|
+
runId: external_exports.string().describe("The run ID returned from platform_run_experiment"),
|
|
37910
|
+
experimentSlug: external_exports.string().optional().describe(
|
|
37911
|
+
"Experiment slug \u2014 required when fetching results for runs older than 24h (Redis state may have expired). Use platform_experiment_list_runs to find the slug."
|
|
37912
|
+
),
|
|
37913
|
+
filter: external_exports.enum(["all", "failed"]).optional().describe(
|
|
37914
|
+
"Filter rows: 'failed' shows only rows that errored or failed an evaluation; 'all' (default) shows everything"
|
|
37915
|
+
),
|
|
37916
|
+
evaluator: external_exports.string().optional().describe("Show only this evaluator's results (matched on `evaluator` field)"),
|
|
37917
|
+
limit: external_exports.number().int().positive().max(50).optional().describe(
|
|
37918
|
+
"Maximum number of rows to include in the markdown output (default 50, hard-capped at 50)."
|
|
37919
|
+
)
|
|
37108
37920
|
},
|
|
37109
|
-
withToolLogging("
|
|
37921
|
+
withToolLogging("platform_experiment_results", async (params) => {
|
|
37110
37922
|
requireApiKey();
|
|
37111
|
-
const { handleEvaluationStatus: handleEvaluationStatus2 } = await Promise.resolve().then(() => (init_run_evaluation(), run_evaluation_exports));
|
|
37112
37923
|
return {
|
|
37113
|
-
content: [
|
|
37924
|
+
content: [
|
|
37925
|
+
{ type: "text", text: await handleExperimentResults(params) }
|
|
37926
|
+
]
|
|
37114
37927
|
};
|
|
37115
37928
|
})
|
|
37116
37929
|
);
|
|
@@ -37269,6 +38082,141 @@ ${lines.join("\n")}`
|
|
|
37269
38082
|
};
|
|
37270
38083
|
}
|
|
37271
38084
|
);
|
|
38085
|
+
server.tool(
|
|
38086
|
+
"platform_list_projects",
|
|
38087
|
+
"List all projects in your LangWatch organization. Requires an org-level API key.",
|
|
38088
|
+
{
|
|
38089
|
+
page: external_exports.number().int().positive().optional().describe("Page number (default: 1)"),
|
|
38090
|
+
limit: external_exports.number().int().positive().max(1e3).optional().describe("Results per page (default: 100)")
|
|
38091
|
+
},
|
|
38092
|
+
withToolLogging("platform_list_projects", async (params) => {
|
|
38093
|
+
requireApiKey();
|
|
38094
|
+
const { handleListProjects: handleListProjects2 } = await Promise.resolve().then(() => (init_list_projects(), list_projects_exports));
|
|
38095
|
+
return {
|
|
38096
|
+
content: [{ type: "text", text: await handleListProjects2(params) }]
|
|
38097
|
+
};
|
|
38098
|
+
})
|
|
38099
|
+
);
|
|
38100
|
+
server.tool(
|
|
38101
|
+
"platform_get_project",
|
|
38102
|
+
"Get details of a specific project by its ID.",
|
|
38103
|
+
{
|
|
38104
|
+
id: external_exports.string().describe("The project ID")
|
|
38105
|
+
},
|
|
38106
|
+
withToolLogging("platform_get_project", async (params) => {
|
|
38107
|
+
requireApiKey();
|
|
38108
|
+
const { handleGetProject: handleGetProject2 } = await Promise.resolve().then(() => (init_get_project(), get_project_exports));
|
|
38109
|
+
return {
|
|
38110
|
+
content: [{ type: "text", text: await handleGetProject2(params) }]
|
|
38111
|
+
};
|
|
38112
|
+
})
|
|
38113
|
+
);
|
|
38114
|
+
server.tool(
|
|
38115
|
+
"platform_create_project",
|
|
38116
|
+
`Create a new project in your LangWatch organization. Returns a one-time service API key for the project.
|
|
38117
|
+
|
|
38118
|
+
You must provide either teamId (to add the project to an existing team) or newTeamName (to create a new team for the project).`,
|
|
38119
|
+
{
|
|
38120
|
+
name: external_exports.string().describe("Project name"),
|
|
38121
|
+
language: external_exports.string().describe('Programming language (e.g. "python", "typescript")'),
|
|
38122
|
+
framework: external_exports.string().describe('Framework (e.g. "openai", "langchain", "custom")'),
|
|
38123
|
+
teamId: external_exports.string().optional().describe("ID of an existing team to add the project to"),
|
|
38124
|
+
newTeamName: external_exports.string().optional().describe("Name for a new team to create for this project")
|
|
38125
|
+
},
|
|
38126
|
+
withToolLogging("platform_create_project", async (params) => {
|
|
38127
|
+
requireApiKey();
|
|
38128
|
+
const { handleCreateProject: handleCreateProject2 } = await Promise.resolve().then(() => (init_create_project(), create_project_exports));
|
|
38129
|
+
return {
|
|
38130
|
+
content: [{ type: "text", text: await handleCreateProject2(params) }]
|
|
38131
|
+
};
|
|
38132
|
+
})
|
|
38133
|
+
);
|
|
38134
|
+
server.tool(
|
|
38135
|
+
"platform_update_project",
|
|
38136
|
+
"Update an existing project's name, language, framework, or PII redaction level.",
|
|
38137
|
+
{
|
|
38138
|
+
id: external_exports.string().describe("The project ID to update"),
|
|
38139
|
+
name: external_exports.string().optional().describe("New project name"),
|
|
38140
|
+
language: external_exports.string().optional().describe("New programming language"),
|
|
38141
|
+
framework: external_exports.string().optional().describe("New framework"),
|
|
38142
|
+
piiRedactionLevel: external_exports.enum(["STRICT", "ESSENTIAL", "DISABLED"]).optional().describe("PII redaction level")
|
|
38143
|
+
},
|
|
38144
|
+
withToolLogging("platform_update_project", async (params) => {
|
|
38145
|
+
requireApiKey();
|
|
38146
|
+
const { handleUpdateProject: handleUpdateProject2 } = await Promise.resolve().then(() => (init_update_project(), update_project_exports));
|
|
38147
|
+
return {
|
|
38148
|
+
content: [{ type: "text", text: await handleUpdateProject2(params) }]
|
|
38149
|
+
};
|
|
38150
|
+
})
|
|
38151
|
+
);
|
|
38152
|
+
server.tool(
|
|
38153
|
+
"platform_archive_project",
|
|
38154
|
+
"Archive (soft-delete) a project. The project can be restored later if needed.",
|
|
38155
|
+
{
|
|
38156
|
+
id: external_exports.string().describe("The project ID to archive")
|
|
38157
|
+
},
|
|
38158
|
+
withToolLogging("platform_archive_project", async (params) => {
|
|
38159
|
+
requireApiKey();
|
|
38160
|
+
const { handleArchiveProject: handleArchiveProject2 } = await Promise.resolve().then(() => (init_archive_project(), archive_project_exports));
|
|
38161
|
+
return {
|
|
38162
|
+
content: [{ type: "text", text: await handleArchiveProject2(params) }]
|
|
38163
|
+
};
|
|
38164
|
+
})
|
|
38165
|
+
);
|
|
38166
|
+
server.tool(
|
|
38167
|
+
"platform_list_api_keys",
|
|
38168
|
+
"List all API keys in your LangWatch organization. Shows key metadata, status (active/revoked/expired), and role bindings. API key tokens are never returned.",
|
|
38169
|
+
{},
|
|
38170
|
+
withToolLogging("platform_list_api_keys", async () => {
|
|
38171
|
+
requireApiKey();
|
|
38172
|
+
const { handleListApiKeys: handleListApiKeys2 } = await Promise.resolve().then(() => (init_list_api_keys(), list_api_keys_exports));
|
|
38173
|
+
return {
|
|
38174
|
+
content: [{ type: "text", text: await handleListApiKeys2() }]
|
|
38175
|
+
};
|
|
38176
|
+
})
|
|
38177
|
+
);
|
|
38178
|
+
server.tool(
|
|
38179
|
+
"platform_create_api_key",
|
|
38180
|
+
`Create a new API key. Two types available:
|
|
38181
|
+
|
|
38182
|
+
- **personal**: Tied to a user, requires explicit role bindings (e.g. ADMIN on PROJECT:proj_123).
|
|
38183
|
+
- **service**: Not tied to a user. Use projectIds for project-scoped service keys, or omit for org-wide access.
|
|
38184
|
+
|
|
38185
|
+
The token is returned once and cannot be retrieved again.`,
|
|
38186
|
+
{
|
|
38187
|
+
keyType: external_exports.enum(["personal", "service"]).describe("Key type: 'personal' (user-tied) or 'service' (headless)"),
|
|
38188
|
+
name: external_exports.string().describe("Key name (max 100 chars)"),
|
|
38189
|
+
description: external_exports.string().optional().describe("Key description (max 500 chars)"),
|
|
38190
|
+
expiresAt: external_exports.string().optional().describe("Expiration date (ISO string)"),
|
|
38191
|
+
bindings: external_exports.array(external_exports.object({
|
|
38192
|
+
role: external_exports.enum(["ADMIN", "MEMBER", "VIEWER"]).describe("Role"),
|
|
38193
|
+
scopeType: external_exports.enum(["ORGANIZATION", "TEAM", "PROJECT"]).describe("Scope type"),
|
|
38194
|
+
scopeId: external_exports.string().describe("Scope ID (org, team, or project ID)")
|
|
38195
|
+
})).optional().describe("Role bindings (required for personal keys)"),
|
|
38196
|
+
projectIds: external_exports.array(external_exports.string()).optional().describe("Project IDs for service keys (creates ADMIN bindings per project)")
|
|
38197
|
+
},
|
|
38198
|
+
withToolLogging("platform_create_api_key", async (params) => {
|
|
38199
|
+
requireApiKey();
|
|
38200
|
+
const { handleCreateApiKey: handleCreateApiKey2 } = await Promise.resolve().then(() => (init_create_api_key(), create_api_key_exports));
|
|
38201
|
+
return {
|
|
38202
|
+
content: [{ type: "text", text: await handleCreateApiKey2(params) }]
|
|
38203
|
+
};
|
|
38204
|
+
})
|
|
38205
|
+
);
|
|
38206
|
+
server.tool(
|
|
38207
|
+
"platform_revoke_api_key",
|
|
38208
|
+
"Revoke an API key. Once revoked, the key can no longer be used for authentication.",
|
|
38209
|
+
{
|
|
38210
|
+
id: external_exports.string().describe("The API key ID to revoke")
|
|
38211
|
+
},
|
|
38212
|
+
withToolLogging("platform_revoke_api_key", async (params) => {
|
|
38213
|
+
requireApiKey();
|
|
38214
|
+
const { handleRevokeApiKey: handleRevokeApiKey2 } = await Promise.resolve().then(() => (init_revoke_api_key(), revoke_api_key_exports));
|
|
38215
|
+
return {
|
|
38216
|
+
content: [{ type: "text", text: await handleRevokeApiKey2(params) }]
|
|
38217
|
+
};
|
|
38218
|
+
})
|
|
38219
|
+
);
|
|
37272
38220
|
}
|
|
37273
38221
|
var modelSchema;
|
|
37274
38222
|
var init_create_mcp_server = __esm({
|
|
@@ -37279,6 +38227,10 @@ var init_create_mcp_server = __esm({
|
|
|
37279
38227
|
init_package();
|
|
37280
38228
|
init_config();
|
|
37281
38229
|
init_create_dataset();
|
|
38230
|
+
init_get_experiment_results();
|
|
38231
|
+
init_list_experiment_runs();
|
|
38232
|
+
init_list_experiments();
|
|
38233
|
+
init_run_experiment();
|
|
37282
38234
|
modelSchema = external_exports.string().describe(
|
|
37283
38235
|
'Model in "provider/model-name" format, e.g., "openai/gpt-4o", "anthropic/claude-sonnet-4-5-20250929"'
|
|
37284
38236
|
);
|
|
@@ -62565,7 +63517,8 @@ async function startHttpServer({
|
|
|
62565
63517
|
});
|
|
62566
63518
|
const sseSessions = {};
|
|
62567
63519
|
app.get("/sse", async (req, res) => {
|
|
62568
|
-
const apiKey = extractBearerToken(req) ||
|
|
63520
|
+
const apiKey = extractBearerToken(req) || // lgtm[js/sensitive-get-query]
|
|
63521
|
+
req.query["apiKey"] || null;
|
|
62569
63522
|
if (!apiKey) {
|
|
62570
63523
|
res.status(401).json({
|
|
62571
63524
|
error: "Authorization: Bearer <LANGWATCH_API_KEY> header or ?apiKey= query parameter required"
|