langwatch 0.1.0 → 0.1.3

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.
Files changed (46) hide show
  1. package/copy-types.sh +17 -0
  2. package/dist/chunk-2I4YLOQY.mjs +736 -0
  3. package/dist/chunk-2I4YLOQY.mjs.map +1 -0
  4. package/dist/index.d.mts +352 -4
  5. package/dist/index.d.ts +352 -4
  6. package/dist/index.js +6505 -413
  7. package/dist/index.js.map +1 -1
  8. package/dist/index.mjs +571 -359
  9. package/dist/index.mjs.map +1 -1
  10. package/dist/{utils-DDcm0z9v.d.mts → utils-CFtM8VVg.d.mts} +108 -31
  11. package/dist/{utils-DDcm0z9v.d.ts → utils-CFtM8VVg.d.ts} +108 -31
  12. package/dist/utils.d.mts +1 -2
  13. package/dist/utils.d.ts +1 -2
  14. package/dist/utils.js +437 -0
  15. package/dist/utils.js.map +1 -1
  16. package/dist/utils.mjs +3 -1
  17. package/example/README.md +3 -1
  18. package/example/app/(chat)/chat/[id]/page.tsx +1 -1
  19. package/example/app/(chat)/page.tsx +10 -5
  20. package/example/app/guardrails/page.tsx +26 -0
  21. package/example/app/langchain/page.tsx +27 -0
  22. package/example/app/langchain-rag/page.tsx +28 -0
  23. package/example/app/share/[id]/page.tsx +1 -1
  24. package/example/components/chat-list.tsx +1 -1
  25. package/example/components/chat-panel.tsx +1 -1
  26. package/example/components/header.tsx +39 -13
  27. package/example/components/prompt-form.tsx +1 -1
  28. package/example/components/stocks/stock-purchase.tsx +1 -1
  29. package/example/components/stocks/stocks.tsx +1 -1
  30. package/example/lib/chat/guardrails.tsx +181 -0
  31. package/example/lib/chat/langchain-rag.tsx +191 -0
  32. package/example/lib/chat/langchain.tsx +112 -0
  33. package/example/lib/chat/{actions.tsx → vercel-ai.tsx} +1 -1
  34. package/example/package-lock.json +289 -6
  35. package/example/package.json +1 -0
  36. package/package.json +13 -5
  37. package/src/evaluations.ts +219 -0
  38. package/src/index.test.ts +5 -0
  39. package/src/index.ts +190 -7
  40. package/src/langchain.ts +557 -0
  41. package/src/{helpers.ts → typeUtils.ts} +20 -2
  42. package/src/types.ts +7 -3
  43. package/src/utils.ts +25 -2
  44. package/ts-to-zod.config.js +2 -0
  45. package/dist/chunk-AP23NJ57.mjs +0 -296
  46. package/dist/chunk-AP23NJ57.mjs.map +0 -1
package/dist/index.mjs CHANGED
@@ -1,9 +1,14 @@
1
1
  import {
2
2
  __spreadProps,
3
3
  __spreadValues,
4
+ autoconvertTypedValues,
4
5
  captureError,
5
- convertFromVercelAIMessages
6
- } from "./chunk-AP23NJ57.mjs";
6
+ collectorRESTParamsSchema,
7
+ convertFromVercelAIMessages,
8
+ reservedSpanParamsSchema,
9
+ reservedTraceMetadataSchema,
10
+ spanSchema
11
+ } from "./chunk-2I4YLOQY.mjs";
7
12
 
8
13
  // src/index.ts
9
14
  import EventEmitter from "events";
@@ -11,11 +16,443 @@ import { nanoid } from "nanoid";
11
16
  import { ZodError } from "zod";
12
17
  import { fromZodError } from "zod-validation-error";
13
18
 
