@langwatch/mcp-server 0.3.3 → 0.5.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 +32 -0
- package/README.md +97 -25
- package/dist/archive-scenario-GAE4XVFM.js +19 -0
- package/dist/archive-scenario-GAE4XVFM.js.map +1 -0
- package/dist/chunk-AAQNA53E.js +28 -0
- package/dist/chunk-AAQNA53E.js.map +1 -0
- package/dist/chunk-JVWDWL3J.js +91 -0
- package/dist/chunk-JVWDWL3J.js.map +1 -0
- package/dist/chunk-K2YFPOSD.js +40 -0
- package/dist/chunk-K2YFPOSD.js.map +1 -0
- package/dist/chunk-ZXKLPC2E.js +27 -0
- package/dist/chunk-ZXKLPC2E.js.map +1 -0
- package/dist/config-FIQWQRUB.js +11 -0
- package/dist/config-FIQWQRUB.js.map +1 -0
- package/dist/create-prompt-P35POKBW.js +22 -0
- package/dist/create-prompt-P35POKBW.js.map +1 -0
- package/dist/create-scenario-3YRZVDYF.js +26 -0
- package/dist/create-scenario-3YRZVDYF.js.map +1 -0
- package/dist/discover-scenario-schema-MEEEVND7.js +65 -0
- package/dist/discover-scenario-schema-MEEEVND7.js.map +1 -0
- package/dist/discover-schema-3T52ORPB.js +446 -0
- package/dist/discover-schema-3T52ORPB.js.map +1 -0
- package/dist/get-analytics-BAVXTAPB.js +55 -0
- package/dist/get-analytics-BAVXTAPB.js.map +1 -0
- package/dist/get-prompt-LKCPT26O.js +48 -0
- package/dist/get-prompt-LKCPT26O.js.map +1 -0
- package/dist/get-scenario-3SCDW4Z6.js +33 -0
- package/dist/get-scenario-3SCDW4Z6.js.map +1 -0
- package/dist/get-trace-QFDWJ5D4.js +50 -0
- package/dist/get-trace-QFDWJ5D4.js.map +1 -0
- package/dist/index.js +22114 -8786
- package/dist/index.js.map +1 -1
- package/dist/list-prompts-UQPBCUYA.js +33 -0
- package/dist/list-prompts-UQPBCUYA.js.map +1 -0
- package/dist/list-scenarios-573YOUKC.js +40 -0
- package/dist/list-scenarios-573YOUKC.js.map +1 -0
- package/dist/search-traces-RSMYCAN7.js +72 -0
- package/dist/search-traces-RSMYCAN7.js.map +1 -0
- package/dist/update-prompt-G2Y5EBQY.js +31 -0
- package/dist/update-prompt-G2Y5EBQY.js.map +1 -0
- package/dist/update-scenario-SSGVOBJO.js +27 -0
- package/dist/update-scenario-SSGVOBJO.js.map +1 -0
- package/package.json +3 -3
- package/src/__tests__/config.unit.test.ts +89 -0
- package/src/__tests__/date-parsing.unit.test.ts +78 -0
- package/src/__tests__/discover-schema.unit.test.ts +118 -0
- package/src/__tests__/integration.integration.test.ts +313 -0
- package/src/__tests__/langwatch-api.unit.test.ts +309 -0
- package/src/__tests__/scenario-tools.integration.test.ts +286 -0
- package/src/__tests__/scenario-tools.unit.test.ts +185 -0
- package/src/__tests__/schemas.unit.test.ts +85 -0
- package/src/__tests__/tools.unit.test.ts +729 -0
- package/src/config.ts +31 -0
- package/src/index.ts +383 -0
- package/src/langwatch-api-scenarios.ts +67 -0
- package/src/langwatch-api.ts +266 -0
- package/src/schemas/analytics-groups.ts +78 -0
- package/src/schemas/analytics-metrics.ts +179 -0
- package/src/schemas/filter-fields.ts +119 -0
- package/src/schemas/index.ts +3 -0
- package/src/tools/archive-scenario.ts +19 -0
- package/src/tools/create-prompt.ts +29 -0
- package/src/tools/create-scenario.ts +30 -0
- package/src/tools/discover-scenario-schema.ts +71 -0
- package/src/tools/discover-schema.ts +106 -0
- package/src/tools/get-analytics.ts +71 -0
- package/src/tools/get-prompt.ts +56 -0
- package/src/tools/get-scenario.ts +36 -0
- package/src/tools/get-trace.ts +61 -0
- package/src/tools/list-prompts.ts +35 -0
- package/src/tools/list-scenarios.ts +47 -0
- package/src/tools/search-traces.ts +91 -0
- package/src/tools/update-prompt.ts +44 -0
- package/src/tools/update-scenario.ts +32 -0
- package/src/utils/date-parsing.ts +31 -0
- package/tests/evaluations.ipynb +634 -634
- package/tests/scenario-openai.test.ts +3 -1
- package/uv.lock +1788 -1322
|
@@ -0,0 +1,266 @@
|
|
|
1
|
+
import { getConfig, requireApiKey } from "./config.js";
|
|
2
|
+
|
|
3
|
+
// --- Response types ---
|
|
4
|
+
|
|
5
|
+
export interface TraceSearchResult {
|
|
6
|
+
trace_id: string;
|
|
7
|
+
formatted_trace?: string;
|
|
8
|
+
input?: { value: string };
|
|
9
|
+
output?: { value: string };
|
|
10
|
+
timestamps?: { started_at?: string | number };
|
|
11
|
+
metadata?: Record<string, unknown>;
|
|
12
|
+
error?: Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface SearchTracesResponse {
|
|
16
|
+
traces: TraceSearchResult[];
|
|
17
|
+
pagination?: {
|
|
18
|
+
totalHits?: number;
|
|
19
|
+
scrollId?: string;
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface TraceDetailResponse {
|
|
24
|
+
trace_id: string;
|
|
25
|
+
formatted_trace?: string;
|
|
26
|
+
input?: { value: string };
|
|
27
|
+
output?: { value: string };
|
|
28
|
+
timestamps?: {
|
|
29
|
+
started_at?: string | number;
|
|
30
|
+
updated_at?: string | number;
|
|
31
|
+
inserted_at?: string | number;
|
|
32
|
+
};
|
|
33
|
+
metadata?: {
|
|
34
|
+
user_id?: string;
|
|
35
|
+
thread_id?: string;
|
|
36
|
+
customer_id?: string;
|
|
37
|
+
labels?: string[];
|
|
38
|
+
[key: string]: unknown;
|
|
39
|
+
};
|
|
40
|
+
error?: Record<string, unknown>;
|
|
41
|
+
ascii_tree?: string;
|
|
42
|
+
evaluations?: Array<{
|
|
43
|
+
evaluator_id?: string;
|
|
44
|
+
name?: string;
|
|
45
|
+
score?: number;
|
|
46
|
+
passed?: boolean;
|
|
47
|
+
label?: string;
|
|
48
|
+
}>;
|
|
49
|
+
spans?: Array<{
|
|
50
|
+
span_id: string;
|
|
51
|
+
name?: string;
|
|
52
|
+
type?: string;
|
|
53
|
+
model?: string;
|
|
54
|
+
input?: { value: string };
|
|
55
|
+
output?: { value: string };
|
|
56
|
+
timestamps?: { started_at?: number; finished_at?: number };
|
|
57
|
+
metrics?: {
|
|
58
|
+
completion_time_ms?: number;
|
|
59
|
+
prompt_tokens?: number;
|
|
60
|
+
completion_tokens?: number;
|
|
61
|
+
tokens_estimated?: boolean;
|
|
62
|
+
cost?: number;
|
|
63
|
+
};
|
|
64
|
+
}>;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export interface AnalyticsBucket {
|
|
68
|
+
date: string;
|
|
69
|
+
[key: string]: unknown;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface AnalyticsTimeseriesResponse {
|
|
73
|
+
currentPeriod: AnalyticsBucket[];
|
|
74
|
+
previousPeriod: AnalyticsBucket[];
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface PromptSummary {
|
|
78
|
+
id?: string;
|
|
79
|
+
handle?: string;
|
|
80
|
+
name?: string;
|
|
81
|
+
description?: string | null;
|
|
82
|
+
latestVersionNumber?: number;
|
|
83
|
+
version?: number;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface PromptVersion {
|
|
87
|
+
version?: number;
|
|
88
|
+
commitMessage?: string;
|
|
89
|
+
model?: string;
|
|
90
|
+
modelProvider?: string;
|
|
91
|
+
messages?: Array<{ role: string; content: string }>;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface PromptDetailResponse extends PromptSummary {
|
|
95
|
+
versions?: PromptVersion[];
|
|
96
|
+
model?: string;
|
|
97
|
+
modelProvider?: string;
|
|
98
|
+
messages?: Array<{ role: string; content: string }>;
|
|
99
|
+
prompt?: Array<{ role: string; content: string }>;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export interface PromptMutationResponse {
|
|
103
|
+
id?: string;
|
|
104
|
+
handle?: string;
|
|
105
|
+
name?: string;
|
|
106
|
+
latestVersionNumber?: number;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// --- HTTP client ---
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Sends an HTTP request to the LangWatch API.
|
|
113
|
+
*
|
|
114
|
+
* Builds the full URL from the configured endpoint, adds authentication,
|
|
115
|
+
* and handles JSON serialization/deserialization.
|
|
116
|
+
*
|
|
117
|
+
* @throws Error with status code and response body when the response is not OK
|
|
118
|
+
*/
|
|
119
|
+
export async function makeRequest(
|
|
120
|
+
method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE",
|
|
121
|
+
path: string,
|
|
122
|
+
body?: unknown
|
|
123
|
+
): Promise<unknown> {
|
|
124
|
+
const url = getConfig().endpoint + path;
|
|
125
|
+
const headers: Record<string, string> = {
|
|
126
|
+
"X-Auth-Token": requireApiKey(),
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
if (body !== undefined) {
|
|
130
|
+
headers["Content-Type"] = "application/json";
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
const response = await fetch(url, {
|
|
134
|
+
method,
|
|
135
|
+
headers,
|
|
136
|
+
...(body !== undefined ? { body: JSON.stringify(body) } : {}),
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
if (!response.ok) {
|
|
140
|
+
const responseBody = await response.text();
|
|
141
|
+
throw new Error(
|
|
142
|
+
`LangWatch API error ${response.status}: ${responseBody}`
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return response.json();
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/** Searches traces with optional filters and pagination. */
|
|
150
|
+
export async function searchTraces(params: {
|
|
151
|
+
query?: string;
|
|
152
|
+
filters?: Record<string, string[]>;
|
|
153
|
+
startDate: number;
|
|
154
|
+
endDate: number;
|
|
155
|
+
pageSize?: number;
|
|
156
|
+
pageOffset?: number;
|
|
157
|
+
scrollId?: string;
|
|
158
|
+
format?: "digest" | "json";
|
|
159
|
+
}): Promise<SearchTracesResponse> {
|
|
160
|
+
const { format = "digest", ...rest } = params;
|
|
161
|
+
return makeRequest("POST", "/api/traces/search", {
|
|
162
|
+
...rest,
|
|
163
|
+
format,
|
|
164
|
+
}) as Promise<SearchTracesResponse>;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/** Retrieves a single trace by its ID. */
|
|
168
|
+
export async function getTraceById(
|
|
169
|
+
traceId: string,
|
|
170
|
+
format: "digest" | "json" = "digest"
|
|
171
|
+
): Promise<TraceDetailResponse> {
|
|
172
|
+
return makeRequest(
|
|
173
|
+
"GET",
|
|
174
|
+
`/api/traces/${encodeURIComponent(traceId)}?format=${format}`
|
|
175
|
+
) as Promise<TraceDetailResponse>;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** Fetches analytics timeseries data for the given metrics and date range. */
|
|
179
|
+
export async function getAnalyticsTimeseries(params: {
|
|
180
|
+
series: Array<{
|
|
181
|
+
metric: string;
|
|
182
|
+
aggregation: string;
|
|
183
|
+
key?: string;
|
|
184
|
+
subkey?: string;
|
|
185
|
+
}>;
|
|
186
|
+
startDate: number;
|
|
187
|
+
endDate: number;
|
|
188
|
+
timeZone?: string;
|
|
189
|
+
groupBy?: string;
|
|
190
|
+
groupByKey?: string;
|
|
191
|
+
filters?: Record<string, string[]>;
|
|
192
|
+
}): Promise<AnalyticsTimeseriesResponse> {
|
|
193
|
+
return makeRequest(
|
|
194
|
+
"POST",
|
|
195
|
+
"/api/analytics/timeseries",
|
|
196
|
+
params
|
|
197
|
+
) as Promise<AnalyticsTimeseriesResponse>;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/** Lists all prompts in the project. */
|
|
201
|
+
export async function listPrompts(): Promise<PromptSummary[]> {
|
|
202
|
+
return makeRequest("GET", "/api/prompts") as Promise<PromptSummary[]>;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
/** Retrieves a single prompt by ID or handle. */
|
|
206
|
+
export async function getPrompt(
|
|
207
|
+
idOrHandle: string,
|
|
208
|
+
version?: number
|
|
209
|
+
): Promise<PromptDetailResponse> {
|
|
210
|
+
const query = version != null ? `?version=${version}` : "";
|
|
211
|
+
return makeRequest(
|
|
212
|
+
"GET",
|
|
213
|
+
`/api/prompts/${encodeURIComponent(idOrHandle)}${query}`
|
|
214
|
+
) as Promise<PromptDetailResponse>;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** Creates a new prompt. */
|
|
218
|
+
export async function createPrompt(data: {
|
|
219
|
+
name: string;
|
|
220
|
+
handle?: string;
|
|
221
|
+
messages: Array<{ role: string; content: string }>;
|
|
222
|
+
model: string;
|
|
223
|
+
modelProvider: string;
|
|
224
|
+
description?: string;
|
|
225
|
+
}): Promise<PromptMutationResponse> {
|
|
226
|
+
return makeRequest(
|
|
227
|
+
"POST",
|
|
228
|
+
"/api/prompts",
|
|
229
|
+
data
|
|
230
|
+
) as Promise<PromptMutationResponse>;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/** Updates an existing prompt by ID or handle. */
|
|
234
|
+
export async function updatePrompt(
|
|
235
|
+
idOrHandle: string,
|
|
236
|
+
data: {
|
|
237
|
+
messages?: Array<{ role: string; content: string }>;
|
|
238
|
+
model?: string;
|
|
239
|
+
modelProvider?: string;
|
|
240
|
+
commitMessage?: string;
|
|
241
|
+
}
|
|
242
|
+
): Promise<PromptMutationResponse> {
|
|
243
|
+
return makeRequest(
|
|
244
|
+
"POST",
|
|
245
|
+
`/api/prompts/${encodeURIComponent(idOrHandle)}`,
|
|
246
|
+
data
|
|
247
|
+
) as Promise<PromptMutationResponse>;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/** Creates a new version of an existing prompt. */
|
|
251
|
+
export async function createPromptVersion(
|
|
252
|
+
idOrHandle: string,
|
|
253
|
+
data: {
|
|
254
|
+
messages?: Array<{ role: string; content: string }>;
|
|
255
|
+
model?: string;
|
|
256
|
+
modelProvider?: string;
|
|
257
|
+
commitMessage?: string;
|
|
258
|
+
}
|
|
259
|
+
): Promise<PromptMutationResponse> {
|
|
260
|
+
return makeRequest(
|
|
261
|
+
"POST",
|
|
262
|
+
`/api/prompts/${encodeURIComponent(idOrHandle)}/versions`,
|
|
263
|
+
data
|
|
264
|
+
) as Promise<PromptMutationResponse>;
|
|
265
|
+
}
|
|
266
|
+
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
export interface GroupByInfo {
|
|
2
|
+
name: string;
|
|
3
|
+
label: string;
|
|
4
|
+
description: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const analyticsGroups: GroupByInfo[] = [
|
|
8
|
+
{
|
|
9
|
+
name: "topics.topics",
|
|
10
|
+
label: "Topic",
|
|
11
|
+
description: "Group by topic classification",
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
name: "metadata.user_id",
|
|
15
|
+
label: "User",
|
|
16
|
+
description: "Group by user ID",
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
name: "metadata.thread_id",
|
|
20
|
+
label: "Thread",
|
|
21
|
+
description: "Group by conversation thread",
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
name: "metadata.customer_id",
|
|
25
|
+
label: "Customer ID",
|
|
26
|
+
description: "Group by customer/organization",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
name: "metadata.labels",
|
|
30
|
+
label: "Label",
|
|
31
|
+
description: "Group by custom labels",
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
name: "metadata.model",
|
|
35
|
+
label: "Model",
|
|
36
|
+
description: "Group by LLM model name",
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: "metadata.span_type",
|
|
40
|
+
label: "Span Type",
|
|
41
|
+
description: "Group by span type (llm, tool, agent, etc.)",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: "sentiment.input_sentiment",
|
|
45
|
+
label: "Input Sentiment",
|
|
46
|
+
description: "Group by detected input sentiment (positive, negative, neutral)",
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: "sentiment.thumbs_up_down",
|
|
50
|
+
label: "Thumbs Up/Down",
|
|
51
|
+
description: "Group by user feedback (positive, negative, neutral)",
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: "events.event_type",
|
|
55
|
+
label: "Event Type",
|
|
56
|
+
description: "Group by event type",
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: "evaluations.evaluation_passed",
|
|
60
|
+
label: "Evaluation Passed",
|
|
61
|
+
description: "Group by evaluation pass/fail status",
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: "evaluations.evaluation_label",
|
|
65
|
+
label: "Evaluation Label",
|
|
66
|
+
description: "Group by evaluation label result",
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
name: "evaluations.evaluation_processing_state",
|
|
70
|
+
label: "Evaluation Processing State",
|
|
71
|
+
description: "Group by evaluation processing state",
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
name: "error.has_error",
|
|
75
|
+
label: "Contains Error",
|
|
76
|
+
description: "Group by whether the trace contains an error",
|
|
77
|
+
},
|
|
78
|
+
];
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
export interface MetricInfo {
|
|
2
|
+
category: string;
|
|
3
|
+
name: string;
|
|
4
|
+
label: string;
|
|
5
|
+
allowedAggregations: string[];
|
|
6
|
+
description: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const analyticsMetrics: MetricInfo[] = [
|
|
10
|
+
// metadata
|
|
11
|
+
{
|
|
12
|
+
category: "metadata",
|
|
13
|
+
name: "trace_id",
|
|
14
|
+
label: "Traces",
|
|
15
|
+
allowedAggregations: ["cardinality"],
|
|
16
|
+
description: "Count of unique traces",
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
category: "metadata",
|
|
20
|
+
name: "user_id",
|
|
21
|
+
label: "Users",
|
|
22
|
+
allowedAggregations: ["cardinality"],
|
|
23
|
+
description: "Count of unique users",
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
category: "metadata",
|
|
27
|
+
name: "thread_id",
|
|
28
|
+
label: "Threads",
|
|
29
|
+
allowedAggregations: ["cardinality"],
|
|
30
|
+
description: "Count of unique conversation threads",
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
category: "metadata",
|
|
34
|
+
name: "span_type",
|
|
35
|
+
label: "Span Type",
|
|
36
|
+
allowedAggregations: ["cardinality"],
|
|
37
|
+
description: "Count of spans, optionally filtered by span type",
|
|
38
|
+
},
|
|
39
|
+
// sentiment
|
|
40
|
+
{
|
|
41
|
+
category: "sentiment",
|
|
42
|
+
name: "input_sentiment",
|
|
43
|
+
label: "Input Sentiment Score",
|
|
44
|
+
allowedAggregations: ["avg", "sum", "min", "max", "median", "p99", "p95", "p90"],
|
|
45
|
+
description: "Sentiment analysis score of inputs",
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
category: "sentiment",
|
|
49
|
+
name: "thumbs_up_down",
|
|
50
|
+
label: "Thumbs Up/Down Score",
|
|
51
|
+
allowedAggregations: [
|
|
52
|
+
"terms",
|
|
53
|
+
"cardinality",
|
|
54
|
+
"avg",
|
|
55
|
+
"sum",
|
|
56
|
+
"min",
|
|
57
|
+
"max",
|
|
58
|
+
"median",
|
|
59
|
+
"p99",
|
|
60
|
+
"p95",
|
|
61
|
+
"p90",
|
|
62
|
+
],
|
|
63
|
+
description: "User feedback score (-1 to 1)",
|
|
64
|
+
},
|
|
65
|
+
// performance
|
|
66
|
+
{
|
|
67
|
+
category: "performance",
|
|
68
|
+
name: "completion_time",
|
|
69
|
+
label: "Completion Time",
|
|
70
|
+
allowedAggregations: ["avg", "sum", "min", "max", "median", "p99", "p95", "p90"],
|
|
71
|
+
description: "Time to complete the trace (ms)",
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
category: "performance",
|
|
75
|
+
name: "first_token",
|
|
76
|
+
label: "Time to First Token",
|
|
77
|
+
allowedAggregations: ["avg", "sum", "min", "max", "median", "p99", "p95", "p90"],
|
|
78
|
+
description: "Time to first token (ms)",
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
category: "performance",
|
|
82
|
+
name: "total_cost",
|
|
83
|
+
label: "Total Cost",
|
|
84
|
+
allowedAggregations: ["avg", "sum", "min", "max", "median", "p99", "p95", "p90"],
|
|
85
|
+
description: "Cost per trace in USD",
|
|
86
|
+
},
|
|
87
|
+
{
|
|
88
|
+
category: "performance",
|
|
89
|
+
name: "prompt_tokens",
|
|
90
|
+
label: "Prompt Tokens",
|
|
91
|
+
allowedAggregations: ["avg", "sum", "min", "max", "median", "p99", "p95", "p90"],
|
|
92
|
+
description: "Input token count",
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
category: "performance",
|
|
96
|
+
name: "completion_tokens",
|
|
97
|
+
label: "Completion Tokens",
|
|
98
|
+
allowedAggregations: ["avg", "sum", "min", "max", "median", "p99", "p95", "p90"],
|
|
99
|
+
description: "Output token count",
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
category: "performance",
|
|
103
|
+
name: "total_tokens",
|
|
104
|
+
label: "Total Tokens",
|
|
105
|
+
allowedAggregations: ["avg", "sum", "min", "max", "median", "p99", "p95", "p90"],
|
|
106
|
+
description: "Total token count (input + output)",
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
category: "performance",
|
|
110
|
+
name: "tokens_per_second",
|
|
111
|
+
label: "Tokens per Second",
|
|
112
|
+
allowedAggregations: ["avg", "sum", "min", "max", "median", "p99", "p95", "p90"],
|
|
113
|
+
description: "Token generation speed",
|
|
114
|
+
},
|
|
115
|
+
// events
|
|
116
|
+
{
|
|
117
|
+
category: "events",
|
|
118
|
+
name: "event_type",
|
|
119
|
+
label: "Event Type",
|
|
120
|
+
allowedAggregations: ["cardinality"],
|
|
121
|
+
description: "Count of events, optionally filtered by event type",
|
|
122
|
+
},
|
|
123
|
+
{
|
|
124
|
+
category: "events",
|
|
125
|
+
name: "event_score",
|
|
126
|
+
label: "Event Score",
|
|
127
|
+
allowedAggregations: [
|
|
128
|
+
"terms",
|
|
129
|
+
"avg",
|
|
130
|
+
"sum",
|
|
131
|
+
"min",
|
|
132
|
+
"max",
|
|
133
|
+
"median",
|
|
134
|
+
"p99",
|
|
135
|
+
"p95",
|
|
136
|
+
"p90",
|
|
137
|
+
],
|
|
138
|
+
description: "Numeric score from events (requires event_type key and metrics key)",
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
category: "events",
|
|
142
|
+
name: "event_details",
|
|
143
|
+
label: "Event Details",
|
|
144
|
+
allowedAggregations: ["cardinality"],
|
|
145
|
+
description:
|
|
146
|
+
"Event detail key/value distribution (requires event_type key and details key)",
|
|
147
|
+
},
|
|
148
|
+
// evaluations
|
|
149
|
+
{
|
|
150
|
+
category: "evaluations",
|
|
151
|
+
name: "evaluation_score",
|
|
152
|
+
label: "Evaluation Score",
|
|
153
|
+
allowedAggregations: ["avg", "sum", "min", "max", "median", "p99", "p95", "p90"],
|
|
154
|
+
description: "Numeric evaluation score (requires evaluator_id key)",
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
category: "evaluations",
|
|
158
|
+
name: "evaluation_pass_rate",
|
|
159
|
+
label: "Evaluation Pass Rate",
|
|
160
|
+
allowedAggregations: ["avg", "sum", "min", "max", "median", "p99", "p95", "p90"],
|
|
161
|
+
description:
|
|
162
|
+
"Percentage of traces passing evaluation (requires evaluator_id key)",
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
category: "evaluations",
|
|
166
|
+
name: "evaluation_runs",
|
|
167
|
+
label: "Evaluation Runs",
|
|
168
|
+
allowedAggregations: ["cardinality"],
|
|
169
|
+
description: "Count of evaluation executions",
|
|
170
|
+
},
|
|
171
|
+
// threads
|
|
172
|
+
{
|
|
173
|
+
category: "threads",
|
|
174
|
+
name: "average_duration_per_thread",
|
|
175
|
+
label: "Thread Duration",
|
|
176
|
+
allowedAggregations: ["avg"],
|
|
177
|
+
description: "Average duration of conversation threads (ms)",
|
|
178
|
+
},
|
|
179
|
+
];
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
export interface FilterFieldInfo {
|
|
2
|
+
field: string;
|
|
3
|
+
description: string;
|
|
4
|
+
example?: string;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export const filterFields: FilterFieldInfo[] = [
|
|
8
|
+
{
|
|
9
|
+
field: "topics.topics",
|
|
10
|
+
description: "Main topic classification of the trace",
|
|
11
|
+
example: "billing",
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
field: "topics.subtopics",
|
|
15
|
+
description: "Subtopic classification",
|
|
16
|
+
example: "refund-request",
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
field: "metadata.user_id",
|
|
20
|
+
description: "User ID from trace metadata",
|
|
21
|
+
example: "user-123",
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
field: "metadata.thread_id",
|
|
25
|
+
description: "Conversation thread ID",
|
|
26
|
+
example: "thread-456",
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
field: "metadata.customer_id",
|
|
30
|
+
description: "Customer/organization ID",
|
|
31
|
+
example: "customer-789",
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
field: "metadata.labels",
|
|
35
|
+
description: "Custom labels attached to traces",
|
|
36
|
+
example: "production",
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
field: "metadata.key",
|
|
40
|
+
description: "Custom metadata key",
|
|
41
|
+
example: "environment",
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
field: "metadata.value",
|
|
45
|
+
description: "Custom metadata value (used with metadata.key)",
|
|
46
|
+
example: "staging",
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
field: "metadata.prompt_ids",
|
|
50
|
+
description: "Prompt IDs used in the trace",
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
field: "traces.error",
|
|
54
|
+
description: "Whether the trace has errors",
|
|
55
|
+
example: "true",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
field: "spans.type",
|
|
59
|
+
description: "Span type (llm, tool, agent, chain, rag)",
|
|
60
|
+
example: "llm",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
field: "spans.model",
|
|
64
|
+
description: "LLM model name used in spans",
|
|
65
|
+
example: "gpt-4o",
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
field: "evaluations.evaluator_id",
|
|
69
|
+
description: "Evaluator that ran on the trace",
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
field: "evaluations.evaluator_id.guardrails_only",
|
|
73
|
+
description: "Evaluator ID filtered to guardrails only",
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
field: "evaluations.passed",
|
|
77
|
+
description: "Whether evaluations passed",
|
|
78
|
+
example: "true",
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
field: "evaluations.score",
|
|
82
|
+
description: "Evaluation score (numeric)",
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
field: "evaluations.state",
|
|
86
|
+
description: "Evaluation state (processed, error, skipped)",
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
field: "evaluations.label",
|
|
90
|
+
description: "Evaluation label result",
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
field: "events.event_type",
|
|
94
|
+
description: "Type of event (thumbs_up_down, custom)",
|
|
95
|
+
example: "thumbs_up_down",
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
field: "events.metrics.key",
|
|
99
|
+
description: "Event metric key",
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
field: "events.metrics.value",
|
|
103
|
+
description: "Event metric value (numeric)",
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
field: "events.event_details.key",
|
|
107
|
+
description: "Event detail key",
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
field: "annotations.hasAnnotation",
|
|
111
|
+
description: "Whether trace has human annotations",
|
|
112
|
+
example: "true",
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
field: "sentiment.input_sentiment",
|
|
116
|
+
description: "Detected sentiment of input",
|
|
117
|
+
example: "positive",
|
|
118
|
+
},
|
|
119
|
+
];
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { archiveScenario as apiArchiveScenario } from "../langwatch-api-scenarios.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Handles the archive_scenario MCP tool invocation.
|
|
5
|
+
*
|
|
6
|
+
* Archives (soft-deletes) a scenario and returns confirmation.
|
|
7
|
+
*/
|
|
8
|
+
export async function handleArchiveScenario(params: {
|
|
9
|
+
scenarioId: string;
|
|
10
|
+
}): Promise<string> {
|
|
11
|
+
const result = await apiArchiveScenario(params.scenarioId);
|
|
12
|
+
|
|
13
|
+
const lines: string[] = [];
|
|
14
|
+
lines.push("Scenario archived successfully!\n");
|
|
15
|
+
lines.push(`**ID**: ${result.id}`);
|
|
16
|
+
lines.push(`**Status**: ${result.archived ? "archived" : "active"}`);
|
|
17
|
+
|
|
18
|
+
return lines.join("\n");
|
|
19
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { createPrompt as apiCreatePrompt } from "../langwatch-api.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Handles the create_prompt MCP tool invocation.
|
|
5
|
+
*
|
|
6
|
+
* Creates a new prompt in the LangWatch project and returns a
|
|
7
|
+
* confirmation with the created prompt's details.
|
|
8
|
+
*/
|
|
9
|
+
export async function handleCreatePrompt(params: {
|
|
10
|
+
name: string;
|
|
11
|
+
handle?: string;
|
|
12
|
+
messages: Array<{ role: string; content: string }>;
|
|
13
|
+
model: string;
|
|
14
|
+
modelProvider: string;
|
|
15
|
+
description?: string;
|
|
16
|
+
}): Promise<string> {
|
|
17
|
+
const result = await apiCreatePrompt(params);
|
|
18
|
+
|
|
19
|
+
const lines: string[] = [];
|
|
20
|
+
lines.push("Prompt created successfully!\n");
|
|
21
|
+
if (result.id) lines.push(`**ID**: ${result.id}`);
|
|
22
|
+
if (result.handle) lines.push(`**Handle**: ${result.handle}`);
|
|
23
|
+
lines.push(`**Name**: ${result.name || params.name}`);
|
|
24
|
+
lines.push(`**Model**: ${params.model} (${params.modelProvider})`);
|
|
25
|
+
if (result.latestVersionNumber != null)
|
|
26
|
+
lines.push(`**Version**: v${result.latestVersionNumber}`);
|
|
27
|
+
|
|
28
|
+
return lines.join("\n");
|
|
29
|
+
}
|