@langwatch/mcp-server 1.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.python-version +1 -0
- package/CHANGELOG.md +110 -0
- package/CONTRIBUTING.md +1 -1
- package/README.md +86 -4
- package/dist/{archive-project-MK3673A7.js → archive-project-W3IKI7UL.js} +5 -5
- package/dist/archive-run-plan-474OKHHU.js +16 -0
- package/dist/{archive-scenario-KATSXRIN.js → archive-scenario-V5UNYK26.js} +5 -5
- package/dist/archive-test-suite-O7FLDMXK.js +16 -0
- package/dist/{assign-prompt-tag-E3C5W6PI.js → assign-prompt-tag-Q46WRB6P.js} +4 -4
- package/dist/chunk-56OGTS24.js +44 -0
- package/dist/chunk-6DJDEXET.js +63 -0
- package/dist/chunk-7E4FZIYJ.js +15 -0
- package/dist/{chunk-J45SVWPR.js → chunk-AN4OUA4D.js} +2 -2
- package/dist/chunk-CKNAH5TG.js +74 -0
- package/dist/{chunk-CE6QMZOP.js → chunk-EYXMLE5X.js} +86 -11
- package/dist/{chunk-XY4STOBE.js → chunk-G4ZAZTZW.js} +2 -2
- package/dist/{chunk-5UWY24RP.js → chunk-GELJ2MQR.js} +12 -3
- package/dist/chunk-HV4DWKBI.js +46 -0
- package/dist/chunk-JR6DJZOU.js +49 -0
- package/dist/{chunk-DAIQKS27.js → chunk-JTQJRNFJ.js} +2 -2
- package/dist/{chunk-WWMDHZZV.js → chunk-K37ZNPXK.js} +2 -2
- package/dist/{chunk-EU22L52K.js → chunk-OJLYYJWI.js} +2 -2
- package/dist/{chunk-Y3HDZ6OW.js → chunk-QAMP3CGR.js} +2 -2
- package/dist/{chunk-VYPSKRPN.js → chunk-QRO35SOM.js} +347 -146
- package/dist/{chunk-O3LWVN67.js → chunk-RVAE2MEA.js} +2 -2
- package/dist/{chunk-UXXA4D6K.js → chunk-S4GVX36W.js} +2 -2
- package/dist/{chunk-BJ7B4R26.js → chunk-SAS5OB7F.js} +18 -2
- package/dist/{chunk-RYRB2YVJ.js → chunk-SR6QPRIE.js} +2 -2
- package/dist/chunk-UF6XIGYR.js +58 -0
- package/dist/{chunk-T7WJVS2N.js → chunk-UFOYFYI7.js} +2 -2
- package/dist/chunk-UJPXFA26.js +267 -0
- package/dist/{chunk-KOO5733S.js → chunk-WT4PO4A3.js} +8 -2
- package/dist/config.js +2 -2
- package/dist/{create-agent-7W57J7MT.js → create-agent-JFJ2K6X3.js} +5 -5
- package/dist/{create-annotation-W2XELBCQ.js → create-annotation-EUXXQ6NS.js} +5 -5
- package/dist/{create-api-key-MKRXKFJM.js → create-api-key-BGBB76JX.js} +5 -5
- package/dist/{create-dashboard-QGL7IODC.js → create-dashboard-Z76AIPLS.js} +5 -5
- package/dist/{create-dataset-3PH7A4HG.js → create-dataset-FD5VAXU4.js} +5 -5
- package/dist/{create-dataset-records-4DZS3VRL.js → create-dataset-records-WQUXXOHI.js} +5 -5
- package/dist/{create-evaluator-YWH6NC4M.js → create-evaluator-6NV33Z52.js} +5 -5
- package/dist/create-mcp-server.js +9 -4
- package/dist/{create-project-BOBQ32C5.js → create-project-ZQ7TFIO2.js} +5 -5
- package/dist/{create-prompt-FLCFGITE.js → create-prompt-BS6QRCUU.js} +4 -4
- package/dist/{create-prompt-tag-EMPNIKEA.js → create-prompt-tag-FCQ5ELSQ.js} +4 -4
- package/dist/{create-scenario-BSBIHUL6.js → create-scenario-DRPTPXU3.js} +12 -5
- package/dist/create-test-suite-ZIZCCFJ4.js +37 -0
- package/dist/{delete-agent-7MSYNY5E.js → delete-agent-SA4JMUZF.js} +5 -5
- package/dist/{delete-annotation-ZT5IGN24.js → delete-annotation-X3KKK7QY.js} +5 -5
- package/dist/{delete-dashboard-BTIY5S3L.js → delete-dashboard-LYMRPF27.js} +5 -5
- package/dist/{delete-dataset-U45HQHPR.js → delete-dataset-W6EZ44HY.js} +5 -5
- package/dist/{delete-dataset-records-R43IMAWB.js → delete-dataset-records-7CNOTALB.js} +5 -5
- package/dist/{delete-evaluator-U6JMQ6C7.js → delete-evaluator-RKYC4TNB.js} +5 -5
- package/dist/{delete-prompt-tag-4EV4TDHB.js → delete-prompt-tag-QB3OCZUV.js} +4 -4
- package/dist/{delete-workflow-5QYALXEL.js → delete-workflow-NG2VXYYM.js} +5 -5
- package/dist/{discover-evaluator-schema-MRGHVNTT.js → discover-evaluator-schema-ESSHQGPY.js} +58 -321
- package/dist/{discover-scenario-schema-UPBTCWPG.js → discover-scenario-schema-W7KBXA4J.js} +54 -2
- package/dist/{discover-schema-ICGXPHUW.js → discover-schema-L6QDPON3.js} +2 -2
- package/dist/get-agent-7THF7HCU.js +66 -0
- package/dist/{get-analytics-PVERWOA5.js → get-analytics-R6AZD3AW.js} +4 -4
- package/dist/{get-dashboard-ZZPC3WMD.js → get-dashboard-P4WWVHFU.js} +5 -5
- package/dist/{get-dataset-25TB2LQH.js → get-dataset-AKTYSQDI.js} +5 -5
- package/dist/{get-evaluator-3FTRQKEC.js → get-evaluator-RZ44UIN6.js} +5 -5
- package/dist/{get-project-5OAXYC57.js → get-project-QSQEAB33.js} +5 -5
- package/dist/get-prompt-GVKXF5NL.js +100 -0
- package/dist/get-run-plan-NY7J5GRE.js +61 -0
- package/dist/{get-scenario-DSSTR6FI.js → get-scenario-Q3LLQE4T.js} +9 -5
- package/dist/{get-simulation-run-RQPMS2MC.js → get-simulation-run-WINEYDMK.js} +14 -5
- package/dist/get-test-suite-4HKA7OKS.js +49 -0
- package/dist/{get-trace-O5VT3NAC.js → get-trace-RCUV7N4O.js} +4 -4
- package/dist/{get-workflow-3EZDOEIF.js → get-workflow-EEOC7Y45.js} +5 -5
- package/dist/http-security-EU3CHTY7.js +26 -0
- package/dist/{http-server-2ACJ3CXW.js → http-server-WCDUARTH.js} +1038 -693
- package/dist/index.js +6437 -4020
- package/dist/{langwatch-api-annotations-E65MI3WZ.js → langwatch-api-annotations-6DHVZWUK.js} +5 -5
- package/dist/{langwatch-api-dashboards-QCDECRCY.js → langwatch-api-dashboards-2KJL2M42.js} +5 -5
- package/dist/{langwatch-api-monitors-UIO2KTDV.js → langwatch-api-monitors-6ISFJ7WX.js} +4 -4
- package/dist/{langwatch-api-secrets-4T2EKSJ7.js → langwatch-api-secrets-OEBD6GBU.js} +4 -4
- package/dist/{langwatch-api-triggers-MPOEKPUY.js → langwatch-api-triggers-5E6DDGX6.js} +4 -4
- package/dist/langwatch-api-workflows-6UJL5U4Z.js +16 -0
- package/dist/list-agents-AMVDQPQL.js +43 -0
- package/dist/{list-annotations-CGX5BT7E.js → list-annotations-6PR5NLIC.js} +5 -5
- package/dist/{list-api-keys-JLWJPFRX.js → list-api-keys-GVPNBIHQ.js} +5 -5
- package/dist/{list-dashboards-RNIWX3TX.js → list-dashboards-Z3BZKDGF.js} +5 -5
- package/dist/{list-dataset-records-B5MHZR66.js → list-dataset-records-O67HZ35Y.js} +5 -5
- package/dist/{list-datasets-BVCAMQCP.js → list-datasets-WXZL6UMP.js} +5 -5
- package/dist/{list-evaluators-65FBTL2U.js → list-evaluators-PAX72WCN.js} +5 -5
- package/dist/{list-model-providers-GRK3I3VV.js → list-model-providers-VVLZMLCX.js} +5 -5
- package/dist/{list-projects-JLMBFMW3.js → list-projects-AQVI6SUK.js} +5 -5
- package/dist/{list-prompt-tags-UHNWDGQI.js → list-prompt-tags-WZFBJOHG.js} +4 -4
- package/dist/{list-prompts-7254B3U7.js → list-prompts-BQOHRHYT.js} +4 -4
- package/dist/list-run-plans-UBAU2DGH.js +46 -0
- package/dist/{list-scenarios-46YNICKM.js → list-scenarios-MS4IUIVM.js} +10 -7
- package/dist/{list-simulation-runs-LGNEFNPN.js → list-simulation-runs-D6YF4ZOU.js} +13 -7
- package/dist/list-test-suites-L7R2O6DR.js +35 -0
- package/dist/{list-workflows-MLQDM6CP.js → list-workflows-6MV4XJHF.js} +5 -5
- package/dist/{rename-prompt-tag-RHQMNEQL.js → rename-prompt-tag-K5LQ4CY6.js} +4 -4
- package/dist/rename-test-suite-NTYHAO5X.js +21 -0
- package/dist/report-issue-RHZZ33IS.js +885 -0
- package/dist/rerun-run-plan-MUDWJBE4.js +22 -0
- package/dist/{revoke-api-key-3Y35EMBT.js → revoke-api-key-6LAZ3QZZ.js} +5 -5
- package/dist/run-agent-CAGWGTYT.js +72 -0
- package/dist/run-plan-T4ZYOZGA.js +39 -0
- package/dist/run-test-suite-L4MZ7G4D.js +26 -0
- package/dist/{run-workflow-5LVBZYLS.js → run-workflow-DFIS23AP.js} +5 -5
- package/dist/{search-traces-U4HLOCZ2.js → search-traces-4XTJYXIK.js} +4 -4
- package/dist/{set-model-provider-V3M5CDIY.js → set-model-provider-XRNMFOVR.js} +5 -5
- package/dist/{update-agent-47RZIHS7.js → update-agent-DUWNYBNA.js} +5 -5
- package/dist/{update-dataset-G6QJJGS5.js → update-dataset-YSOMDCOB.js} +5 -5
- package/dist/{update-dataset-record-RMWLSWCS.js → update-dataset-record-DEA2ITYR.js} +5 -5
- package/dist/{update-evaluator-SFRRI5Q3.js → update-evaluator-NH7Q5GWV.js} +5 -5
- package/dist/{update-project-PI5DWBVK.js → update-project-Q26FBSYH.js} +5 -5
- package/dist/update-prompt-ZQQ2C3KU.js +143 -0
- package/dist/{update-scenario-G3IU2UIB.js → update-scenario-WUX34JAR.js} +12 -5
- package/package.json +8 -9
- package/pyproject.toml +5 -5
- package/src/__tests__/agent-tools.unit.test.ts +257 -0
- package/src/__tests__/all-tools.integration.test.ts +321 -75
- package/src/__tests__/config.unit.test.ts +33 -0
- package/src/__tests__/docker.integration.test.ts +91 -7
- package/src/__tests__/documentation-fetch-security.integration.test.ts +8 -2
- package/src/__tests__/feature-map-tool-drift.unit.test.ts +93 -0
- package/src/__tests__/http-security-origin.unit.test.ts +97 -0
- package/src/__tests__/http-security-sessions.unit.test.ts +209 -0
- package/src/__tests__/http-security-verifier.unit.test.ts +248 -0
- package/src/__tests__/http-server-allocation.integration.test.ts +279 -0
- package/src/__tests__/http-server-origin.integration.test.ts +169 -0
- package/src/__tests__/http-server-session-auth.integration.test.ts +341 -0
- package/src/__tests__/http-transport.integration.test.ts +85 -87
- package/src/__tests__/integration.integration.test.ts +7 -11
- package/src/__tests__/prompt-response-types.unit.test.ts +51 -0
- package/src/__tests__/prompts.integration.test.ts +736 -0
- package/src/__tests__/run-plan-tools.unit.test.ts +565 -0
- package/src/__tests__/scenario-tools.unit.test.ts +19 -0
- package/src/__tests__/simulation-run-tools.unit.test.ts +116 -0
- package/src/__tests__/support/http-server-harness.ts +138 -0
- package/src/__tests__/test-suite-tools.unit.test.ts +615 -0
- package/src/__tests__/{tools.unit.test.ts → tools.integration.test.ts} +31 -59
- package/src/config.ts +17 -2
- package/src/create-mcp-server.ts +334 -55
- package/src/http-security.ts +492 -0
- package/src/http-server.ts +536 -152
- package/src/index.ts +49 -2
- package/src/langwatch-api-agents.ts +196 -12
- package/src/langwatch-api-run-plans.ts +157 -0
- package/src/langwatch-api-scenarios.ts +9 -0
- package/src/langwatch-api-simulation-runs.ts +5 -0
- package/src/langwatch-api-test-suites.ts +135 -0
- package/src/langwatch-api.ts +62 -12
- package/src/schemas/index.ts +5 -0
- package/src/schemas/run-plan.ts +92 -0
- package/src/schemas/suite-fields.ts +149 -0
- package/src/tools/archive-run-plan.ts +12 -0
- package/src/tools/archive-test-suite.ts +12 -0
- package/src/tools/create-scenario.ts +8 -0
- package/src/tools/create-test-suite.ts +43 -0
- package/src/tools/discover-evaluator-schema.ts +2 -2
- package/src/tools/discover-scenario-schema.ts +54 -0
- package/src/tools/format-run-plan.ts +68 -0
- package/src/tools/format-scenario.ts +14 -0
- package/src/tools/format-suite-details.ts +96 -0
- package/src/tools/get-agent.ts +45 -3
- package/src/tools/get-prompt.ts +108 -24
- package/src/tools/get-run-plan.ts +62 -0
- package/src/tools/get-scenario.ts +3 -0
- package/src/tools/get-simulation-run.ts +9 -0
- package/src/tools/get-test-suite.ts +49 -0
- package/src/tools/list-agents.ts +20 -3
- package/src/tools/list-run-plans.ts +47 -0
- package/src/tools/list-scenarios.ts +12 -2
- package/src/tools/list-simulation-runs.ts +6 -2
- package/src/tools/list-test-suites.ts +35 -0
- package/src/tools/rename-test-suite.ts +18 -0
- package/src/tools/rerun-run-plan.ts +21 -0
- package/src/tools/run-agent.ts +54 -6
- package/src/tools/run-plan.ts +49 -0
- package/src/tools/run-test-suite.ts +30 -0
- package/src/tools/test-agent.ts +18 -0
- package/src/tools/update-prompt.ts +195 -10
- package/src/tools/update-scenario.ts +8 -0
- package/src/tools/update-test-suite.ts +45 -0
- package/tsconfig.json +7 -2
- package/uv.lock +418 -298
- package/dist/archive-suite-C3KX6IIZ.js +0 -16
- package/dist/chunk-WDH5P5RF.js +0 -48
- package/dist/create-suite-TWF6BBR4.js +0 -39
- package/dist/get-agent-7QJVPH72.js +0 -29
- package/dist/get-prompt-I753LZKZ.js +0 -46
- package/dist/get-suite-GTOCY5PL.js +0 -45
- package/dist/langwatch-api-workflows-5HRZ7HR4.js +0 -16
- package/dist/list-agents-TIJTP566.js +0 -33
- package/dist/list-suites-5VK4HXEK.js +0 -43
- package/dist/report-issue-DXJ6TPTC.js +0 -412
- package/dist/run-agent-RBSIFKRT.js +0 -37
- package/dist/run-suite-K3DNQ3SE.js +0 -30
- package/dist/update-prompt-RQFTEO7Y.js +0 -25
- package/dist/update-suite-TRGGLNR7.js +0 -40
- package/pnpm-workspace.yaml +0 -34
- package/src/langwatch-api-suites.ts +0 -118
- package/src/tools/archive-suite.ts +0 -12
- package/src/tools/create-suite.ts +0 -42
- package/src/tools/get-suite.ts +0 -47
- package/src/tools/list-suites.ts +0 -43
- package/src/tools/run-suite.ts +0 -28
- package/src/tools/update-suite.ts +0 -44
package/src/index.ts
CHANGED
|
@@ -24,6 +24,17 @@ const argv = await yargs(hideBin(process.argv))
|
|
|
24
24
|
description: "HTTP server port (only used with --http)",
|
|
25
25
|
default: 3000,
|
|
26
26
|
})
|
|
27
|
+
.option("host", {
|
|
28
|
+
type: "string",
|
|
29
|
+
description:
|
|
30
|
+
"HTTP listen address (only used with --http). Defaults to loopback; pass 0.0.0.0 to accept connections from other machines",
|
|
31
|
+
})
|
|
32
|
+
.option("allowedOrigin", {
|
|
33
|
+
type: "array",
|
|
34
|
+
string: true,
|
|
35
|
+
description:
|
|
36
|
+
"Browser origin allowed to call the HTTP server, repeatable. Loopback origins are always allowed",
|
|
37
|
+
})
|
|
27
38
|
.help()
|
|
28
39
|
.parseAsync();
|
|
29
40
|
|
|
@@ -34,11 +45,47 @@ initConfig({
|
|
|
34
45
|
|
|
35
46
|
if (argv.http) {
|
|
36
47
|
const { startHttpServer } = await import("./http-server.js");
|
|
37
|
-
const {
|
|
38
|
-
|
|
48
|
+
const { isLoopbackHost, parseAllowedOrigins } = await import(
|
|
49
|
+
"./http-security.js"
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
const allowedOrigins =
|
|
53
|
+
argv.allowedOrigin && argv.allowedOrigin.length > 0
|
|
54
|
+
? parseAllowedOrigins(argv.allowedOrigin.join(","))
|
|
55
|
+
: undefined;
|
|
56
|
+
|
|
57
|
+
const { port, host } = await startHttpServer({
|
|
58
|
+
port: argv.port,
|
|
59
|
+
host: argv.host,
|
|
60
|
+
allowedOrigins,
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
// An IPv6 literal has to be bracketed inside a URL, and must not be
|
|
64
|
+
// double-bracketed when the operator already wrote it that way.
|
|
65
|
+
const displayHost =
|
|
66
|
+
host.includes(":") && !host.startsWith("[") ? `[${host}]` : host;
|
|
67
|
+
console.log(
|
|
68
|
+
`LangWatch MCP server listening on http://${displayHost}:${port}/mcp`
|
|
69
|
+
);
|
|
39
70
|
console.log(
|
|
40
71
|
"Clients must provide their API key via Authorization: Bearer <key> header"
|
|
41
72
|
);
|
|
73
|
+
if (!isLoopbackHost(host)) {
|
|
74
|
+
console.warn(
|
|
75
|
+
`Warning: bound to ${host}, so the server is reachable from other machines. ` +
|
|
76
|
+
"Make sure it sits behind a trusted network boundary and that --allowedOrigin " +
|
|
77
|
+
"lists only origins you control."
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
if (process.env.LANGWATCH_MCP_TRUST_PROXY === "true") {
|
|
81
|
+
console.warn(
|
|
82
|
+
"Warning: LANGWATCH_MCP_TRUST_PROXY=true, so the rate limit on failed " +
|
|
83
|
+
"authentication uses the client address from X-Forwarded-For. Keep this " +
|
|
84
|
+
"on only when a trusted proxy terminates in front of the port and " +
|
|
85
|
+
"overwrites that header. Otherwise a client can supply any address there " +
|
|
86
|
+
"and the limit stops counting."
|
|
87
|
+
);
|
|
88
|
+
}
|
|
42
89
|
} else {
|
|
43
90
|
const transport = new StdioServerTransport();
|
|
44
91
|
const server = createMcpServer();
|
|
@@ -1,6 +1,42 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
1
3
|
import { makeRequest } from "./langwatch-api.js";
|
|
2
4
|
import { requestPublicJson } from "./public-http-request.js";
|
|
3
5
|
|
|
6
|
+
/**
|
|
7
|
+
* The run parameters a call carries: a flat record of scalars. The platform
|
|
8
|
+
* declares run parameters as `string`, `number` or `boolean`, so a nested
|
|
9
|
+
* object or an array is outside the contract and is refused here.
|
|
10
|
+
*/
|
|
11
|
+
export const agentCallParamsSchema = z.record(
|
|
12
|
+
z.string(),
|
|
13
|
+
z.union([z.string(), z.number(), z.boolean()]),
|
|
14
|
+
);
|
|
15
|
+
|
|
16
|
+
export type AgentCallParams = z.infer<typeof agentCallParamsSchema>;
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* One run parameter an agent declares, as the platform lists it. An agent
|
|
20
|
+
* never declares a secret parameter: a secret belongs to the scenario and is
|
|
21
|
+
* supplied per run.
|
|
22
|
+
*/
|
|
23
|
+
export interface AgentParameterSpec {
|
|
24
|
+
name: string;
|
|
25
|
+
type: "string" | "number" | "boolean";
|
|
26
|
+
options?: string[];
|
|
27
|
+
default?: string | number | boolean;
|
|
28
|
+
description?: string;
|
|
29
|
+
required?: boolean;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** One process connected as an instance of a connected agent. */
|
|
33
|
+
export interface AgentInstance {
|
|
34
|
+
id: string;
|
|
35
|
+
hostname: string;
|
|
36
|
+
label?: string | null;
|
|
37
|
+
connectedAt: string;
|
|
38
|
+
}
|
|
39
|
+
|
|
4
40
|
export interface AgentSummary {
|
|
5
41
|
id: string;
|
|
6
42
|
name: string;
|
|
@@ -8,6 +44,19 @@ export interface AgentSummary {
|
|
|
8
44
|
config: Record<string, unknown> | null;
|
|
9
45
|
createdAt: string;
|
|
10
46
|
updatedAt: string;
|
|
47
|
+
/** Connected agents: the environment the SDK registered under. */
|
|
48
|
+
environment?: string | null;
|
|
49
|
+
/** Connected agents: online while at least one instance is connected. */
|
|
50
|
+
status?: "online" | "offline" | null;
|
|
51
|
+
instances?: AgentInstance[];
|
|
52
|
+
lastSeenAt?: string | null;
|
|
53
|
+
owner?: { userId: string; name: string } | null;
|
|
54
|
+
hostLabel?: string | null;
|
|
55
|
+
/** Whether this key can run the agent. */
|
|
56
|
+
selectable?: boolean;
|
|
57
|
+
/** Why the agent cannot be run with this key; null when it can. */
|
|
58
|
+
notSelectableReason?: "owned_by_another_person" | null;
|
|
59
|
+
parameters?: AgentParameterSpec[];
|
|
11
60
|
}
|
|
12
61
|
|
|
13
62
|
export interface AgentListResponse {
|
|
@@ -20,6 +69,31 @@ export interface AgentListResponse {
|
|
|
20
69
|
};
|
|
21
70
|
}
|
|
22
71
|
|
|
72
|
+
/** One conversation message as the relay carries it, OpenAI style. */
|
|
73
|
+
export interface AgentCallMessage {
|
|
74
|
+
role: string;
|
|
75
|
+
content?: unknown;
|
|
76
|
+
[key: string]: unknown;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** The body `POST /api/v1/agents/:id/call` takes. */
|
|
80
|
+
export interface AgentCallBody {
|
|
81
|
+
messages: AgentCallMessage[];
|
|
82
|
+
newMessages?: AgentCallMessage[];
|
|
83
|
+
threadId?: string;
|
|
84
|
+
params?: AgentCallParams;
|
|
85
|
+
session?: unknown;
|
|
86
|
+
traceparent?: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** The reply of the relay: the function's output and the instance that ran it. */
|
|
90
|
+
export interface AgentCallResponse {
|
|
91
|
+
output: unknown;
|
|
92
|
+
session?: unknown;
|
|
93
|
+
instance: { hostname: string; label?: string | null };
|
|
94
|
+
durationMs: number;
|
|
95
|
+
}
|
|
96
|
+
|
|
23
97
|
export async function listAgents(params?: {
|
|
24
98
|
page?: number;
|
|
25
99
|
limit?: number;
|
|
@@ -28,13 +102,13 @@ export async function listAgents(params?: {
|
|
|
28
102
|
if (params?.page) query.set("page", String(params.page));
|
|
29
103
|
if (params?.limit) query.set("limit", String(params.limit));
|
|
30
104
|
const qs = query.toString() ? `?${query}` : "";
|
|
31
|
-
return makeRequest("GET", `/api/agents${qs}`) as Promise<AgentListResponse>;
|
|
105
|
+
return makeRequest("GET", `/api/v1/agents${qs}`) as Promise<AgentListResponse>;
|
|
32
106
|
}
|
|
33
107
|
|
|
34
108
|
export async function getAgent(id: string): Promise<AgentSummary> {
|
|
35
109
|
return makeRequest(
|
|
36
110
|
"GET",
|
|
37
|
-
`/api/agents/${encodeURIComponent(id)}`,
|
|
111
|
+
`/api/v1/agents/${encodeURIComponent(id)}`,
|
|
38
112
|
) as Promise<AgentSummary>;
|
|
39
113
|
}
|
|
40
114
|
|
|
@@ -43,7 +117,7 @@ export async function createAgent(data: {
|
|
|
43
117
|
type: string;
|
|
44
118
|
config: Record<string, unknown>;
|
|
45
119
|
}): Promise<AgentSummary> {
|
|
46
|
-
return makeRequest("POST", "/api/agents", data) as Promise<AgentSummary>;
|
|
120
|
+
return makeRequest("POST", "/api/v1/agents", data) as Promise<AgentSummary>;
|
|
47
121
|
}
|
|
48
122
|
|
|
49
123
|
export async function updateAgent(params: {
|
|
@@ -55,22 +129,132 @@ export async function updateAgent(params: {
|
|
|
55
129
|
const { id, ...data } = params;
|
|
56
130
|
return makeRequest(
|
|
57
131
|
"PATCH",
|
|
58
|
-
`/api/agents/${encodeURIComponent(id)}`,
|
|
132
|
+
`/api/v1/agents/${encodeURIComponent(id)}`,
|
|
59
133
|
data,
|
|
60
134
|
) as Promise<AgentSummary>;
|
|
61
135
|
}
|
|
62
136
|
|
|
63
137
|
/**
|
|
64
|
-
*
|
|
65
|
-
*
|
|
138
|
+
* Runs one turn of a connected agent through the relay: the platform
|
|
139
|
+
* dispatches it to a live instance and answers with the function's output.
|
|
140
|
+
*/
|
|
141
|
+
export async function callAgent({
|
|
142
|
+
id,
|
|
143
|
+
body,
|
|
144
|
+
}: {
|
|
145
|
+
id: string;
|
|
146
|
+
body: AgentCallBody;
|
|
147
|
+
}): Promise<AgentCallResponse> {
|
|
148
|
+
return makeRequest(
|
|
149
|
+
"POST",
|
|
150
|
+
`/api/v1/agents/${encodeURIComponent(id)}/call`,
|
|
151
|
+
body,
|
|
152
|
+
) as Promise<AgentCallResponse>;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/** The ids `POST /api/v1/agents/:id/test` answers with. */
|
|
156
|
+
export interface AgentTestRunResponse {
|
|
157
|
+
scenarioRunId: string;
|
|
158
|
+
batchRunId: string;
|
|
159
|
+
setId: string;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Runs one scripted scenario against an agent: the user sends "ping", the
|
|
164
|
+
* agent answers, and the run succeeds when the answer arrives. The project
|
|
165
|
+
* gains no scenario, run plan or test suite, and the answer carries the run
|
|
166
|
+
* ids to follow.
|
|
167
|
+
*/
|
|
168
|
+
export async function testAgent(id: string): Promise<AgentTestRunResponse> {
|
|
169
|
+
return makeRequest(
|
|
170
|
+
"POST",
|
|
171
|
+
`/api/v1/agents/${encodeURIComponent(id)}/test`,
|
|
172
|
+
{},
|
|
173
|
+
) as Promise<AgentTestRunResponse>;
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const isMessageList = (value: unknown): value is AgentCallMessage[] =>
|
|
177
|
+
Array.isArray(value) &&
|
|
178
|
+
value.every(
|
|
179
|
+
(item) =>
|
|
180
|
+
typeof item === "object" && item !== null && typeof (item as AgentCallMessage).role === "string",
|
|
181
|
+
);
|
|
182
|
+
|
|
183
|
+
/**
|
|
184
|
+
* The relay body for a connected agent: `message` is one user turn, `input`
|
|
185
|
+
* is the body itself (it must carry `messages`), `parameters` are the run
|
|
186
|
+
* parameters and `threadId` continues a conversation. A string is the
|
|
187
|
+
* refusal, so the tool can answer it.
|
|
188
|
+
*/
|
|
189
|
+
export function buildRelayBody({
|
|
190
|
+
input,
|
|
191
|
+
message,
|
|
192
|
+
parameters,
|
|
193
|
+
threadId,
|
|
194
|
+
}: {
|
|
195
|
+
input: Record<string, unknown>;
|
|
196
|
+
message?: string;
|
|
197
|
+
parameters?: AgentCallParams;
|
|
198
|
+
threadId?: string;
|
|
199
|
+
}): AgentCallBody | string {
|
|
200
|
+
let messages: AgentCallMessage[];
|
|
201
|
+
if (message !== undefined) {
|
|
202
|
+
messages = [{ role: "user", content: message }];
|
|
203
|
+
} else if (isMessageList(input.messages)) {
|
|
204
|
+
messages = input.messages;
|
|
205
|
+
} else {
|
|
206
|
+
return "a connected agent takes a conversation: give `message`, or `input` with a `messages` list.";
|
|
207
|
+
}
|
|
208
|
+
const body: AgentCallBody = { messages };
|
|
209
|
+
const thread = threadId ?? (typeof input.threadId === "string" ? input.threadId : undefined);
|
|
210
|
+
if (thread) body.threadId = thread;
|
|
211
|
+
if (isMessageList(input.newMessages)) body.newMessages = input.newMessages;
|
|
212
|
+
if (input.session !== undefined) body.session = input.session;
|
|
213
|
+
let inputParams: AgentCallParams | undefined;
|
|
214
|
+
if (input.params !== undefined) {
|
|
215
|
+
const parsed = agentCallParamsSchema.safeParse(input.params);
|
|
216
|
+
if (!parsed.success) {
|
|
217
|
+
return "`params` takes one flat object of string, number or boolean values. Nested objects and arrays are not run parameters.";
|
|
218
|
+
}
|
|
219
|
+
inputParams = parsed.data;
|
|
220
|
+
}
|
|
221
|
+
if (inputParams || parameters) body.params = { ...(inputParams ?? {}), ...(parameters ?? {}) };
|
|
222
|
+
return body;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
/**
|
|
226
|
+
* Run an agent. A connected agent runs one turn through the relay; an HTTP
|
|
227
|
+
* agent is called at its URL; a workflow-linked agent runs on the workflow
|
|
228
|
+
* engine.
|
|
66
229
|
*/
|
|
67
|
-
export async function runAgent(
|
|
68
|
-
id
|
|
69
|
-
input
|
|
70
|
-
|
|
230
|
+
export async function runAgent({
|
|
231
|
+
id,
|
|
232
|
+
input,
|
|
233
|
+
message,
|
|
234
|
+
parameters,
|
|
235
|
+
threadId,
|
|
236
|
+
}: {
|
|
237
|
+
id: string;
|
|
238
|
+
input?: Record<string, unknown>;
|
|
239
|
+
message?: string;
|
|
240
|
+
parameters?: AgentCallParams;
|
|
241
|
+
threadId?: string;
|
|
242
|
+
}): Promise<{ agentType: string; result: Record<string, unknown> }> {
|
|
71
243
|
const agent = await getAgent(id);
|
|
72
244
|
const config = agent.config ?? {};
|
|
73
245
|
|
|
246
|
+
if (agent.type === "connected") {
|
|
247
|
+
const body = buildRelayBody({ input: input ?? {}, message, parameters, threadId });
|
|
248
|
+
if (typeof body === "string") throw new Error(body);
|
|
249
|
+
if (agent.status === "offline") {
|
|
250
|
+
throw new Error(
|
|
251
|
+
`Agent "${agent.name}" is offline. Start the process that calls connectAgent (or connect_agent) and try again.`,
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
const result = await callAgent({ id: agent.id, body });
|
|
255
|
+
return { agentType: "connected", result: result as unknown as Record<string, unknown> };
|
|
256
|
+
}
|
|
257
|
+
|
|
74
258
|
if (agent.type === "http") {
|
|
75
259
|
const url = (config as Record<string, unknown>).url as string | undefined;
|
|
76
260
|
if (!url) {
|
|
@@ -91,7 +275,7 @@ export async function runAgent(
|
|
|
91
275
|
if (!workflowId) {
|
|
92
276
|
throw new Error(
|
|
93
277
|
`Agent "${agent.name}" (type: ${agent.type}) cannot be executed directly. ` +
|
|
94
|
-
`Only HTTP agents and workflow-linked agents can be run.`,
|
|
278
|
+
`Only connected agents, HTTP agents and workflow-linked agents can be run.`,
|
|
95
279
|
);
|
|
96
280
|
}
|
|
97
281
|
|
|
@@ -103,6 +287,6 @@ export async function runAgent(
|
|
|
103
287
|
export async function deleteAgent(id: string): Promise<{ id: string; name: string }> {
|
|
104
288
|
return makeRequest(
|
|
105
289
|
"DELETE",
|
|
106
|
-
`/api/agents/${encodeURIComponent(id)}`,
|
|
290
|
+
`/api/v1/agents/${encodeURIComponent(id)}`,
|
|
107
291
|
) as Promise<{ id: string; name: string }>;
|
|
108
292
|
}
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
import { makeRequest } from "./langwatch-api.js";
|
|
3
|
+
import type {
|
|
4
|
+
runParametersSchema,
|
|
5
|
+
runPlanScopeSchema,
|
|
6
|
+
runPlanTargetSchema,
|
|
7
|
+
RunPlanTargetWire,
|
|
8
|
+
} from "./schemas/run-plan.js";
|
|
9
|
+
import type { EvaluatorAttachmentWire } from "./schemas/suite-fields.js";
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Client for `/api/v1/run-plans`.
|
|
13
|
+
*
|
|
14
|
+
* A run plan is what you run, and its NAME identifies it: running against a
|
|
15
|
+
* name that exists replaces that plan's configuration, running against a new
|
|
16
|
+
* name creates one. Configuration is the scope, the targets, the repeat count
|
|
17
|
+
* and the two models. Parameters, the note and the idempotency key belong to
|
|
18
|
+
* one run, not to the plan.
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* The shapes the run plan tools accept, taken from the zod that validates
|
|
23
|
+
* them. They are inferred rather than written twice, so the schema stays the
|
|
24
|
+
* one place the shape is stated.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
/** What a run plan covers. Mirrors `suiteScopeSchema` on the platform. */
|
|
28
|
+
export type RunPlanScope = z.infer<typeof runPlanScopeSchema>;
|
|
29
|
+
|
|
30
|
+
/** One thing a plan runs its scenarios against, as a tool caller writes it. */
|
|
31
|
+
export type RunPlanTarget = z.infer<typeof runPlanTargetSchema>;
|
|
32
|
+
|
|
33
|
+
/** The values a run supplies for the parameters its scenarios declare. */
|
|
34
|
+
export type RunParameters = z.infer<typeof runParametersSchema>;
|
|
35
|
+
|
|
36
|
+
export interface RunPlan {
|
|
37
|
+
id: string;
|
|
38
|
+
name: string;
|
|
39
|
+
slug: string;
|
|
40
|
+
scope: RunPlanScope | null;
|
|
41
|
+
scenarioIds: string[];
|
|
42
|
+
targets: RunPlanTargetWire[];
|
|
43
|
+
repeatCount: number;
|
|
44
|
+
simulatorModel: string | null;
|
|
45
|
+
judgeModel: string | null;
|
|
46
|
+
labels: string[];
|
|
47
|
+
archivedAt: string | null;
|
|
48
|
+
createdAt: string;
|
|
49
|
+
updatedAt: string;
|
|
50
|
+
platformUrl: string;
|
|
51
|
+
/** The plan's own evaluators. Absent on servers that predate them. */
|
|
52
|
+
evaluators?: EvaluatorAttachmentWire[];
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** The configuration a run either writes onto a plan or creates it with. */
|
|
56
|
+
export interface RunPlanConfig {
|
|
57
|
+
scope: RunPlanScope;
|
|
58
|
+
targets: RunPlanTargetWire[];
|
|
59
|
+
repeatCount?: number;
|
|
60
|
+
simulatorModel?: string | null;
|
|
61
|
+
judgeModel?: string | null;
|
|
62
|
+
scenarioIds?: string[];
|
|
63
|
+
/**
|
|
64
|
+
* The plan's own evaluators, run beside the ones its test suites attach. A
|
|
65
|
+
* plan evaluator reads the conversation and the trace, never a scenario
|
|
66
|
+
* field. Left out, the plan keeps what it already holds.
|
|
67
|
+
*/
|
|
68
|
+
evaluators?: EvaluatorAttachmentWire[];
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
export interface RunPlanRunResult {
|
|
72
|
+
scheduled: boolean;
|
|
73
|
+
batchRunId: string;
|
|
74
|
+
setId: string;
|
|
75
|
+
jobCount: number;
|
|
76
|
+
skippedArchived: {
|
|
77
|
+
scenarios: string[];
|
|
78
|
+
targets: string[];
|
|
79
|
+
};
|
|
80
|
+
items: Array<{
|
|
81
|
+
scenarioRunId: string;
|
|
82
|
+
scenarioId: string;
|
|
83
|
+
target: RunPlanTargetWire;
|
|
84
|
+
name: string | null;
|
|
85
|
+
}>;
|
|
86
|
+
runPlanId: string;
|
|
87
|
+
planName: string;
|
|
88
|
+
/** True when this run created the plan, false when it joined an existing one. */
|
|
89
|
+
created: boolean;
|
|
90
|
+
platformUrl: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface RunPlanArchiveResponse {
|
|
94
|
+
id: string;
|
|
95
|
+
archived: boolean;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** Lists the run plans of the project. */
|
|
99
|
+
export async function listRunPlans(params?: {
|
|
100
|
+
includeArchived?: boolean;
|
|
101
|
+
}): Promise<RunPlan[]> {
|
|
102
|
+
const query = params?.includeArchived ? "?includeArchived=true" : "";
|
|
103
|
+
return makeRequest("GET", `/api/v1/run-plans${query}`) as Promise<RunPlan[]>;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/** Retrieves a single run plan by id. */
|
|
107
|
+
export async function getRunPlan(id: string): Promise<RunPlan> {
|
|
108
|
+
return makeRequest(
|
|
109
|
+
"GET",
|
|
110
|
+
`/api/v1/run-plans/${encodeURIComponent(id)}`,
|
|
111
|
+
) as Promise<RunPlan>;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Runs a configuration by plan name. A name that exists is replaced with this
|
|
116
|
+
* configuration, a name that does not is created. Sending no name lets the
|
|
117
|
+
* server derive one.
|
|
118
|
+
*/
|
|
119
|
+
export async function runRunPlan(data: {
|
|
120
|
+
name?: string;
|
|
121
|
+
config: RunPlanConfig;
|
|
122
|
+
idempotencyKey?: string;
|
|
123
|
+
parameters?: RunParameters;
|
|
124
|
+
note?: string;
|
|
125
|
+
}): Promise<RunPlanRunResult> {
|
|
126
|
+
return makeRequest(
|
|
127
|
+
"POST",
|
|
128
|
+
"/api/v1/run-plans/run",
|
|
129
|
+
data,
|
|
130
|
+
) as Promise<RunPlanRunResult>;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/** Runs a plan again with the configuration it already holds. */
|
|
134
|
+
export async function rerunRunPlan(
|
|
135
|
+
id: string,
|
|
136
|
+
data?: {
|
|
137
|
+
idempotencyKey?: string;
|
|
138
|
+
parameters?: RunParameters;
|
|
139
|
+
note?: string;
|
|
140
|
+
},
|
|
141
|
+
): Promise<RunPlanRunResult> {
|
|
142
|
+
return makeRequest(
|
|
143
|
+
"POST",
|
|
144
|
+
`/api/v1/run-plans/${encodeURIComponent(id)}/run`,
|
|
145
|
+
data ?? {},
|
|
146
|
+
) as Promise<RunPlanRunResult>;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Archives a run plan. */
|
|
150
|
+
export async function archiveRunPlan(
|
|
151
|
+
id: string,
|
|
152
|
+
): Promise<RunPlanArchiveResponse> {
|
|
153
|
+
return makeRequest(
|
|
154
|
+
"DELETE",
|
|
155
|
+
`/api/v1/run-plans/${encodeURIComponent(id)}`,
|
|
156
|
+
) as Promise<RunPlanArchiveResponse>;
|
|
157
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { makeRequest } from "./langwatch-api.js";
|
|
2
|
+
import type { ScenarioFieldValues } from "./schemas/suite-fields.js";
|
|
2
3
|
|
|
3
4
|
// --- Scenario types ---
|
|
4
5
|
|
|
@@ -8,6 +9,10 @@ export interface ScenarioSummary {
|
|
|
8
9
|
situation: string;
|
|
9
10
|
criteria: string[];
|
|
10
11
|
labels: string[];
|
|
12
|
+
/** The test suite this scenario is filed in, null when it is unfiled. */
|
|
13
|
+
testSuiteId?: string | null;
|
|
14
|
+
/** The scenario's value for each field its test suite declares. */
|
|
15
|
+
fields?: ScenarioFieldValues;
|
|
11
16
|
}
|
|
12
17
|
|
|
13
18
|
export interface ScenarioArchiveResponse {
|
|
@@ -36,6 +41,8 @@ export async function createScenario(data: {
|
|
|
36
41
|
situation: string;
|
|
37
42
|
criteria?: string[];
|
|
38
43
|
labels?: string[];
|
|
44
|
+
testSuiteId?: string | null;
|
|
45
|
+
fields?: ScenarioFieldValues;
|
|
39
46
|
}): Promise<ScenarioSummary> {
|
|
40
47
|
return makeRequest("POST", "/api/scenarios", data) as Promise<ScenarioSummary>;
|
|
41
48
|
}
|
|
@@ -47,6 +54,8 @@ export async function updateScenario(params: {
|
|
|
47
54
|
situation?: string;
|
|
48
55
|
criteria?: string[];
|
|
49
56
|
labels?: string[];
|
|
57
|
+
testSuiteId?: string | null;
|
|
58
|
+
fields?: ScenarioFieldValues;
|
|
50
59
|
}): Promise<ScenarioSummary> {
|
|
51
60
|
const { id, ...data } = params;
|
|
52
61
|
return makeRequest(
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { makeRequest } from "./langwatch-api.js";
|
|
2
|
+
import type { SimulationRunEvaluation } from "./tools/format-suite-details.js";
|
|
2
3
|
|
|
3
4
|
export interface SimulationRunSummary {
|
|
4
5
|
scenarioRunId: string;
|
|
@@ -14,8 +15,12 @@ export interface SimulationRunSummary {
|
|
|
14
15
|
metCriteria?: string[];
|
|
15
16
|
unmetCriteria?: string[];
|
|
16
17
|
error?: string | null;
|
|
18
|
+
/** One result per evaluator that ran after the conversation. */
|
|
19
|
+
evaluations?: SimulationRunEvaluation[];
|
|
17
20
|
} | null;
|
|
18
21
|
messages?: Array<{ role: string; content: string }>;
|
|
22
|
+
/** Why the run was started, as given when it was queued. Null without one. */
|
|
23
|
+
note?: string | null;
|
|
19
24
|
timestamp: number;
|
|
20
25
|
updatedAt: number;
|
|
21
26
|
}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
import { makeRequest } from "./langwatch-api.js";
|
|
2
|
+
import type {
|
|
3
|
+
RunParameters,
|
|
4
|
+
RunPlanRunResult,
|
|
5
|
+
} from "./langwatch-api-run-plans.js";
|
|
6
|
+
import type { RunPlanTargetWire } from "./schemas/run-plan.js";
|
|
7
|
+
import type {
|
|
8
|
+
EvaluatorAttachmentWire,
|
|
9
|
+
SuiteField,
|
|
10
|
+
} from "./schemas/suite-fields.js";
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Client for `/api/v1/test-suites`.
|
|
14
|
+
*
|
|
15
|
+
* A test suite groups scenarios: a name and the scenarios filed in it.
|
|
16
|
+
* Running one is sugar over a run plan, so the run returns the same result a
|
|
17
|
+
* run plan does.
|
|
18
|
+
*/
|
|
19
|
+
|
|
20
|
+
export interface TestSuite {
|
|
21
|
+
id: string;
|
|
22
|
+
name: string;
|
|
23
|
+
slug: string;
|
|
24
|
+
scenarioIds: string[];
|
|
25
|
+
scenarioCount: number;
|
|
26
|
+
archivedAt: string | null;
|
|
27
|
+
createdAt: string;
|
|
28
|
+
updatedAt: string;
|
|
29
|
+
platformUrl: string;
|
|
30
|
+
/** The fields the suite declares. Absent on servers that predate them. */
|
|
31
|
+
fields?: SuiteField[];
|
|
32
|
+
/** The evaluators attached to the suite. Absent on servers that predate them. */
|
|
33
|
+
evaluators?: EvaluatorAttachmentWire[];
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface TestSuiteDetail extends TestSuite {
|
|
37
|
+
scenarios: Array<{ id: string; name: string }>;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface TestSuiteArchiveResponse {
|
|
41
|
+
id: string;
|
|
42
|
+
archived: boolean;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Lists the test suites of the project. */
|
|
46
|
+
export async function listTestSuites(): Promise<TestSuite[]> {
|
|
47
|
+
return makeRequest("GET", "/api/v1/test-suites") as Promise<TestSuite[]>;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Creates a test suite, with the fields and the evaluators it declares. */
|
|
51
|
+
export async function createTestSuite(data: {
|
|
52
|
+
name: string;
|
|
53
|
+
fields?: SuiteField[];
|
|
54
|
+
evaluators?: EvaluatorAttachmentWire[];
|
|
55
|
+
}): Promise<TestSuite> {
|
|
56
|
+
return makeRequest(
|
|
57
|
+
"POST",
|
|
58
|
+
"/api/v1/test-suites",
|
|
59
|
+
data,
|
|
60
|
+
) as Promise<TestSuite>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Retrieves a test suite with the scenarios filed in it. */
|
|
64
|
+
export async function getTestSuite(id: string): Promise<TestSuiteDetail> {
|
|
65
|
+
return makeRequest(
|
|
66
|
+
"GET",
|
|
67
|
+
`/api/v1/test-suites/${encodeURIComponent(id)}`,
|
|
68
|
+
) as Promise<TestSuiteDetail>;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Edits a test suite: any of its name, its fields and its evaluators. A list
|
|
73
|
+
* given here replaces the one the suite holds.
|
|
74
|
+
*/
|
|
75
|
+
export async function updateTestSuite(params: {
|
|
76
|
+
id: string;
|
|
77
|
+
name?: string;
|
|
78
|
+
fields?: SuiteField[];
|
|
79
|
+
evaluators?: EvaluatorAttachmentWire[];
|
|
80
|
+
}): Promise<TestSuite> {
|
|
81
|
+
const { id, ...data } = params;
|
|
82
|
+
return makeRequest(
|
|
83
|
+
"PATCH",
|
|
84
|
+
`/api/v1/test-suites/${encodeURIComponent(id)}`,
|
|
85
|
+
data,
|
|
86
|
+
) as Promise<TestSuite>;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Renames a test suite. */
|
|
90
|
+
export async function renameTestSuite(params: {
|
|
91
|
+
id: string;
|
|
92
|
+
name: string;
|
|
93
|
+
}): Promise<TestSuite> {
|
|
94
|
+
return makeRequest(
|
|
95
|
+
"PATCH",
|
|
96
|
+
`/api/v1/test-suites/${encodeURIComponent(params.id)}`,
|
|
97
|
+
{ name: params.name },
|
|
98
|
+
) as Promise<TestSuite>;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** Archives a test suite and the scenarios filed in it. */
|
|
102
|
+
export async function archiveTestSuite(
|
|
103
|
+
id: string,
|
|
104
|
+
): Promise<TestSuiteArchiveResponse> {
|
|
105
|
+
return makeRequest(
|
|
106
|
+
"DELETE",
|
|
107
|
+
`/api/v1/test-suites/${encodeURIComponent(id)}`,
|
|
108
|
+
) as Promise<TestSuiteArchiveResponse>;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Runs every scenario of a test suite against the given targets. The server
|
|
113
|
+
* creates or joins the run plan named "<suite name> <target name>" when no
|
|
114
|
+
* name is sent.
|
|
115
|
+
*/
|
|
116
|
+
export async function runTestSuite({
|
|
117
|
+
id,
|
|
118
|
+
...data
|
|
119
|
+
}: {
|
|
120
|
+
id: string;
|
|
121
|
+
targets: RunPlanTargetWire[];
|
|
122
|
+
name?: string;
|
|
123
|
+
repeatCount?: number;
|
|
124
|
+
simulatorModel?: string | null;
|
|
125
|
+
judgeModel?: string | null;
|
|
126
|
+
parameters?: RunParameters;
|
|
127
|
+
note?: string;
|
|
128
|
+
idempotencyKey?: string;
|
|
129
|
+
}): Promise<RunPlanRunResult> {
|
|
130
|
+
return makeRequest(
|
|
131
|
+
"POST",
|
|
132
|
+
`/api/v1/test-suites/${encodeURIComponent(id)}/run`,
|
|
133
|
+
data,
|
|
134
|
+
) as Promise<RunPlanRunResult>;
|
|
135
|
+
}
|