14
- // src/helpers.ts
19
+ // package.json
20
+ var version = "0.1.3";
21
+
22
+ // src/evaluations.ts
23
+ var evaluate = async (params) => {
24
+ const slug = "slug" in params ? params.slug : params.evaluator;
25
+ const span = optionalCreateSpan({
26
+ trace: params.trace,
27
+ span: params.span,
28
+ name: params.name ? params.name : slug,
29
+ type: params.asGuardrail ? "guardrail" : "evaluation"
30
+ });
31
+ try {
32
+ const requestParams = prepareData(__spreadProps(__spreadValues({}, params), {
33
+ slug,
34
+ traceId: span == null ? void 0 : span.trace.traceId,
35
+ spanId: span == null ? void 0 : span.spanId,
36
+ span
37
+ }));
38
+ const response = await fetch(requestParams.url, {
39
+ method: "POST",
40
+ headers: requestParams.headers,
41
+ body: JSON.stringify(requestParams.json)
42
+ });
43
+ if (!response.ok) {
44
+ throw new Error(`HTTP error! status: ${response.status}`);
45
+ }
46
+ const result = await response.json();
47
+ return handleResponse(result, span, params.asGuardrail);
48
+ } catch (e) {
49
+ return handleException(e, span, params.asGuardrail);
50
+ }
51
+ };
52
+ var optionalCreateSpan = ({
53
+ trace,
54
+ span,
55
+ name,
56
+ type
57
+ }) => {
58
+ if (span) {
59
+ return span.startSpan({ name, type });
60
+ } else if (trace) {
61
+ return trace.startSpan({ name, type });
62
+ }
63
+ return void 0;
64
+ };
65
+ var prepareData = (params) => {
66
+ var _a;
67
+ const data = {};
68
+ if (params.input) data.input = params.input;
69
+ if (params.output) data.output = params.output;
70
+ if (params.expectedOutput) data.expected_output = params.expectedOutput;
71
+ if (params.contexts && params.contexts.length > 0)
72
+ data.contexts = params.contexts;
73
+ if (params.conversation && params.conversation.length > 0)
74
+ data.conversation = params.conversation;
75
+ if (params.span) {
76
+ params.span.update({
77
+ input: { type: "json", value: data },
78
+ params: params.settings
79
+ });
80
+ }
81
+ return {
82
+ url: `${process.env.LANGWATCH_ENDPOINT}/api/evaluations/${params.slug}/evaluate`,
83
+ json: {
84
+ trace_id: params.traceId,
85
+ span_id: params.spanId,
86
+ name: params.name,
87
+ data,
88
+ settings: params.settings,
89
+ as_guardrail: params.asGuardrail
90
+ },
91
+ headers: {
92
+ "X-Auth-Token": (_a = process.env.LANGWATCH_API_KEY) != null ? _a : "",
93
+ "Content-Type": "application/json"
94
+ }
95
+ };
96
+ };
97
+ var handleResponse = (response, span, asGuardrail = false) => {
98
+ var _a;
99
+ if (response.status === "error") {
100
+ response.details = (_a = response.details) != null ? _a : "";
101
+ }
102
+ for (const key of Object.keys(response)) {
103
+ if (response[key] === null || response[key] === void 0) {
104
+ delete response[key];
105
+ }
106
+ }
107
+ if (span) {
108
+ const output = asGuardrail ? {
109
+ type: "guardrail_result",
110
+ value: response
111
+ } : {
112
+ type: "evaluation_result",
113
+ value: response
114
+ };
115
+ span.update({ output });
116
+ if (response.cost) {
117
+ span.update({
118
+ metrics: {
119
+ cost: response.cost.amount
120
+ }
121
+ });
122
+ }
123
+ span.end();
124
+ }
125
+ return response;
126
+ };
127
+ var handleException = (e, span, asGuardrail = false) => {
128
+ const response = {
129
+ status: "error",
130
+ details: e.toString()
131
+ };
132
+ if (asGuardrail) {
133
+ response.passed = true;
134
+ }
135
+ return handleResponse(response, span, asGuardrail);
136
+ };
137
+
138
+ // src/langchain.ts
139
+ import { BaseCallbackHandler } from "@langchain/core/callbacks/base";
140
+ import {
141
+ AIMessage,
142
+ AIMessageChunk,
143
+ FunctionMessage,
144
+ FunctionMessageChunk,
145
+ HumanMessage,
146
+ HumanMessageChunk,
147
+ SystemMessage,
148
+ SystemMessageChunk,
149
+ ToolMessage,
150
+ ToolMessageChunk,
151
+ mapChatMessagesToStoredMessages
152
+ } from "@langchain/core/messages";
153
+ import { stringify } from "javascript-stringify";
154
+ var LangWatchCallbackHandler = class extends BaseCallbackHandler {
155
+ constructor({ trace }) {
156
+ super();
157
+ this.name = "LangWatchCallbackHandler";
158
+ this.spans = {};
159
+ this.trace = trace;
160
+ }
161
+ async handleLLMStart(llm, prompts, runId, parentRunId, extraParams, _tags, metadata, name) {
162
+ this.spans[runId] = this.buildLLMSpan({
163
+ llm,
164
+ runId,
165
+ parentRunId,
166
+ input: {
167
+ type: "json",
168
+ value: prompts
169
+ },
170
+ extraParams,
171
+ metadata,
172
+ name
173
+ });
174
+ }
175
+ buildLLMSpan({
176
+ llm,
177
+ runId,
178
+ parentRunId,
179
+ input,
180
+ extraParams,
181
+ metadata,
182
+ name
183
+ }) {
184
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
185
+ try {
186
+ const parent = this.getParent(parentRunId);
187
+ const vendor = (_b = metadata == null ? void 0 : metadata.ls_provider) != null ? _b : (_a = llm.id.at(-2)) == null ? void 0 : _a.toString();
188
+ const model = (_e = (_d = metadata == null ? void 0 : metadata.ls_model_name) != null ? _d : (_c = llm.kwargs) == null ? void 0 : _c.model) != null ? _e : "unknown";
189
+ const span = parent.startLLMSpan({
190
+ spanId: runId,
191
+ name: name != null ? name : (_f = llm.id.at(-1)) == null ? void 0 : _f.toString(),
192
+ input,
193
+ model: [vendor, model].filter((x) => x).join("/"),
194
+ params: __spreadValues({
195
+ temperature: (_g = extraParams == null ? void 0 : extraParams.invocation_params) == null ? void 0 : _g.temperature
196
+ }, ((_h = extraParams == null ? void 0 : extraParams.invocation_params) == null ? void 0 : _h.functions) ? { functions: (_i = extraParams == null ? void 0 : extraParams.invocation_params) == null ? void 0 : _i.functions } : {})
197
+ });
198
+ return span;
199
+ } catch (e) {
200
+ this.trace.client.emit("error", e);
201
+ throw e;
202
+ }
203
+ }
204
+ async handleChatModelStart(llm, messages, runId, parentRunId, extraParams, tags, metadata, name) {
205
+ this.spans[runId] = this.buildLLMSpan({
206
+ name,
207
+ llm,
208
+ runId,
209
+ parentRunId,
210
+ input: {
211
+ type: "chat_messages",
212
+ value: messages.flatMap(convertFromLangChainMessages)
213
+ },
214
+ extraParams,
215
+ metadata
216
+ });
217
+ }
218
+ async handleNewToken(_token, runId) {
219
+ const span = this.spans[runId];
220
+ if (runId && span && !span.timestamps.firstTokenAt) {
221
+ span.update({
222
+ timestamps: __spreadProps(__spreadValues({}, span.timestamps), { firstTokenAt: Date.now() })
223
+ });
224
+ }
225
+ }
226
+ async handleLLMEnd(response, runId, _parentRunId) {
227
+ try {
228
+ const span = this.spans[runId];
229
+ if (!span) {
230
+ return;
231
+ }
232
+ const outputs = [];
233
+ for (const generation of response.generations) {
234
+ for (const generation_ of generation) {
235
+ if ("message" in generation_) {
236
+ outputs.push({
237
+ type: "chat_messages",
238
+ value: convertFromLangChainMessages([
239
+ generation_.message
240
+ ])
241
+ });
242
+ } else if ("text" in generation_) {
243
+ outputs.push({
244
+ type: "text",
245
+ value: generation_.text
246
+ });
247
+ } else {
248
+ outputs.push({
249
+ type: "text",
250
+ value: JSON.stringify(generation_)
251
+ });
252
+ }
253
+ }
254
+ }
255
+ const output = outputs.length === 1 ? outputs[0] : { type: "list", value: outputs };
256
+ span.end({
257
+ output
258
+ // ...(metrics ? { metrics } : {}),
259
+ });
260
+ } catch (e) {
261
+ this.trace.client.emit("error", e);
262
+ throw e;
263
+ }
264
+ }
265
+ async handleLLMError(err, runId, _parentRunId) {
266
+ this.errorSpan({ runId, error: err });
267
+ }
268
+ async handleChainStart(chain, inputs, runId, parentRunId, _tags, _metadata, _runType, name) {
269
+ this.spans[runId] = this.buildSpan({
270
+ type: "chain",
271
+ serialized: chain,
272
+ runId,
273
+ parentRunId,
274
+ input: inputs,
275
+ name
276
+ });
277
+ }
278
+ async handleChainEnd(output, runId, _parentRunId) {
279
+ this.endSpan({
280
+ runId,
281
+ output
282
+ });
283
+ }
284
+ async handleChainError(err, runId, _parentRunId, _tags, _kwargs) {
285
+ this.errorSpan({ runId, error: err });
286
+ }
287
+ async handleToolStart(tool, input, runId, parentRunId, _tags, _metadata, name) {
288
+ this.spans[runId] = this.buildSpan({
289
+ type: "tool",
290
+ serialized: tool,
291
+ runId,
292
+ parentRunId,
293
+ input,
294
+ name
295
+ });
296
+ }
297
+ async handleToolEnd(output, runId, _parentRunId) {
298
+ this.endSpan({ runId, output });
299
+ }
300
+ async handleToolError(err, runId, _parentRunId, _tags) {
301
+ this.errorSpan({ runId, error: err });
302
+ }
303
+ async handleRetrieverStart(retriever, query, runId, parentRunId, _tags, _metadata, name) {
304
+ var _a, _b;
305
+ try {
306
+ const parent = this.getParent(parentRunId);
307
+ this.spans[runId] = parent.startRAGSpan({
308
+ spanId: runId,
309
+ name: (_b = name != null ? name : retriever.name) != null ? _b : (_a = retriever.id.at(-1)) == null ? void 0 : _a.toString(),
310
+ input: this.autoconvertTypedValues(query)
311
+ });
312
+ } catch (e) {
313
+ this.trace.client.emit("error", e);
314
+ throw e;
315
+ }
316
+ }
317
+ async handleRetrieverEnd(documents, runId, _parentRunId, _tags) {
318
+ try {
319
+ const contexts = documents.map((doc) => __spreadValues({
320
+ content: doc.pageContent
321
+ }, doc.metadata.source ? { documentId: doc.metadata.source } : {}));
322
+ const span = this.spans[runId];
323
+ if (!span) {
324
+ return;
325
+ }
326
+ span.end({
327
+ contexts,
328
+ output: this.autoconvertTypedValues(documents)
329
+ });
330
+ } catch (e) {
331
+ this.trace.client.emit("error", e);
332
+ throw e;
333
+ }
334
+ }
335
+ async handleRetrieverError(err, runId, _parentRunId, _tags) {
336
+ this.errorSpan({ runId, error: err });
337
+ }
338
+ async handleAgentAction(_action, runId, _parentRunId, _tags) {
339
+ const span = this.spans[runId];
340
+ if (!span) {
341
+ return;
342
+ }
343
+ span.update({
344
+ type: "agent"
345
+ });
346
+ }
347
+ async handleAgentEnd(action, runId, _parentRunId, _tags) {
348
+ this.endSpan({
349
+ runId,
350
+ output: action.returnValues
351
+ });
352
+ }
353
+ buildSpan({
354
+ type,
355
+ serialized,
356
+ runId,
357
+ parentRunId,
358
+ input,
359
+ name
360
+ }) {
361
+ var _a, _b;
362
+ try {
363
+ const parent = this.getParent(parentRunId);
364
+ const span = parent.startSpan({
365
+ spanId: runId,
366
+ type,
367
+ name: (_b = name != null ? name : serialized.name) != null ? _b : (_a = serialized.id.at(-1)) == null ? void 0 : _a.toString(),
368
+ input: this.autoconvertTypedValues(input)
369
+ });
370
+ return span;
371
+ } catch (e) {
372
+ this.trace.client.emit("error", e);
373
+ throw e;
374
+ }
375
+ }
376
+ endSpan({ runId, output }) {
377
+ try {
378
+ const span = this.spans[runId];
379
+ if (!span) {
380
+ return;
381
+ }
382
+ span.end({
383
+ output: this.autoconvertTypedValues(output)
384
+ });
385
+ } catch (e) {
386
+ this.trace.client.emit("error", e);
387
+ throw e;
388
+ }
389
+ }
390
+ errorSpan({ runId, error }) {
391
+ const span = this.spans[runId];
392
+ if (!span) {
393
+ return;
394
+ }
395
+ span.end({
396
+ error
397
+ });
398
+ }
399
+ autoconvertTypedValues(value) {
400
+ var _a;
401
+ if (!value || typeof value === "object" && Object.keys(value).length === 0) {
402
+ return void 0;
403
+ }
404
+ if (typeof value === "string") {
405
+ return { type: "text", value };
406
+ }
407
+ try {
408
+ JSON.stringify(value);
409
+ return { type: "json", value };
410
+ } catch (e) {
411
+ return { type: "text", value: (_a = stringify(value)) != null ? _a : value.toString() };
412
+ }
413
+ }
414
+ getParent(parentRunId) {
415
+ var _a, _b;
416
+ return (_b = parentRunId ? this.spans[parentRunId] : this.spans[(_a = Object.keys(this.spans).at(-1)) != null ? _a : ""]) != null ? _b : this.trace;
417
+ }
418
+ };
419
+ var convertFromLangChainMessages = (messages) => {
420
+ const chatMessages = [];
421
+ for (const message of messages) {
422
+ chatMessages.push(convertFromLangChainMessage(message));
423
+ }
424
+ return chatMessages;
425
+ };
426
+ var convertFromLangChainMessage = (message) => {
427
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
428
+ let role = "user";
429
+ const message_ = message.lc_serializable ? mapChatMessagesToStoredMessages([message])[0] : message;
430
+ if (message_ instanceof HumanMessage || message_ instanceof HumanMessageChunk || ((_a = message_.id) == null ? void 0 : _a.at(-1)) === "HumanMessage" || ((_b = message_.id) == null ? void 0 : _b.at(-1)) === "HumanMessageChunk" || message_.type === "human") {
431
+ role = "user";
432
+ } else if (message instanceof AIMessage || message instanceof AIMessageChunk || ((_c = message.id) == null ? void 0 : _c.at(-1)) === "AIMessage" || ((_d = message.id) == null ? void 0 : _d.at(-1)) === "AIMessageChunk" || message_.type === "ai") {
433
+ role = "assistant";
434
+ } else if (message instanceof SystemMessage || message instanceof SystemMessageChunk || ((_e = message.id) == null ? void 0 : _e.at(-1)) === "SystemMessage" || ((_f = message.id) == null ? void 0 : _f.at(-1)) === "SystemMessageChunk" || message_.type === "system") {
435
+ role = "system";
436
+ } else if (message instanceof FunctionMessage || message instanceof FunctionMessageChunk || ((_g = message.id) == null ? void 0 : _g.at(-1)) === "FunctionMessage" || ((_h = message.id) == null ? void 0 : _h.at(-1)) === "FunctionMessageChunk" || message_.type === "function") {
437
+ role = "function";
438
+ } else if (message instanceof ToolMessage || message instanceof ToolMessageChunk || ((_i = message.id) == null ? void 0 : _i.at(-1)) === "ToolMessage" || ((_j = message.id) == null ? void 0 : _j.at(-1)) === "ToolMessageChunk" || message_.type === "tool") {
439
+ role = "tool";
440
+ }
441
+ const content = typeof message.content === "string" ? message.content : message.content.map(
442
+ (content2) => content2.type === "text" ? { type: "text", text: content2.text } : content2.type == "image_url" ? { type: "image_url", image_url: content2.image_url } : { type: "text", text: JSON.stringify(content2) }
443
+ );
444
+ const functionCall = message.additional_kwargs;
445
+ return __spreadValues({
446
+ role,
447
+ content
448
+ }, functionCall && typeof functionCall === "object" && Object.keys(functionCall).length > 0 ? { function_call: functionCall } : {});
449
+ };
450
+
451
+ // src/typeUtils.ts
15
452
  function camelToSnakeCase(str) {
16
453
  return str.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
17
454
  }
