@langwatch/mcp-server 0.5.0 → 0.6.1
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 +32 -0
- package/dist/{archive-scenario-GAE4XVFM.js → archive-scenario-YFD5THOR.js} +3 -3
- package/dist/archive-scenario-YFD5THOR.js.map +1 -0
- package/dist/chunk-5UOPNRXW.js +37 -0
- package/dist/chunk-5UOPNRXW.js.map +1 -0
- package/dist/{chunk-K2YFPOSD.js → chunk-6U4TCGFC.js} +2 -2
- package/dist/chunk-IX6QJKAD.js +22 -0
- package/dist/chunk-IX6QJKAD.js.map +1 -0
- package/dist/{chunk-JVWDWL3J.js → chunk-LLRQIF52.js} +3 -11
- package/dist/chunk-LLRQIF52.js.map +1 -0
- package/dist/create-evaluator-E5X5ZP3B.js +27 -0
- package/dist/create-evaluator-E5X5ZP3B.js.map +1 -0
- package/dist/create-prompt-7Z35MIL6.js +36 -0
- package/dist/create-prompt-7Z35MIL6.js.map +1 -0
- package/dist/{create-scenario-3YRZVDYF.js → create-scenario-DIMPJRPY.js} +3 -3
- package/dist/create-scenario-DIMPJRPY.js.map +1 -0
- package/dist/discover-evaluator-schema-H23XCLNE.js +1402 -0
- package/dist/discover-evaluator-schema-H23XCLNE.js.map +1 -0
- package/dist/{get-analytics-BAVXTAPB.js → get-analytics-4YJW4S5L.js} +2 -2
- package/dist/get-evaluator-WDEH2F7M.js +47 -0
- package/dist/get-evaluator-WDEH2F7M.js.map +1 -0
- package/dist/{get-prompt-LKCPT26O.js → get-prompt-F6PDVC76.js} +2 -5
- package/dist/get-prompt-F6PDVC76.js.map +1 -0
- package/dist/{get-scenario-3SCDW4Z6.js → get-scenario-H24ZYNT5.js} +3 -3
- package/dist/{get-trace-QFDWJ5D4.js → get-trace-27USKGO7.js} +2 -2
- package/dist/index.js +13311 -2411
- package/dist/index.js.map +1 -1
- package/dist/list-evaluators-KRGI72EH.js +34 -0
- package/dist/list-evaluators-KRGI72EH.js.map +1 -0
- package/dist/list-model-providers-A5YCFTPI.js +35 -0
- package/dist/list-model-providers-A5YCFTPI.js.map +1 -0
- package/dist/{list-prompts-UQPBCUYA.js → list-prompts-LKJSE7XN.js} +6 -7
- package/dist/list-prompts-LKJSE7XN.js.map +1 -0
- package/dist/{list-scenarios-573YOUKC.js → list-scenarios-ZK5CMGC4.js} +5 -5
- package/dist/list-scenarios-ZK5CMGC4.js.map +1 -0
- package/dist/{search-traces-RSMYCAN7.js → search-traces-SOKAAMAR.js} +2 -2
- package/dist/set-model-provider-7MGULZDH.js +33 -0
- package/dist/set-model-provider-7MGULZDH.js.map +1 -0
- package/dist/update-evaluator-A3XINFLJ.js +24 -0
- package/dist/update-evaluator-A3XINFLJ.js.map +1 -0
- package/dist/update-prompt-IW7X2UQM.js +22 -0
- package/dist/update-prompt-IW7X2UQM.js.map +1 -0
- package/dist/{update-scenario-SSGVOBJO.js → update-scenario-ZT7TOBFR.js} +3 -3
- package/dist/update-scenario-ZT7TOBFR.js.map +1 -0
- package/package.json +10 -10
- package/src/__tests__/all-tools.integration.test.ts +1337 -0
- package/src/__tests__/discover-evaluator-schema.unit.test.ts +89 -0
- package/src/__tests__/evaluator-tools.unit.test.ts +262 -0
- package/src/__tests__/integration.integration.test.ts +9 -34
- package/src/__tests__/langwatch-api.unit.test.ts +4 -32
- package/src/__tests__/model-provider-tools.unit.test.ts +190 -0
- package/src/__tests__/scenario-tools.integration.test.ts +5 -5
- package/src/__tests__/scenario-tools.unit.test.ts +2 -2
- package/src/__tests__/tools.unit.test.ts +59 -65
- package/src/index.ts +250 -89
- package/src/langwatch-api-evaluators.ts +70 -0
- package/src/langwatch-api-model-providers.ts +41 -0
- package/src/langwatch-api.ts +3 -28
- package/src/tools/archive-scenario.ts +1 -1
- package/src/tools/create-evaluator.ts +33 -0
- package/src/tools/create-prompt.ts +30 -5
- package/src/tools/create-scenario.ts +1 -1
- package/src/tools/discover-evaluator-schema.ts +143 -0
- package/src/tools/get-evaluator.ts +53 -0
- package/src/tools/get-prompt.ts +1 -4
- package/src/tools/list-evaluators.ts +37 -0
- package/src/tools/list-model-providers.ts +40 -0
- package/src/tools/list-prompts.ts +5 -6
- package/src/tools/list-scenarios.ts +3 -3
- package/src/tools/set-model-provider.ts +46 -0
- package/src/tools/update-evaluator.ts +30 -0
- package/src/tools/update-prompt.ts +9 -25
- package/src/tools/update-scenario.ts +1 -1
- package/dist/archive-scenario-GAE4XVFM.js.map +0 -1
- package/dist/chunk-JVWDWL3J.js.map +0 -1
- package/dist/create-prompt-P35POKBW.js +0 -22
- package/dist/create-prompt-P35POKBW.js.map +0 -1
- package/dist/create-scenario-3YRZVDYF.js.map +0 -1
- package/dist/get-prompt-LKCPT26O.js.map +0 -1
- package/dist/list-prompts-UQPBCUYA.js.map +0 -1
- package/dist/list-scenarios-573YOUKC.js.map +0 -1
- package/dist/update-prompt-G2Y5EBQY.js +0 -31
- package/dist/update-prompt-G2Y5EBQY.js.map +0 -1
- package/dist/update-scenario-SSGVOBJO.js.map +0 -1
- /package/dist/{chunk-K2YFPOSD.js.map → chunk-6U4TCGFC.js.map} +0 -0
- /package/dist/{get-analytics-BAVXTAPB.js.map → get-analytics-4YJW4S5L.js.map} +0 -0
- /package/dist/{get-scenario-3SCDW4Z6.js.map → get-scenario-H24ZYNT5.js.map} +0 -0
- /package/dist/{get-trace-QFDWJ5D4.js.map → get-trace-27USKGO7.js.map} +0 -0
- /package/dist/{search-traces-RSMYCAN7.js.map → search-traces-SOKAAMAR.js.map} +0 -0
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { formatEvaluatorSchema } from "../tools/discover-evaluator-schema.js";
|
|
3
|
+
|
|
4
|
+
describe("formatEvaluatorSchema()", () => {
|
|
5
|
+
describe("when called without evaluatorType (overview)", () => {
|
|
6
|
+
it("includes the overview header", () => {
|
|
7
|
+
const result = formatEvaluatorSchema();
|
|
8
|
+
expect(result).toContain("# Available Evaluator Types");
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it("includes category sections", () => {
|
|
12
|
+
const result = formatEvaluatorSchema();
|
|
13
|
+
expect(result).toContain("## safety");
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
it("includes evaluator type identifiers", () => {
|
|
17
|
+
const result = formatEvaluatorSchema();
|
|
18
|
+
expect(result).toContain("openai/moderation");
|
|
19
|
+
expect(result).toContain("langevals/exact_match");
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
it("includes evaluator display names", () => {
|
|
23
|
+
const result = formatEvaluatorSchema();
|
|
24
|
+
expect(result).toContain("OpenAI Moderation");
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("instructs the agent to use evaluatorType parameter for full details", () => {
|
|
28
|
+
const result = formatEvaluatorSchema();
|
|
29
|
+
expect(result).toContain(
|
|
30
|
+
"discover_schema({ category: 'evaluators', evaluatorType: '<type>' })",
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe("when called with a valid evaluatorType (detail)", () => {
|
|
36
|
+
it("includes the evaluator name in the heading", () => {
|
|
37
|
+
const result = formatEvaluatorSchema("openai/moderation");
|
|
38
|
+
expect(result).toContain("# OpenAI Moderation");
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
it("includes the evaluator type in backticks", () => {
|
|
42
|
+
const result = formatEvaluatorSchema("openai/moderation");
|
|
43
|
+
expect(result).toContain("`openai/moderation`");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("includes the category", () => {
|
|
47
|
+
const result = formatEvaluatorSchema("openai/moderation");
|
|
48
|
+
expect(result).toContain("**Category**: safety");
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it("includes settings with descriptions and defaults", () => {
|
|
52
|
+
const result = formatEvaluatorSchema("openai/moderation");
|
|
53
|
+
expect(result).toContain("## Settings");
|
|
54
|
+
expect(result).toContain("**model**");
|
|
55
|
+
expect(result).toContain("Default:");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it("includes required/optional fields section", () => {
|
|
59
|
+
const result = formatEvaluatorSchema("openai/moderation");
|
|
60
|
+
expect(result).toContain("## Fields");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
it("includes result fields", () => {
|
|
64
|
+
const result = formatEvaluatorSchema("openai/moderation");
|
|
65
|
+
expect(result).toContain("## Result Fields");
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it("includes a usage example with evaluatorType", () => {
|
|
69
|
+
const result = formatEvaluatorSchema("openai/moderation");
|
|
70
|
+
expect(result).toContain("## Usage Example");
|
|
71
|
+
expect(result).toContain('"evaluatorType"');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it("includes env vars when the evaluator requires them", () => {
|
|
75
|
+
const result = formatEvaluatorSchema("azure/content_safety");
|
|
76
|
+
expect(result).toContain("## Required Environment Variables");
|
|
77
|
+
expect(result).toContain("AZURE_CONTENT_SAFETY_ENDPOINT");
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
describe("when called with an unknown evaluatorType", () => {
|
|
82
|
+
it("returns an error message with guidance", () => {
|
|
83
|
+
const result = formatEvaluatorSchema("nonexistent/type");
|
|
84
|
+
expect(result).toContain("Unknown evaluator type");
|
|
85
|
+
expect(result).toContain("nonexistent/type");
|
|
86
|
+
expect(result).toContain("discover_schema");
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
});
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
|
|
3
|
+
vi.mock("../langwatch-api-evaluators.js", async (importOriginal) => {
|
|
4
|
+
const actual = await importOriginal() as Record<string, unknown>;
|
|
5
|
+
return {
|
|
6
|
+
...actual,
|
|
7
|
+
listEvaluators: vi.fn(),
|
|
8
|
+
getEvaluator: vi.fn(),
|
|
9
|
+
createEvaluator: vi.fn(),
|
|
10
|
+
updateEvaluator: vi.fn(),
|
|
11
|
+
};
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
listEvaluators,
|
|
16
|
+
getEvaluator,
|
|
17
|
+
createEvaluator,
|
|
18
|
+
updateEvaluator,
|
|
19
|
+
} from "../langwatch-api-evaluators.js";
|
|
20
|
+
|
|
21
|
+
import { handleListEvaluators } from "../tools/list-evaluators.js";
|
|
22
|
+
import { handleGetEvaluator } from "../tools/get-evaluator.js";
|
|
23
|
+
import { handleCreateEvaluator } from "../tools/create-evaluator.js";
|
|
24
|
+
import { handleUpdateEvaluator } from "../tools/update-evaluator.js";
|
|
25
|
+
|
|
26
|
+
const mockListEvaluators = vi.mocked(listEvaluators);
|
|
27
|
+
const mockGetEvaluator = vi.mocked(getEvaluator);
|
|
28
|
+
const mockCreateEvaluator = vi.mocked(createEvaluator);
|
|
29
|
+
const mockUpdateEvaluator = vi.mocked(updateEvaluator);
|
|
30
|
+
|
|
31
|
+
beforeEach(() => {
|
|
32
|
+
vi.clearAllMocks();
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe("handleListEvaluators()", () => {
|
|
36
|
+
const sampleEvaluators = [
|
|
37
|
+
{
|
|
38
|
+
id: "evaluator_abc123",
|
|
39
|
+
projectId: "proj_1",
|
|
40
|
+
name: "Toxicity Check",
|
|
41
|
+
slug: "toxicity-check",
|
|
42
|
+
type: "evaluator",
|
|
43
|
+
config: { evaluatorType: "openai/moderation" },
|
|
44
|
+
workflowId: null,
|
|
45
|
+
copiedFromEvaluatorId: null,
|
|
46
|
+
createdAt: "2024-01-01T00:00:00.000Z",
|
|
47
|
+
updatedAt: "2024-01-01T00:00:00.000Z",
|
|
48
|
+
fields: [{ identifier: "input", type: "str" }],
|
|
49
|
+
outputFields: [{ identifier: "passed", type: "bool" }],
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: "evaluator_def456",
|
|
53
|
+
projectId: "proj_1",
|
|
54
|
+
name: "Exact Match",
|
|
55
|
+
slug: "exact-match",
|
|
56
|
+
type: "evaluator",
|
|
57
|
+
config: { evaluatorType: "langevals/exact_match" },
|
|
58
|
+
workflowId: null,
|
|
59
|
+
copiedFromEvaluatorId: null,
|
|
60
|
+
createdAt: "2024-01-02T00:00:00.000Z",
|
|
61
|
+
updatedAt: "2024-01-02T00:00:00.000Z",
|
|
62
|
+
fields: [
|
|
63
|
+
{ identifier: "output", type: "str" },
|
|
64
|
+
{ identifier: "expected_output", type: "str" },
|
|
65
|
+
],
|
|
66
|
+
outputFields: [{ identifier: "passed", type: "bool" }],
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
|
|
70
|
+
describe("when evaluators exist", () => {
|
|
71
|
+
let result: string;
|
|
72
|
+
|
|
73
|
+
beforeEach(async () => {
|
|
74
|
+
mockListEvaluators.mockResolvedValue(sampleEvaluators);
|
|
75
|
+
result = await handleListEvaluators();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
it("includes evaluator id", () => {
|
|
79
|
+
expect(result).toContain("evaluator_abc123");
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it("includes evaluator name", () => {
|
|
83
|
+
expect(result).toContain("Toxicity Check");
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it("includes evaluator type", () => {
|
|
87
|
+
expect(result).toContain("openai/moderation");
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it("includes slug", () => {
|
|
91
|
+
expect(result).toContain("toxicity-check");
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it("includes all evaluators in the list", () => {
|
|
95
|
+
expect(result).toContain("evaluator_def456");
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
it("includes the total count header", () => {
|
|
99
|
+
expect(result).toContain("# Evaluators (2 total)");
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe("when no evaluators exist", () => {
|
|
104
|
+
let result: string;
|
|
105
|
+
|
|
106
|
+
beforeEach(async () => {
|
|
107
|
+
mockListEvaluators.mockResolvedValue([]);
|
|
108
|
+
result = await handleListEvaluators();
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
it("returns a no-evaluators message", () => {
|
|
112
|
+
expect(result).toContain("No evaluators found");
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it("includes a tip to use platform_create_evaluator", () => {
|
|
116
|
+
expect(result).toContain("platform_create_evaluator");
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
describe("handleGetEvaluator()", () => {
|
|
122
|
+
const sampleEvaluator = {
|
|
123
|
+
id: "evaluator_abc123",
|
|
124
|
+
projectId: "proj_1",
|
|
125
|
+
name: "Toxicity Check",
|
|
126
|
+
slug: "toxicity-check",
|
|
127
|
+
type: "evaluator",
|
|
128
|
+
config: {
|
|
129
|
+
evaluatorType: "openai/moderation",
|
|
130
|
+
settings: { model: "text-moderation-stable" },
|
|
131
|
+
},
|
|
132
|
+
workflowId: null,
|
|
133
|
+
copiedFromEvaluatorId: null,
|
|
134
|
+
createdAt: "2024-01-01T00:00:00.000Z",
|
|
135
|
+
updatedAt: "2024-01-01T00:00:00.000Z",
|
|
136
|
+
fields: [
|
|
137
|
+
{ identifier: "input", type: "str" },
|
|
138
|
+
{ identifier: "output", type: "str", optional: true },
|
|
139
|
+
],
|
|
140
|
+
outputFields: [
|
|
141
|
+
{ identifier: "passed", type: "bool" },
|
|
142
|
+
{ identifier: "score", type: "float" },
|
|
143
|
+
],
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
describe("when evaluator is found", () => {
|
|
147
|
+
let result: string;
|
|
148
|
+
|
|
149
|
+
beforeEach(async () => {
|
|
150
|
+
mockGetEvaluator.mockResolvedValue(sampleEvaluator);
|
|
151
|
+
result = await handleGetEvaluator({ idOrSlug: "evaluator_abc123" });
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it("includes the evaluator name in the heading", () => {
|
|
155
|
+
expect(result).toContain("# Evaluator: Toxicity Check");
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it("includes the evaluator type", () => {
|
|
159
|
+
expect(result).toContain("openai/moderation");
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
it("includes the config as JSON", () => {
|
|
163
|
+
expect(result).toContain("text-moderation-stable");
|
|
164
|
+
});
|
|
165
|
+
|
|
166
|
+
it("includes input fields", () => {
|
|
167
|
+
expect(result).toContain("## Input Fields");
|
|
168
|
+
expect(result).toContain("**input** (str)");
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it("marks optional fields", () => {
|
|
172
|
+
expect(result).toContain("(optional)");
|
|
173
|
+
});
|
|
174
|
+
|
|
175
|
+
it("includes output fields", () => {
|
|
176
|
+
expect(result).toContain("## Output Fields");
|
|
177
|
+
expect(result).toContain("**passed** (bool)");
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
describe("handleCreateEvaluator()", () => {
|
|
183
|
+
describe("when creation succeeds", () => {
|
|
184
|
+
let result: string;
|
|
185
|
+
|
|
186
|
+
beforeEach(async () => {
|
|
187
|
+
mockCreateEvaluator.mockResolvedValue({
|
|
188
|
+
id: "evaluator_new123",
|
|
189
|
+
projectId: "proj_1",
|
|
190
|
+
name: "My LLM Judge",
|
|
191
|
+
slug: "my-llm-judge",
|
|
192
|
+
type: "evaluator",
|
|
193
|
+
config: { evaluatorType: "langevals/llm_boolean" },
|
|
194
|
+
workflowId: null,
|
|
195
|
+
copiedFromEvaluatorId: null,
|
|
196
|
+
createdAt: "2024-01-01T00:00:00.000Z",
|
|
197
|
+
updatedAt: "2024-01-01T00:00:00.000Z",
|
|
198
|
+
fields: [{ identifier: "input", type: "str" }],
|
|
199
|
+
outputFields: [{ identifier: "passed", type: "bool" }],
|
|
200
|
+
});
|
|
201
|
+
result = await handleCreateEvaluator({
|
|
202
|
+
name: "My LLM Judge",
|
|
203
|
+
config: { evaluatorType: "langevals/llm_boolean" },
|
|
204
|
+
});
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it("confirms creation", () => {
|
|
208
|
+
expect(result).toContain("Evaluator created successfully!");
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it("includes the generated ID", () => {
|
|
212
|
+
expect(result).toContain("evaluator_new123");
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
it("includes the slug", () => {
|
|
216
|
+
expect(result).toContain("my-llm-judge");
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
it("includes the evaluator type", () => {
|
|
220
|
+
expect(result).toContain("langevals/llm_boolean");
|
|
221
|
+
});
|
|
222
|
+
});
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
describe("handleUpdateEvaluator()", () => {
|
|
226
|
+
describe("when update succeeds", () => {
|
|
227
|
+
let result: string;
|
|
228
|
+
|
|
229
|
+
beforeEach(async () => {
|
|
230
|
+
mockUpdateEvaluator.mockResolvedValue({
|
|
231
|
+
id: "evaluator_abc123",
|
|
232
|
+
projectId: "proj_1",
|
|
233
|
+
name: "Updated Name",
|
|
234
|
+
slug: "toxicity-check",
|
|
235
|
+
type: "evaluator",
|
|
236
|
+
config: { evaluatorType: "openai/moderation" },
|
|
237
|
+
workflowId: null,
|
|
238
|
+
copiedFromEvaluatorId: null,
|
|
239
|
+
createdAt: "2024-01-01T00:00:00.000Z",
|
|
240
|
+
updatedAt: "2024-01-02T00:00:00.000Z",
|
|
241
|
+
fields: [],
|
|
242
|
+
outputFields: [],
|
|
243
|
+
});
|
|
244
|
+
result = await handleUpdateEvaluator({
|
|
245
|
+
evaluatorId: "evaluator_abc123",
|
|
246
|
+
name: "Updated Name",
|
|
247
|
+
});
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
it("confirms update", () => {
|
|
251
|
+
expect(result).toContain("Evaluator updated successfully!");
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it("includes the evaluator ID", () => {
|
|
255
|
+
expect(result).toContain("evaluator_abc123");
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it("includes the updated name", () => {
|
|
259
|
+
expect(result).toContain("Updated Name");
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
});
|
|
@@ -49,14 +49,12 @@ const CANNED_PROMPTS_LIST = [
|
|
|
49
49
|
id: "p1",
|
|
50
50
|
handle: "greeting-bot",
|
|
51
51
|
name: "Greeting Bot",
|
|
52
|
-
description: "A friendly greeting bot",
|
|
53
52
|
latestVersionNumber: 3,
|
|
54
53
|
},
|
|
55
54
|
{
|
|
56
55
|
id: "p2",
|
|
57
56
|
handle: "qa-assistant",
|
|
58
57
|
name: "QA Assistant",
|
|
59
|
-
description: null,
|
|
60
58
|
latestVersionNumber: 1,
|
|
61
59
|
},
|
|
62
60
|
];
|
|
@@ -65,14 +63,12 @@ const CANNED_PROMPT_DETAIL = {
|
|
|
65
63
|
id: "p1",
|
|
66
64
|
handle: "greeting-bot",
|
|
67
65
|
name: "Greeting Bot",
|
|
68
|
-
description: "A friendly greeting bot",
|
|
69
66
|
latestVersionNumber: 3,
|
|
70
67
|
versions: [
|
|
71
68
|
{
|
|
72
69
|
version: 3,
|
|
73
70
|
commitMessage: "Updated tone",
|
|
74
|
-
model: "gpt-4o",
|
|
75
|
-
modelProvider: "openai",
|
|
71
|
+
model: "openai/gpt-4o",
|
|
76
72
|
messages: [{ role: "system", content: "You are a friendly bot." }],
|
|
77
73
|
},
|
|
78
74
|
{ version: 2, commitMessage: "Added greeting" },
|
|
@@ -128,12 +124,6 @@ function createMockServer(): Server {
|
|
|
128
124
|
} else if (url === "/api/prompts" && req.method === "GET") {
|
|
129
125
|
res.writeHead(200);
|
|
130
126
|
res.end(JSON.stringify(CANNED_PROMPTS_LIST));
|
|
131
|
-
} else if (
|
|
132
|
-
url.match(/^\/api\/prompts\/[^/]+\/versions/) &&
|
|
133
|
-
req.method === "POST"
|
|
134
|
-
) {
|
|
135
|
-
res.writeHead(200);
|
|
136
|
-
res.end(JSON.stringify(CANNED_PROMPT_UPDATED));
|
|
137
127
|
} else if (url.match(/^\/api\/prompts\/[^/]+$/) && req.method === "GET") {
|
|
138
128
|
res.writeHead(200);
|
|
139
129
|
res.end(JSON.stringify(CANNED_PROMPT_DETAIL));
|
|
@@ -142,7 +132,7 @@ function createMockServer(): Server {
|
|
|
142
132
|
res.end(JSON.stringify(CANNED_PROMPT_CREATED));
|
|
143
133
|
} else if (
|
|
144
134
|
url.match(/^\/api\/prompts\/[^/]+$/) &&
|
|
145
|
-
req.method === "
|
|
135
|
+
req.method === "PUT"
|
|
146
136
|
) {
|
|
147
137
|
res.writeHead(200);
|
|
148
138
|
res.end(JSON.stringify(CANNED_PROMPT_UPDATED));
|
|
@@ -222,7 +212,7 @@ describe("MCP tools integration", () => {
|
|
|
222
212
|
});
|
|
223
213
|
});
|
|
224
214
|
|
|
225
|
-
describe("
|
|
215
|
+
describe("platform_list_prompts", () => {
|
|
226
216
|
it("returns formatted prompt list from mock server", async () => {
|
|
227
217
|
const { handleListPrompts } = await import("../tools/list-prompts.js");
|
|
228
218
|
const result = await handleListPrompts();
|
|
@@ -232,7 +222,7 @@ describe("MCP tools integration", () => {
|
|
|
232
222
|
});
|
|
233
223
|
});
|
|
234
224
|
|
|
235
|
-
describe("
|
|
225
|
+
describe("platform_get_prompt", () => {
|
|
236
226
|
it("returns formatted prompt details from mock server", async () => {
|
|
237
227
|
const { handleGetPrompt } = await import("../tools/get-prompt.js");
|
|
238
228
|
const result = await handleGetPrompt({ idOrHandle: "greeting-bot" });
|
|
@@ -243,7 +233,7 @@ describe("MCP tools integration", () => {
|
|
|
243
233
|
});
|
|
244
234
|
});
|
|
245
235
|
|
|
246
|
-
describe("
|
|
236
|
+
describe("platform_create_prompt", () => {
|
|
247
237
|
it("returns success message from mock server", async () => {
|
|
248
238
|
const { handleCreatePrompt } = await import(
|
|
249
239
|
"../tools/create-prompt.js"
|
|
@@ -251,41 +241,26 @@ describe("MCP tools integration", () => {
|
|
|
251
241
|
const result = await handleCreatePrompt({
|
|
252
242
|
name: "New Prompt",
|
|
253
243
|
messages: [{ role: "system", content: "You are helpful." }],
|
|
254
|
-
model: "gpt-4o",
|
|
255
|
-
modelProvider: "openai",
|
|
244
|
+
model: "openai/gpt-4o",
|
|
256
245
|
});
|
|
257
246
|
expect(result).toContain("created successfully");
|
|
258
247
|
expect(result).toContain("p-new");
|
|
259
248
|
});
|
|
260
249
|
});
|
|
261
250
|
|
|
262
|
-
describe("
|
|
263
|
-
it("returns success message
|
|
251
|
+
describe("platform_update_prompt", () => {
|
|
252
|
+
it("returns success message from mock server", async () => {
|
|
264
253
|
const { handleUpdatePrompt } = await import(
|
|
265
254
|
"../tools/update-prompt.js"
|
|
266
255
|
);
|
|
267
256
|
const result = await handleUpdatePrompt({
|
|
268
257
|
idOrHandle: "greeting-bot",
|
|
269
|
-
model: "gpt-4o-mini",
|
|
258
|
+
model: "openai/gpt-4o-mini",
|
|
270
259
|
commitMessage: "Switch to mini",
|
|
271
260
|
});
|
|
272
261
|
expect(result).toContain("updated successfully");
|
|
273
262
|
expect(result).toContain("Switch to mini");
|
|
274
263
|
});
|
|
275
|
-
|
|
276
|
-
it("returns success message for version creation from mock server", async () => {
|
|
277
|
-
const { handleUpdatePrompt } = await import(
|
|
278
|
-
"../tools/update-prompt.js"
|
|
279
|
-
);
|
|
280
|
-
const result = await handleUpdatePrompt({
|
|
281
|
-
idOrHandle: "greeting-bot",
|
|
282
|
-
messages: [{ role: "system", content: "Be concise." }],
|
|
283
|
-
createVersion: true,
|
|
284
|
-
commitMessage: "Make concise",
|
|
285
|
-
});
|
|
286
|
-
expect(result).toContain("version created");
|
|
287
|
-
expect(result).toContain("Make concise");
|
|
288
|
-
});
|
|
289
264
|
});
|
|
290
265
|
|
|
291
266
|
describe("when API key is invalid", () => {
|
|
@@ -208,10 +208,9 @@ describe("langwatch-api", () => {
|
|
|
208
208
|
it("sends POST to /api/prompts with body", async () => {
|
|
209
209
|
const { createPrompt } = await import("../langwatch-api.js");
|
|
210
210
|
const data = {
|
|
211
|
-
|
|
211
|
+
handle: "test-prompt",
|
|
212
212
|
messages: [{ role: "system", content: "You are helpful." }],
|
|
213
|
-
model: "gpt-4o",
|
|
214
|
-
modelProvider: "openai",
|
|
213
|
+
model: "openai/gpt-4o",
|
|
215
214
|
};
|
|
216
215
|
const responseData = { id: "new-id", ...data };
|
|
217
216
|
mockJsonResponse(responseData);
|
|
@@ -234,7 +233,7 @@ describe("langwatch-api", () => {
|
|
|
234
233
|
});
|
|
235
234
|
|
|
236
235
|
describe("updatePrompt()", () => {
|
|
237
|
-
it("sends
|
|
236
|
+
it("sends PUT to /api/prompts/{id} with body", async () => {
|
|
238
237
|
const { updatePrompt } = await import("../langwatch-api.js");
|
|
239
238
|
const data = {
|
|
240
239
|
messages: [{ role: "system", content: "Updated" }],
|
|
@@ -248,34 +247,7 @@ describe("langwatch-api", () => {
|
|
|
248
247
|
expect(mockFetch).toHaveBeenCalledWith(
|
|
249
248
|
`${TEST_ENDPOINT}/api/prompts/${encodeURIComponent("p1")}`,
|
|
250
249
|
expect.objectContaining({
|
|
251
|
-
method: "
|
|
252
|
-
headers: expect.objectContaining({
|
|
253
|
-
"X-Auth-Token": TEST_API_KEY,
|
|
254
|
-
"Content-Type": "application/json",
|
|
255
|
-
}),
|
|
256
|
-
body: JSON.stringify(data),
|
|
257
|
-
})
|
|
258
|
-
);
|
|
259
|
-
expect(result).toEqual(responseData);
|
|
260
|
-
});
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
describe("createPromptVersion()", () => {
|
|
264
|
-
it("sends POST to /api/prompts/{id}/versions with body", async () => {
|
|
265
|
-
const { createPromptVersion } = await import("../langwatch-api.js");
|
|
266
|
-
const data = {
|
|
267
|
-
messages: [{ role: "user", content: "new version" }],
|
|
268
|
-
commitMessage: "v2",
|
|
269
|
-
};
|
|
270
|
-
const responseData = { version: 2 };
|
|
271
|
-
mockJsonResponse(responseData);
|
|
272
|
-
|
|
273
|
-
const result = await createPromptVersion("p1", data);
|
|
274
|
-
|
|
275
|
-
expect(mockFetch).toHaveBeenCalledWith(
|
|
276
|
-
`${TEST_ENDPOINT}/api/prompts/${encodeURIComponent("p1")}/versions`,
|
|
277
|
-
expect.objectContaining({
|
|
278
|
-
method: "POST",
|
|
250
|
+
method: "PUT",
|
|
279
251
|
headers: expect.objectContaining({
|
|
280
252
|
"X-Auth-Token": TEST_API_KEY,
|
|
281
253
|
"Content-Type": "application/json",
|