18
- function camelToSnakeCaseNested(obj) {
455
+ function camelToSnakeCaseNested(obj, parentKey) {
19
456
  if (Array.isArray(obj)) {
20
457
  return obj.map(
21
458
  (item) => camelToSnakeCaseNested(item)
@@ -25,7 +462,11 @@ function camelToSnakeCaseNested(obj) {
25
462
  for (const key in obj) {
26
463
  if (obj.hasOwnProperty(key)) {
27
464
  const newKey = camelToSnakeCase(key);
28
- newObj[newKey] = camelToSnakeCaseNested(obj[key]);
465
+ if (parentKey === "metadata" && !Object.keys(reservedTraceMetadataSchema.shape).includes(newKey) || parentKey === "params" && !Object.keys(reservedSpanParamsSchema.shape).includes(newKey)) {
466
+ newObj[key] = obj[key];
467
+ } else {
468
+ newObj[newKey] = camelToSnakeCaseNested(obj[key], newKey);
469
+ }
29
470
  }
30
471
  }
31
472
  return newObj;
@@ -34,355 +475,6 @@ function camelToSnakeCaseNested(obj) {
34
475
  }
35
476
  }
36
477
 
37
- // src/server/types/tracer.generated.ts
38
- import { z } from "zod";
39
- var chatRoleSchema = z.union([
40
- z.literal("system"),
41
- z.literal("user"),
42
- z.literal("assistant"),
43
- z.literal("function"),
44
- z.literal("tool"),
45
- z.literal("unknown")
46
- ]);
47
- var functionCallSchema = z.object({
48
- name: z.string().optional(),
49
- arguments: z.string().optional()
50
- });
51
- var toolCallSchema = z.object({
52
- id: z.string(),
53
- type: z.string(),
54
- function: functionCallSchema
55
- });
56
- var chatRichContentSchema = z.union([
57
- z.object({
58
- type: z.literal("text"),
59
- text: z.string().optional()
60
- }),
61
- z.object({
62
- type: z.literal("image_url"),
63
- image_url: z.object({
64
- url: z.string(),
65
- detail: z.union([z.literal("auto"), z.literal("low"), z.literal("high")]).optional()
66
- }).optional()
67
- })
68
- ]);
69
- var typedValueTextSchema = z.object({
70
- type: z.literal("text"),
71
- value: z.string()
72
- });
73
- var typedValueRawSchema = z.object({
74
- type: z.literal("raw"),
75
- value: z.string()
76
- });
77
- var jSONSerializableSchema = z.union([
78
- z.string(),
79
- z.number(),
80
- z.boolean(),
81
- z.record(z.any()),
82
- z.array(z.any())
83
- ]).nullable();
84
- var typedValueJsonSchema = z.object({
85
- type: z.literal("json"),
86
- value: jSONSerializableSchema
87
- });
88
- var moneySchema = z.object({
89
- currency: z.string(),
90
- amount: z.number()
91
- });
92
- var guardrailResultSchema = z.object({
93
- status: z.union([
94
- z.literal("processed"),
95
- z.literal("skipped"),
96
- z.literal("error")
97
- ]),
98
- passed: z.boolean(),
99
- score: z.number().optional().nullable(),
100
- details: z.string().optional().nullable(),
101
- cost: moneySchema.optional().nullable()
102
- });
103
- var typedValueGuardrailResultSchema = z.object({
104
- type: z.literal("guardrail_result"),
105
- value: guardrailResultSchema
106
- });
107
- var errorCaptureSchema = z.object({
108
- has_error: z.literal(true),
109
- message: z.string(),
110
- stacktrace: z.array(z.string())
111
- });
112
- var spanMetricsSchema = z.object({
113
- prompt_tokens: z.number().optional().nullable(),
114
- completion_tokens: z.number().optional().nullable(),
115
- tokens_estimated: z.boolean().optional().nullable(),
116
- cost: z.number().optional().nullable()
117
- });
118
- var spanParamsSchema = z.object({
119
- temperature: z.number().optional(),
120
- stream: z.boolean().optional(),
121
- functions: z.array(z.record(z.any())).optional(),
122
- tools: z.array(z.record(z.any())).optional(),
123
- tool_choice: z.string().optional()
124
- });
125
- var spanTimestampsSchema = z.object({
126
- started_at: z.number(),
127
- first_token_at: z.number().optional().nullable(),
128
- finished_at: z.number()
129
- });
130
- var spanTypesSchema = z.union([
131
- z.literal("span"),
132
- z.literal("llm"),
133
- z.literal("chain"),
134
- z.literal("tool"),
135
- z.literal("agent"),
136
- z.literal("rag"),
137
- z.literal("guardrail"),
138
- z.literal("unknown")
139
- ]);
140
- var rAGChunkSchema = z.object({
141
- document_id: z.string().optional().nullable(),
142
- chunk_id: z.string().optional().nullable(),
143
- content: z.union([z.string(), z.record(z.any()), z.array(z.any())])
144
- });
145
- var traceInputSchema = z.object({
146
- value: z.string(),
147
- embeddings: z.object({
148
- model: z.string(),
149
- embeddings: z.array(z.number())
150
- }).optional(),
151
- satisfaction_score: z.number().optional()
152
- });
153
- var traceOutputSchema = z.object({
154
- value: z.string(),
155
- embeddings: z.object({
156
- model: z.string(),
157
- embeddings: z.array(z.number())
158
- }).optional()
159
- });
160
- var traceSchema = z.object({
161
- trace_id: z.string(),
162
- project_id: z.string(),
163
- metadata: z.object({
164
- thread_id: z.string().optional(),
165
- user_id: z.string().optional(),
166
- customer_id: z.string().optional(),
167
- labels: z.array(z.string()).optional(),
168
- topic_id: z.string().optional(),
169
- subtopic_id: z.string().optional()
170
- }),
171
- timestamps: z.object({
172
- started_at: z.number(),
173
- inserted_at: z.number(),
174
- updated_at: z.number()
175
- }),
176
- input: traceInputSchema,
177
- output: traceOutputSchema.optional(),
178
- metrics: z.object({
179
- first_token_ms: z.number().optional().nullable(),
180
- total_time_ms: z.number().optional().nullable(),
181
- prompt_tokens: z.number().optional().nullable(),
182
- completion_tokens: z.number().optional().nullable(),
183
- total_cost: z.number().optional().nullable(),
184
- tokens_estimated: z.boolean().optional().nullable()
185
- }),
186
- error: errorCaptureSchema.optional().nullable(),
187
- indexing_md5s: z.array(z.string()).optional()
188
- });
189
- var elasticSearchTraceSchema = traceSchema.and(
190
- z.object({
191
- timestamps: traceSchema.shape.timestamps.and(
192
- z.object({
193
- updated_at: z.number()
194
- })
195
- )
196
- })
197
- );
198
- var traceCheckSchema = z.object({
199
- trace_id: z.string(),
200
- check_id: z.string(),
201
- project_id: z.string(),
202
- check_type: z.string(),
203
- check_name: z.string(),
204
- is_guardrail: z.boolean(),
205
- status: z.union([
206
- z.literal("scheduled"),
207
- z.literal("in_progress"),
208
- z.literal("error"),
209
- z.literal("skipped"),
210
- z.literal("processed")
211
- ]),
212
- passed: z.boolean().optional(),
213
- score: z.number().optional(),
214
- details: z.string().optional(),
215
- error: errorCaptureSchema.optional().nullable(),
216
- retries: z.number().optional(),
217
- timestamps: z.object({
218
- inserted_at: z.number().optional(),
219
- started_at: z.number().optional(),
220
- finished_at: z.number().optional(),
221
- updated_at: z.number()
222
- }),
223
- trace_metadata: z.object({
224
- thread_id: z.string().optional(),
225
- user_id: z.string().optional(),
226
- customer_id: z.string().optional(),
227
- labels: z.array(z.string()).optional(),
228
- topics: z.array(z.string()).optional()
229
- })
230
- });
231
- var experimentSchema = z.object({
232
- experiment_id: z.string(),
233
- variant: z.number()
234
- });
235
- var eventSchema = z.object({
236
- event_id: z.string(),
237
- event_type: z.string(),
238
- project_id: z.string(),
239
- metrics: z.record(z.number()),
240
- event_details: z.record(z.string()),
241
- trace_id: z.string().optional(),
242
- trace_metadata: z.object({
243
- thread_id: z.string().optional(),
244
- user_id: z.string().optional(),
245
- customer_id: z.string().optional(),
246
- labels: z.array(z.string()).optional(),
247
- topics: z.array(z.string()).optional()
248
- }),
249
- timestamps: z.object({
250
- started_at: z.number(),
251
- inserted_at: z.number(),
252
- updated_at: z.number()
253
- })
254
- });
255
- var elasticSearchEventSchema = eventSchema.omit({ metrics: true, event_details: true }).and(
256
- z.object({
257
- metrics: z.array(
258
- z.object({
259
- key: z.string(),
260
- value: z.number()
261
- })
262
- ),
263
- event_details: z.array(
264
- z.object({
265
- key: z.string(),
266
- value: z.string()
267
- })
268
- )
269
- })
270
- );
271
- var trackEventRESTParamsValidatorSchema = eventSchema.omit({
272
- event_id: true,
273
- project_id: true,
274
- timestamps: true,
275
- event_details: true,
276
- trace_metadata: true
277
- }).and(
278
- z.object({
279
- event_id: z.string().optional(),
280
- event_details: z.record(z.string()).optional(),
281
- timestamp: z.number().optional()
282
- })
283
- );
284
- var chatMessageSchema = z.object({
285
- role: chatRoleSchema.optional(),
286
- content: z.union([z.string(), z.array(chatRichContentSchema)]).optional().nullable(),
287
- function_call: functionCallSchema.optional().nullable(),
288
- tool_calls: z.array(toolCallSchema).optional().nullable(),
289
- tool_call_id: z.string().optional().nullable()
290
- });
291
- var typedValueChatMessagesSchema = z.object({
292
- type: z.literal("chat_messages"),
293
- value: z.array(chatMessageSchema)
294
- });
295
- var spanInputOutputSchema = z.lazy(
296
- () => z.union([
297
- typedValueTextSchema,
298
- typedValueChatMessagesSchema,
299
- typedValueGuardrailResultSchema,
300
- typedValueJsonSchema,
301
- typedValueRawSchema,
302
- z.object({
303
- type: z.literal("list"),
304
- value: z.array(spanInputOutputSchema)
305
- })
306
- ])
307
- );
308
- var baseSpanSchema = z.object({
309
- span_id: z.string(),
310
- parent_id: z.string().optional().nullable(),
311
- trace_id: z.string(),
312
- type: spanTypesSchema,
313
- name: z.string().optional().nullable(),
314
- input: spanInputOutputSchema.optional().nullable(),
315
- output: spanInputOutputSchema.optional().nullable(),
316
- error: errorCaptureSchema.optional().nullable(),
317
- timestamps: spanTimestampsSchema,
318
- metrics: spanMetricsSchema.optional().nullable()
319
- });
320
- var lLMSpanSchema = baseSpanSchema.extend({
321
- type: z.literal("llm"),
322
- vendor: z.string().optional().nullable(),
323
- model: z.string(),
324
- params: spanParamsSchema
325
- });
326
- var rAGSpanSchema = baseSpanSchema.extend({
327
- type: z.literal("rag"),
328
- contexts: z.array(rAGChunkSchema)
329
- });
330
- var spanSchema = z.union([
331
- lLMSpanSchema,
332
- rAGSpanSchema,
333
- baseSpanSchema
334
- ]);
335
- var spanInputOutputValidatorSchema = spanInputOutputSchema.and(
336
- z.object({
337
- value: z.any()
338
- })
339
- );
340
- var spanValidatorSchema = z.union([
341
- lLMSpanSchema.omit({ input: true, output: true }),
342
- rAGSpanSchema.omit({ input: true, output: true }),
343
- baseSpanSchema.omit({ input: true, output: true })
344
- ]).and(
345
- z.object({
346
- input: spanInputOutputValidatorSchema.optional().nullable(),
347
- output: spanInputOutputValidatorSchema.optional().nullable()
348
- })
349
- );
350
- var collectorRESTParamsSchema = z.object({
351
- trace_id: z.union([z.string(), z.undefined()]).optional().nullable(),
352
- spans: z.array(spanSchema),
353
- metadata: z.object({
354
- user_id: z.union([z.string(), z.undefined()]).optional().nullable(),
355
- thread_id: z.union([z.string(), z.undefined()]).optional().nullable(),
356
- customer_id: z.union([z.string(), z.undefined()]).optional().nullable(),
357
- labels: z.union([z.array(z.string()), z.undefined()]).optional().nullable(),
358
- experiments: z.union([z.array(experimentSchema), z.undefined()]).optional().nullable()
359
- }).optional()
360
- });
361
- var collectorRESTParamsValidatorSchema = collectorRESTParamsSchema.omit({ spans: true });
362
- var datasetSpanSchema = z.union([
363
- baseSpanSchema.omit({
364
- project_id: true,
365
- trace_id: true,
366
- id: true,
367
- timestamps: true,
368
- metrics: true
369
- }),
370
- lLMSpanSchema.omit({
371
- project_id: true,
372
- trace_id: true,
373
- id: true,
374
- timestamps: true,
375
- metrics: true
376
- }),
377
- rAGSpanSchema.omit({
378
- project_id: true,
379
- trace_id: true,
380
- id: true,
381
- timestamps: true,
382
- metrics: true
383
- })
384
- ]);
385
-
386
478
  // src/index.ts
387
479
  var LangWatch = class extends EventEmitter {
388
480
  constructor({
@@ -467,34 +559,139 @@ var LangWatchTrace = class {
467
559
  metadata
468
560
  }) {
469
561
  this.finishedSpans = {};
562
+ this.evaluations = [];
563
+ this.addEvaluation = ({
564
+ evaluationId,
565
+ span,
566
+ name,
567
+ type,
568
+ isGuardrail,
569
+ status = "processed",
570
+ passed,
571
+ score,
572
+ label,
573
+ details,
574
+ error,
575
+ timestamps
576
+ }) => {
577
+ var _a, _b;
578
+ const currentEvaluationIndex = this.evaluations.findIndex(
579
+ (e) => evaluationId && "evaluationId" in e && e.evaluationId === evaluationId
580
+ );
581
+ const currentEvaluation = currentEvaluationIndex !== -1 ? this.evaluations[currentEvaluationIndex] : void 0;
582
+ const evaluationResult = __spreadValues(__spreadValues(__spreadValues(__spreadValues({
583
+ status
584
+ }, passed !== void 0 && { passed }), score !== void 0 && { score }), label !== void 0 && { label }), details !== void 0 && { details });
585
+ let span_ = span;
586
+ if (!span_) {
587
+ span_ = this.startSpan({
588
+ type: "evaluation"
589
+ });
590
+ }
591
+ if (span_.type !== "evaluation") {
592
+ span_ = span_.startSpan({ type: "evaluation" });
593
+ }
594
+ span_.update({
595
+ name,
596
+ output: {
597
+ type: "evaluation_result",
598
+ value: evaluationResult
599
+ },
600
+ error,
601
+ timestamps: timestamps ? {
602
+ startedAt: (_a = timestamps.startedAt) != null ? _a : span_.timestamps.startedAt,
603
+ finishedAt: (_b = timestamps.finishedAt) != null ? _b : void 0
604
+ } : void 0
605
+ });
606
+ span_.end();
607
+ const evaluation = {
608
+ evaluationId: evaluationId != null ? evaluationId : `eval_${nanoid()}`,
609
+ spanId: span_.spanId,
610
+ name,
611
+ type,
612
+ isGuardrail,
613
+ status,
614
+ passed,
615
+ score,
616
+ label,
617
+ details,
618
+ error: error ? captureError(error) : void 0,
619
+ timestamps: timestamps != null ? timestamps : {
620
+ startedAt: span_.timestamps.startedAt,
621
+ finishedAt: span_.timestamps.finishedAt
622
+ }
623
+ };
624
+ if (currentEvaluation && currentEvaluationIndex !== -1) {
625
+ this.evaluations[currentEvaluationIndex] = __spreadValues(__spreadValues({}, currentEvaluation), evaluation);
626
+ } else {
627
+ this.evaluations.push(evaluation);
628
+ }
629
+ };
470
630
  this.client = client;
471
631
  this.traceId = traceId;
472
- this.metadata = metadata;
632
+ this.metadata = __spreadProps(__spreadValues({}, metadata), {
633
+ sdkVersion: version,
634
+ sdkLanguage: "typescript"
635
+ });
473
636
  }
474
637
  update({ metadata }) {
475
- var _a, _b;
476
- this.metadata = __spreadValues(__spreadValues(__spreadValues({}, this.metadata), metadata), typeof metadata.labels !== "undefined" ? { labels: [...(_b = (_a = this.metadata) == null ? void 0 : _a.labels) != null ? _b : [], ...metadata.labels] } : {});
638
+ var _a, _b, _c;
639
+ this.metadata = __spreadValues(__spreadValues(__spreadValues({}, this.metadata), metadata), typeof metadata.labels !== "undefined" ? {
640
+ labels: [
641
+ ...(_b = (_a = this.metadata) == null ? void 0 : _a.labels) != null ? _b : [],
642
+ ...(_c = metadata.labels) != null ? _c : []
643
+ ]
644
+ } : {});
645
+ }
646
+ setCurrentSpan(span) {
647
+ this.currentSpan = {
648
+ current: span,
649
+ previous: this.currentSpan
650
+ };
651
+ }
652
+ getCurrentSpan() {
653
+ var _a;
654
+ return (_a = this.currentSpan) == null ? void 0 : _a.current;
655
+ }
656
+ resetCurrentSpan() {
657
+ var _a;
658
+ this.currentSpan = (_a = this.currentSpan) == null ? void 0 : _a.previous;
477
659
  }
478
660
  startSpan(params) {
479
661
  const span = new LangWatchSpan(__spreadValues({
480
662
  trace: this
481
663
  }, params));
664
+ this.setCurrentSpan(span);
482
665
  return span;
483
666
  }
484
667
  startLLMSpan(params) {
485
668
  const span = new LangWatchLLMSpan(__spreadValues({
486
669
  trace: this
487
670
  }, params));
671
+ this.setCurrentSpan(span);
488
672
  return span;
489
673
  }
490
674
  startRAGSpan(params) {
491
675
  const span = new LangWatchRAGSpan(__spreadValues({
492
676
  trace: this
493
677
  }, params));
678
+ this.setCurrentSpan(span);
494
679
  return span;
495
680
  }
681
+ async evaluate(params) {
682
+ return evaluate(__spreadValues({
683
+ trace: this
684
+ }, params));
685
+ }
686
+ getLangChainCallback() {
687
+ if (!this.langchainCallback) {
688
+ this.langchainCallback = new LangWatchCallbackHandler({ trace: this });
689
+ }
690
+ return this.langchainCallback;
691
+ }
496
692
  onEnd(span) {
497
693
  this.finishedSpans[span.span_id] = span;
694
+ this.resetCurrentSpan();
498
695
  this.delayedSendSpans();
499
696
  }
500
697
  delayedSendSpans() {
@@ -509,8 +706,9 @@ var LangWatchTrace = class {
509
706
  try {
510
707
  trace = collectorRESTParamsSchema.parse({
511
708
  trace_id: this.traceId,
512
- metadata: camelToSnakeCaseNested(this.metadata),
513
- spans: Object.values(this.finishedSpans)
709
+ metadata: camelToSnakeCaseNested(this.metadata, "metadata"),
710
+ spans: Object.values(this.finishedSpans),
711
+ evaluations: camelToSnakeCaseNested(this.evaluations)
514
712
  });
515
713
  } catch (error) {
516
714
  if (error instanceof ZodError) {
@@ -585,6 +783,7 @@ var LangWatchSpan = class _LangWatchSpan {
585
783
  trace: this.trace,
586
784
  parentId: this.spanId
587
785
  }, params));
786
+ this.trace.setCurrentSpan(span);
588
787
  return span;
589
788
  }
590
789
  startLLMSpan(params) {
@@ -592,6 +791,7 @@ var LangWatchSpan = class _LangWatchSpan {
592
791
  trace: this.trace,
593
792
  parentId: this.spanId
594
793
  }, params));
794
+ this.trace.setCurrentSpan(span);
595
795
  return span;
596
796
  }
597
797
  startRAGSpan(params) {
@@ -599,8 +799,19 @@ var LangWatchSpan = class _LangWatchSpan {
599
799
  trace: this.trace,
600
800
  parentId: this.spanId
601
801
  }, params));
802
+ this.trace.setCurrentSpan(span);
602
803
  return span;
603
804
  }
805
+ addEvaluation(params) {
806
+ this.trace.addEvaluation(__spreadProps(__spreadValues({}, params), {
807
+ span: this
808
+ }));
809
+ }
810
+ async evaluate(params) {
811
+ return evaluate(__spreadValues({
812
+ span: this
813
+ }, params));
814
+ }
604
815
  end(params) {
605
816
  this.timestamps.finishedAt = Date.now();
606
817
  if (params) {
@@ -671,6 +882,7 @@ export {
671
882
  LangWatchRAGSpan,
672
883
  LangWatchSpan,
673
884
  LangWatchTrace,
885
+ autoconvertTypedValues,
674
886
  captureError,
675
887
  convertFromVercelAIMessages
676
888
  };