langwatch 0.2.0 → 0.3.0-prerelease.2

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 (229) hide show
  1. package/LICENSE +7 -0
  2. package/README.md +268 -1
  3. package/dist/chunk-4BZATFKJ.mjs +181 -0
  4. package/dist/chunk-4BZATFKJ.mjs.map +1 -0
  5. package/dist/chunk-CSC3CMIT.mjs +118 -0
  6. package/dist/chunk-CSC3CMIT.mjs.map +1 -0
  7. package/dist/chunk-F63YKTXA.mjs +47 -0
  8. package/dist/chunk-F63YKTXA.mjs.map +1 -0
  9. package/dist/chunk-G3AUABT7.js +4 -0
  10. package/dist/chunk-G3AUABT7.js.map +1 -0
  11. package/dist/chunk-HPC6Z7J4.js +118 -0
  12. package/dist/chunk-HPC6Z7J4.js.map +1 -0
  13. package/dist/chunk-KGDAENGD.js +50 -0
  14. package/dist/chunk-KGDAENGD.js.map +1 -0
  15. package/dist/chunk-LD74LVRU.js +47 -0
  16. package/dist/chunk-LD74LVRU.js.map +1 -0
  17. package/dist/chunk-OM7VY3XT.mjs +4 -0
  18. package/dist/chunk-PCQVQ7SB.js +45 -0
  19. package/dist/chunk-PCQVQ7SB.js.map +1 -0
  20. package/dist/chunk-PMBEK6YE.mjs +424 -0
  21. package/dist/chunk-PMBEK6YE.mjs.map +1 -0
  22. package/dist/chunk-PR3JDWC3.mjs +50 -0
  23. package/dist/chunk-PR3JDWC3.mjs.map +1 -0
  24. package/dist/chunk-PTJ6AAI7.js +360 -0
  25. package/dist/chunk-PTJ6AAI7.js.map +1 -0
  26. package/dist/chunk-QEWDG5QE.mjs +45 -0
  27. package/dist/chunk-QEWDG5QE.mjs.map +1 -0
  28. package/dist/chunk-REUCVT7A.mjs +39 -0
  29. package/dist/chunk-REUCVT7A.mjs.map +1 -0
  30. package/dist/chunk-SVJ7SCGB.js +424 -0
  31. package/dist/chunk-SVJ7SCGB.js.map +1 -0
  32. package/dist/chunk-VJSOCNPA.js +181 -0
  33. package/dist/chunk-VJSOCNPA.js.map +1 -0
  34. package/dist/chunk-WM2GRSRW.js +39 -0
  35. package/dist/chunk-WM2GRSRW.js.map +1 -0
  36. package/dist/chunk-Z5J5UI5E.mjs +360 -0
  37. package/dist/chunk-Z5J5UI5E.mjs.map +1 -0
  38. package/dist/client-B2HqIKg6.d.ts +51 -0
  39. package/dist/client-XyCqclCi.d.mts +51 -0
  40. package/dist/client-browser.d.mts +8 -0
  41. package/dist/client-browser.d.ts +8 -0
  42. package/dist/client-browser.js +83 -0
  43. package/dist/client-browser.js.map +1 -0
  44. package/dist/client-browser.mjs +83 -0
  45. package/dist/client-browser.mjs.map +1 -0
  46. package/dist/client-node.d.mts +8 -0
  47. package/dist/client-node.d.ts +8 -0
  48. package/dist/client-node.js +90 -0
  49. package/dist/client-node.js.map +1 -0
  50. package/dist/client-node.mjs +90 -0
  51. package/dist/client-node.mjs.map +1 -0
  52. package/dist/evaluation/index.d.mts +897 -0
  53. package/dist/evaluation/index.d.ts +897 -0
  54. package/dist/evaluation/index.js +13 -0
  55. package/dist/evaluation/index.js.map +1 -0
  56. package/dist/evaluation/index.mjs +13 -0
  57. package/dist/evaluation/index.mjs.map +1 -0
  58. package/dist/filterable-batch-span-processor-zO5kcjBY.d.mts +64 -0
  59. package/dist/filterable-batch-span-processor-zO5kcjBY.d.ts +64 -0
  60. package/dist/index.d.mts +45 -1027
  61. package/dist/index.d.ts +45 -1027
  62. package/dist/index.js +11 -27291
  63. package/dist/index.js.map +1 -1
  64. package/dist/index.mjs +23 -956
  65. package/dist/index.mjs.map +1 -1
  66. package/dist/observability/index.d.mts +260 -0
  67. package/dist/observability/index.d.ts +260 -0
  68. package/dist/observability/index.js +20 -0
  69. package/dist/observability/index.js.map +1 -0
  70. package/dist/observability/index.mjs +20 -0
  71. package/dist/observability/index.mjs.map +1 -0
  72. package/dist/observability/instrumentation/langchain/index.d.mts +40 -0
  73. package/dist/observability/instrumentation/langchain/index.d.ts +40 -0
  74. package/dist/observability/instrumentation/langchain/index.js +666 -0
  75. package/dist/observability/instrumentation/langchain/index.js.map +1 -0
  76. package/dist/observability/instrumentation/langchain/index.mjs +666 -0
  77. package/dist/observability/instrumentation/langchain/index.mjs.map +1 -0
  78. package/dist/prompt/index.d.mts +10 -0
  79. package/dist/prompt/index.d.ts +10 -0
  80. package/dist/prompt/index.js +18 -0
  81. package/dist/prompt/index.js.map +1 -0
  82. package/dist/prompt/index.mjs +18 -0
  83. package/dist/prompt/index.mjs.map +1 -0
  84. package/dist/prompt-BXJWdbQp.d.mts +1967 -0
  85. package/dist/prompt-BXJWdbQp.d.ts +1967 -0
  86. package/dist/record-evaluation-CmxMXa-3.d.mts +25 -0
  87. package/dist/record-evaluation-CmxMXa-3.d.ts +25 -0
  88. package/dist/trace-D-bZOuqb.d.mts +622 -0
  89. package/dist/trace-G2312klE.d.ts +622 -0
  90. package/package.json +86 -37
  91. package/.eslintrc.cjs +0 -37
  92. package/copy-types.sh +0 -17
  93. package/dist/chunk-LKD2K67J.mjs +0 -717
  94. package/dist/chunk-LKD2K67J.mjs.map +0 -1
  95. package/dist/utils-Cv-rUjJ1.d.mts +0 -313
  96. package/dist/utils-Cv-rUjJ1.d.ts +0 -313
  97. package/dist/utils.d.mts +0 -2
  98. package/dist/utils.d.ts +0 -2
  99. package/dist/utils.js +0 -709
  100. package/dist/utils.js.map +0 -1
  101. package/dist/utils.mjs +0 -11
  102. package/example/.env.example +0 -12
  103. package/example/.eslintrc.json +0 -26
  104. package/example/LICENSE +0 -13
  105. package/example/README.md +0 -12
  106. package/example/app/(chat)/chat/[id]/page.tsx +0 -60
  107. package/example/app/(chat)/layout.tsx +0 -14
  108. package/example/app/(chat)/page.tsx +0 -27
  109. package/example/app/actions.ts +0 -156
  110. package/example/app/globals.css +0 -76
  111. package/example/app/guardrails/page.tsx +0 -26
  112. package/example/app/langchain/page.tsx +0 -27
  113. package/example/app/langchain-rag/page.tsx +0 -28
  114. package/example/app/late-update/page.tsx +0 -27
  115. package/example/app/layout.tsx +0 -64
  116. package/example/app/login/actions.ts +0 -71
  117. package/example/app/login/page.tsx +0 -18
  118. package/example/app/manual/page.tsx +0 -27
  119. package/example/app/new/page.tsx +0 -5
  120. package/example/app/opengraph-image.png +0 -0
  121. package/example/app/share/[id]/page.tsx +0 -58
  122. package/example/app/signup/actions.ts +0 -111
  123. package/example/app/signup/page.tsx +0 -18
  124. package/example/app/twitter-image.png +0 -0
  125. package/example/auth.config.ts +0 -42
  126. package/example/auth.ts +0 -45
  127. package/example/components/button-scroll-to-bottom.tsx +0 -36
  128. package/example/components/chat-history.tsx +0 -49
  129. package/example/components/chat-list.tsx +0 -52
  130. package/example/components/chat-message-actions.tsx +0 -40
  131. package/example/components/chat-message.tsx +0 -80
  132. package/example/components/chat-panel.tsx +0 -139
  133. package/example/components/chat-share-dialog.tsx +0 -95
  134. package/example/components/chat.tsx +0 -84
  135. package/example/components/clear-history.tsx +0 -75
  136. package/example/components/empty-screen.tsx +0 -38
  137. package/example/components/external-link.tsx +0 -29
  138. package/example/components/footer.tsx +0 -19
  139. package/example/components/header.tsx +0 -114
  140. package/example/components/login-button.tsx +0 -42
  141. package/example/components/login-form.tsx +0 -97
  142. package/example/components/markdown.tsx +0 -9
  143. package/example/components/prompt-form.tsx +0 -115
  144. package/example/components/providers.tsx +0 -17
  145. package/example/components/sidebar-actions.tsx +0 -125
  146. package/example/components/sidebar-desktop.tsx +0 -19
  147. package/example/components/sidebar-footer.tsx +0 -16
  148. package/example/components/sidebar-item.tsx +0 -124
  149. package/example/components/sidebar-items.tsx +0 -42
  150. package/example/components/sidebar-list.tsx +0 -38
  151. package/example/components/sidebar-mobile.tsx +0 -31
  152. package/example/components/sidebar-toggle.tsx +0 -24
  153. package/example/components/sidebar.tsx +0 -21
  154. package/example/components/signup-form.tsx +0 -95
  155. package/example/components/stocks/events-skeleton.tsx +0 -31
  156. package/example/components/stocks/events.tsx +0 -30
  157. package/example/components/stocks/index.tsx +0 -36
  158. package/example/components/stocks/message.tsx +0 -134
  159. package/example/components/stocks/spinner.tsx +0 -16
  160. package/example/components/stocks/stock-purchase.tsx +0 -146
  161. package/example/components/stocks/stock-skeleton.tsx +0 -22
  162. package/example/components/stocks/stock.tsx +0 -210
  163. package/example/components/stocks/stocks-skeleton.tsx +0 -9
  164. package/example/components/stocks/stocks.tsx +0 -67
  165. package/example/components/tailwind-indicator.tsx +0 -14
  166. package/example/components/theme-toggle.tsx +0 -31
  167. package/example/components/ui/alert-dialog.tsx +0 -141
  168. package/example/components/ui/badge.tsx +0 -36
  169. package/example/components/ui/button.tsx +0 -57
  170. package/example/components/ui/codeblock.tsx +0 -148
  171. package/example/components/ui/dialog.tsx +0 -122
  172. package/example/components/ui/dropdown-menu.tsx +0 -205
  173. package/example/components/ui/icons.tsx +0 -507
  174. package/example/components/ui/input.tsx +0 -25
  175. package/example/components/ui/label.tsx +0 -26
  176. package/example/components/ui/select.tsx +0 -164
  177. package/example/components/ui/separator.tsx +0 -31
  178. package/example/components/ui/sheet.tsx +0 -140
  179. package/example/components/ui/sonner.tsx +0 -31
  180. package/example/components/ui/switch.tsx +0 -29
  181. package/example/components/ui/textarea.tsx +0 -24
  182. package/example/components/ui/tooltip.tsx +0 -30
  183. package/example/components/user-menu.tsx +0 -53
  184. package/example/components.json +0 -17
  185. package/example/instrumentation.ts +0 -11
  186. package/example/lib/chat/guardrails.tsx +0 -181
  187. package/example/lib/chat/langchain-rag.tsx +0 -191
  188. package/example/lib/chat/langchain.tsx +0 -112
  189. package/example/lib/chat/late-update.tsx +0 -208
  190. package/example/lib/chat/manual.tsx +0 -605
  191. package/example/lib/chat/vercel-ai.tsx +0 -576
  192. package/example/lib/hooks/use-copy-to-clipboard.tsx +0 -33
  193. package/example/lib/hooks/use-enter-submit.tsx +0 -23
  194. package/example/lib/hooks/use-local-storage.ts +0 -24
  195. package/example/lib/hooks/use-scroll-anchor.tsx +0 -86
  196. package/example/lib/hooks/use-sidebar.tsx +0 -60
  197. package/example/lib/hooks/use-streamable-text.ts +0 -25
  198. package/example/lib/types.ts +0 -41
  199. package/example/lib/utils.ts +0 -89
  200. package/example/middleware.ts +0 -8
  201. package/example/next-env.d.ts +0 -5
  202. package/example/next.config.js +0 -16
  203. package/example/package-lock.json +0 -10917
  204. package/example/package.json +0 -84
  205. package/example/pnpm-lock.yaml +0 -5712
  206. package/example/postcss.config.js +0 -6
  207. package/example/prettier.config.cjs +0 -34
  208. package/example/public/apple-touch-icon.png +0 -0
  209. package/example/public/favicon-16x16.png +0 -0
  210. package/example/public/favicon.ico +0 -0
  211. package/example/public/next.svg +0 -1
  212. package/example/public/thirteen.svg +0 -1
  213. package/example/public/vercel.svg +0 -1
  214. package/example/tailwind.config.ts +0 -81
  215. package/example/tsconfig.json +0 -35
  216. package/src/LangWatchExporter.ts +0 -96
  217. package/src/evaluations.ts +0 -219
  218. package/src/index.test.ts +0 -402
  219. package/src/index.ts +0 -596
  220. package/src/langchain.ts +0 -557
  221. package/src/server/types/.gitkeep +0 -0
  222. package/src/typeUtils.ts +0 -89
  223. package/src/types.ts +0 -82
  224. package/src/utils.ts +0 -205
  225. package/ts-to-zod.config.js +0 -24
  226. package/tsconfig.json +0 -32
  227. package/tsup.config.ts +0 -10
  228. package/vitest.config.ts +0 -8
  229. /package/dist/{utils.mjs.map → chunk-OM7VY3XT.mjs.map} +0 -0
package/src/index.ts DELETED
@@ -1,596 +0,0 @@
1
- import EventEmitter from "eventemitter3";
2
- import { nanoid } from "nanoid";
3
- import { ZodError } from "zod";
4
- import { fromZodError } from "zod-validation-error";
5
- import { version } from "../package.json";
6
- import {
7
- evaluate,
8
- type EvaluationParams,
9
- type EvaluationResultModel,
10
- } from "./evaluations";
11
- import { LangWatchCallbackHandler } from "./langchain";
12
- import {
13
- type CollectorRESTParams,
14
- type EvaluationResult,
15
- type Span as ServerSpan,
16
- type SpanTypes,
17
- type TypedValueEvaluationResult,
18
- } from "./server/types/tracer";
19
- import {
20
- collectorRESTParamsSchema,
21
- spanSchema,
22
- } from "./server/types/tracer.generated";
23
- import {
24
- type Trace,
25
- type BaseSpan,
26
- type ChatMessage,
27
- type ChatRichContent,
28
- type LLMSpan,
29
- type Metadata,
30
- type PendingBaseSpan,
31
- type PendingLLMSpan,
32
- type PendingRAGSpan,
33
- type RAGSpan,
34
- type RESTEvaluation,
35
- type SpanInputOutput,
36
- type LLMModeTrace,
37
- type ErrorCapture,
38
- } from "./types";
39
- import { camelToSnakeCaseNested, type Strict } from "./typeUtils";
40
- import {
41
- autoconvertTypedValues,
42
- captureError,
43
- convertFromVercelAIMessages,
44
- } from "./utils";
45
- import { LangWatchExporter } from "./LangWatchExporter";
46
-
47
- export type {
48
- Trace,
49
- BaseSpan,
50
- ChatMessage as ChatMessage,
51
- ChatRichContent,
52
- LLMSpan,
53
- Metadata,
54
- PendingBaseSpan,
55
- PendingLLMSpan,
56
- PendingRAGSpan,
57
- RAGSpan,
58
- SpanInputOutput,
59
- LLMModeTrace,
60
- ErrorCapture,
61
- };
62
-
63
- export {
64
- autoconvertTypedValues,
65
- captureError,
66
- convertFromVercelAIMessages,
67
- LangWatchExporter,
68
- };
69
-
70
- export class LangWatch extends EventEmitter {
71
- apiKey: string | undefined;
72
- endpoint: string;
73
-
74
- constructor({
75
- apiKey,
76
- endpoint = process.env.LANGWATCH_ENDPOINT ?? "https://app.langwatch.ai",
77
- }: {
78
- apiKey?: string;
79
- endpoint?: string;
80
- } = {}) {
81
- super();
82
- const apiKey_ = apiKey ?? process.env.LANGWATCH_API_KEY;
83
- if (!apiKey_) {
84
- const error = new Error(
85
- "LangWatch API key is not set, please set the LANGWATCH_API_KEY environment variable or pass it in the constructor. Traces will not be captured."
86
- );
87
- this.emit("error", error);
88
- }
89
- this.apiKey = apiKey_;
90
- this.endpoint = endpoint;
91
- }
92
-
93
- getTrace({
94
- traceId,
95
- metadata,
96
- }: { traceId?: string; metadata?: Metadata } = {}) {
97
- return new LangWatchTrace({
98
- client: this,
99
- traceId: traceId ?? `trace_${nanoid()}`,
100
- metadata,
101
- });
102
- }
103
-
104
- async sendTrace(params: CollectorRESTParams) {
105
- const backoff = [1000, 2000, 4000, 8000, 16000];
106
- for (const backoffTime of backoff) {
107
- try {
108
- await this._sendTrace(params);
109
- return;
110
- } catch (e) {
111
- console.warn(
112
- `[LangWatch] ⚠️ Failed to send trace, retrying in ${
113
- backoffTime / 1000
114
- }s`
115
- );
116
- await new Promise((resolve) => setTimeout(resolve, backoffTime));
117
- }
118
- }
119
- console.warn("[LangWatch] ⚠️ Failed to send trace, giving up");
120
- }
121
-
122
- async _sendTrace(params: CollectorRESTParams) {
123
- if (params.spans.length === 0) {
124
- return;
125
- }
126
-
127
- if (!this.apiKey) {
128
- const error = new Error(
129
- "LangWatch API key is not set, LLMs traces will not be sent, go to https://langwatch.ai to set it up"
130
- );
131
- this.emit("error", error);
132
- return;
133
- }
134
-
135
- const response = await fetch(`${this.endpoint}/api/collector`, {
136
- method: "POST",
137
- headers: {
138
- "X-Auth-Token": this.apiKey,
139
- "Content-Type": "application/json",
140
- },
141
- body: JSON.stringify(params),
142
- });
143
-
144
- if (response.status === 429) {
145
- const error = new Error(
146
- "Rate limit exceeded, dropping message from being sent to LangWatch. Please check your dashboard to upgrade your plan."
147
- );
148
- this.emit("error", error);
149
- return;
150
- }
151
- if (!response.ok) {
152
- const error = new Error(
153
- `Failed to send trace, status: ${response.status}`
154
- );
155
- this.emit("error", error);
156
- throw error;
157
- }
158
- }
159
- }
160
-
161
- type CurrentSpan = {
162
- current: LangWatchSpan;
163
- previous?: CurrentSpan;
164
- };
165
-
166
- type AddEvaluationParams = {
167
- evaluationId?: string;
168
- span?: LangWatchSpan;
169
- name: string;
170
- type?: string;
171
- isGuardrail?: boolean;
172
- status?: "processed" | "skipped" | "error";
173
- passed?: boolean;
174
- score?: number;
175
- label?: string;
176
- details?: string;
177
- error?: Error;
178
- timestamps?: RESTEvaluation["timestamps"];
179
- };
180
-
181
- export class LangWatchTrace {
182
- client: LangWatch;
183
- traceId: string;
184
- metadata?: Metadata;
185
- finishedSpans: Record<string, ServerSpan> = {};
186
- langchainCallback?: LangWatchCallbackHandler;
187
- evaluations: RESTEvaluation[] = [];
188
- private currentSpan?: CurrentSpan;
189
- private timeoutRef?: NodeJS.Timeout;
190
-
191
- constructor({
192
- client,
193
- traceId,
194
- metadata,
195
- }: {
196
- client: LangWatch;
197
- traceId: string;
198
- metadata?: Metadata;
199
- }) {
200
- this.client = client;
201
- this.traceId = traceId;
202
- this.metadata = {
203
- ...metadata,
204
- sdkVersion: version,
205
- sdkLanguage: "typescript",
206
- };
207
- }
208
-
209
- update({ metadata }: { metadata: Metadata }) {
210
- this.metadata = {
211
- ...this.metadata,
212
- ...metadata,
213
- ...(typeof metadata.labels !== "undefined"
214
- ? {
215
- labels: [
216
- ...(this.metadata?.labels ?? []),
217
- ...(metadata.labels ?? []),
218
- ],
219
- }
220
- : {}),
221
- };
222
- }
223
-
224
- setCurrentSpan(span: LangWatchSpan) {
225
- this.currentSpan = {
226
- current: span,
227
- previous: this.currentSpan,
228
- };
229
- }
230
-
231
- getCurrentSpan() {
232
- return this.currentSpan?.current;
233
- }
234
-
235
- resetCurrentSpan() {
236
- this.currentSpan = this.currentSpan?.previous;
237
- }
238
-
239
- startSpan(params: Omit<Partial<PendingBaseSpan>, "parentId">) {
240
- const span = new LangWatchSpan({
241
- trace: this,
242
- ...params,
243
- });
244
- this.setCurrentSpan(span);
245
- return span;
246
- }
247
-
248
- startLLMSpan(params: Omit<Partial<PendingLLMSpan>, "parentId">) {
249
- const span = new LangWatchLLMSpan({
250
- trace: this,
251
- ...params,
252
- });
253
- this.setCurrentSpan(span);
254
- return span;
255
- }
256
-
257
- startRAGSpan(params: Omit<Partial<PendingRAGSpan>, "parentId">) {
258
- const span = new LangWatchRAGSpan({
259
- trace: this,
260
- ...params,
261
- });
262
- this.setCurrentSpan(span);
263
- return span;
264
- }
265
-
266
- addEvaluation = ({
267
- evaluationId,
268
- span,
269
- name,
270
- type,
271
- isGuardrail,
272
- status = "processed",
273
- passed,
274
- score,
275
- label,
276
- details,
277
- error,
278
- timestamps,
279
- }: AddEvaluationParams): void => {
280
- const currentEvaluationIndex = this.evaluations.findIndex(
281
- (e) =>
282
- evaluationId && "evaluationId" in e && e.evaluationId === evaluationId
283
- );
284
-
285
- const currentEvaluation =
286
- currentEvaluationIndex !== -1
287
- ? this.evaluations[currentEvaluationIndex]
288
- : undefined;
289
-
290
- const evaluationResult: EvaluationResult = {
291
- status,
292
- ...(passed !== undefined && { passed }),
293
- ...(score !== undefined && { score }),
294
- ...(label !== undefined && { label }),
295
- ...(details !== undefined && { details }),
296
- };
297
-
298
- let span_ = span;
299
- if (!span_) {
300
- span_ = this.startSpan({
301
- type: "evaluation",
302
- });
303
- }
304
- if (span_.type !== "evaluation") {
305
- span_ = span_.startSpan({ type: "evaluation" });
306
- }
307
-
308
- span_.update({
309
- name,
310
- output: {
311
- type: "evaluation_result",
312
- value: evaluationResult,
313
- } as TypedValueEvaluationResult,
314
- error,
315
- timestamps: timestamps
316
- ? {
317
- startedAt: timestamps.startedAt ?? span_.timestamps.startedAt,
318
- finishedAt: timestamps.finishedAt ?? undefined,
319
- }
320
- : undefined,
321
- });
322
- span_.end();
323
-
324
- const evaluation: RESTEvaluation = {
325
- evaluationId: evaluationId ?? `eval_${nanoid()}`,
326
- spanId: span_.spanId,
327
- name,
328
- type,
329
- isGuardrail,
330
- status,
331
- passed,
332
- score,
333
- label,
334
- details,
335
- error: error ? captureError(error) : undefined,
336
- timestamps: timestamps ?? {
337
- startedAt: span_.timestamps.startedAt,
338
- finishedAt: span_.timestamps.finishedAt,
339
- },
340
- };
341
-
342
- if (currentEvaluation && currentEvaluationIndex !== -1) {
343
- this.evaluations[currentEvaluationIndex] = {
344
- ...currentEvaluation,
345
- ...evaluation,
346
- };
347
- } else {
348
- this.evaluations.push(evaluation);
349
- }
350
- };
351
-
352
- async evaluate(params: EvaluationParams): Promise<EvaluationResultModel> {
353
- return evaluate({
354
- trace: this,
355
- ...params,
356
- });
357
- }
358
-
359
- getLangChainCallback() {
360
- if (!this.langchainCallback) {
361
- this.langchainCallback = new LangWatchCallbackHandler({ trace: this });
362
- }
363
- return this.langchainCallback;
364
- }
365
-
366
- onEnd(span: ServerSpan) {
367
- this.finishedSpans[span.span_id] = span;
368
- this.resetCurrentSpan();
369
- this.delayedSendSpans();
370
- }
371
-
372
- delayedSendSpans() {
373
- clearTimeout(this.timeoutRef);
374
- this.timeoutRef = setTimeout(() => {
375
- void this.sendSpans();
376
- }, 1000);
377
- }
378
-
379
- async sendSpans() {
380
- clearTimeout(this.timeoutRef);
381
-
382
- let trace: CollectorRESTParams | undefined = undefined;
383
- try {
384
- trace = collectorRESTParamsSchema.parse({
385
- trace_id: this.traceId,
386
- metadata: camelToSnakeCaseNested(this.metadata, "metadata"),
387
- spans: Object.values(this.finishedSpans),
388
- evaluations: camelToSnakeCaseNested(this.evaluations),
389
- } as Strict<CollectorRESTParams>);
390
- } catch (error) {
391
- if (error instanceof ZodError) {
392
- console.warn("[LangWatch] ⚠️ Failed to parse trace");
393
- console.warn(fromZodError(error).message);
394
- }
395
- this.client.emit("error", error);
396
- }
397
-
398
- if (trace) {
399
- await this.client.sendTrace(trace);
400
- }
401
- }
402
- }
403
-
404
- export class LangWatchSpan implements PendingBaseSpan {
405
- trace: LangWatchTrace;
406
-
407
- spanId: string;
408
- parentId?: string | null;
409
- type: SpanTypes;
410
- name?: string | null;
411
- input?: PendingBaseSpan["input"];
412
- output?: PendingBaseSpan["output"];
413
- error?: PendingBaseSpan["error"];
414
- timestamps: PendingBaseSpan["timestamps"];
415
- metrics: PendingBaseSpan["metrics"];
416
-
417
- constructor({
418
- trace,
419
- spanId,
420
- parentId,
421
- type,
422
- name,
423
- input,
424
- output,
425
- error,
426
- timestamps,
427
- metrics,
428
- }: Partial<PendingBaseSpan> & { trace: LangWatchTrace }) {
429
- this.spanId = spanId ?? `span_${nanoid()}`;
430
- this.parentId = parentId;
431
- this.trace = trace;
432
- this.type = type ?? "span";
433
- this.name = name;
434
- this.input = input;
435
- this.output = output;
436
- this.error = error;
437
- this.timestamps = timestamps ?? {
438
- startedAt: Date.now(),
439
- };
440
- this.metrics = metrics;
441
- }
442
-
443
- update(params: Partial<Omit<PendingBaseSpan, "spanId" | "parentId">>) {
444
- if (Object.isFrozen(this)) {
445
- const error = new Error(
446
- `Tried to update span ${this.spanId}, but the span is already finished, discarding update`
447
- );
448
- this.trace.client.emit("error", error);
449
- return;
450
- }
451
-
452
- if (params.type) {
453
- this.type = params.type;
454
- }
455
- if ("name" in params) {
456
- this.name = params.name;
457
- }
458
- if ("input" in params) {
459
- this.input = params.input;
460
- }
461
- if ("output" in params) {
462
- this.output = params.output;
463
- }
464
- if ("error" in params) {
465
- this.error = params.error;
466
- }
467
- if (params.timestamps) {
468
- this.timestamps = params.timestamps;
469
- }
470
- if ("metrics" in params) {
471
- this.metrics = params.metrics;
472
- }
473
- }
474
-
475
- startSpan(params: Omit<Partial<PendingBaseSpan>, "parentId">) {
476
- const span = new LangWatchSpan({
477
- trace: this.trace,
478
- parentId: this.spanId,
479
- ...params,
480
- });
481
- this.trace.setCurrentSpan(span);
482
- return span;
483
- }
484
-
485
- startLLMSpan(params: Omit<Partial<PendingLLMSpan>, "parentId">) {
486
- const span = new LangWatchLLMSpan({
487
- trace: this.trace,
488
- parentId: this.spanId,
489
- ...params,
490
- });
491
- this.trace.setCurrentSpan(span);
492
- return span;
493
- }
494
-
495
- startRAGSpan(params: Omit<Partial<PendingRAGSpan>, "parentId">) {
496
- const span = new LangWatchRAGSpan({
497
- trace: this.trace,
498
- parentId: this.spanId,
499
- ...params,
500
- });
501
- this.trace.setCurrentSpan(span);
502
- return span;
503
- }
504
-
505
- addEvaluation(params: AddEvaluationParams) {
506
- this.trace.addEvaluation({
507
- ...params,
508
- span: this,
509
- });
510
- }
511
-
512
- async evaluate(params: EvaluationParams): Promise<EvaluationResultModel> {
513
- return evaluate({
514
- span: this,
515
- ...params,
516
- });
517
- }
518
-
519
- end(params?: Partial<Omit<PendingBaseSpan, "spanId" | "parentId">>) {
520
- this.timestamps.finishedAt = Date.now();
521
- if (params) {
522
- this.update(params);
523
- }
524
-
525
- try {
526
- const finalSpan = spanSchema.parse(
527
- camelToSnakeCaseNested({
528
- ...this,
529
- trace: undefined,
530
- traceId: this.trace.traceId,
531
- timestamps: {
532
- ...this.timestamps,
533
- finishedAt: this.timestamps.finishedAt,
534
- },
535
- ...(this.error && { error: captureError(this.error) }),
536
- }) as ServerSpan
537
- );
538
- this.trace.onEnd(finalSpan);
539
- } catch (error) {
540
- if (error instanceof ZodError) {
541
- console.warn("[LangWatch] ⚠️ Failed to parse span");
542
- console.warn(fromZodError(error).message);
543
- }
544
- this.trace.client.emit("error", error);
545
- }
546
- }
547
- }
548
-
549
- export class LangWatchLLMSpan extends LangWatchSpan implements PendingLLMSpan {
550
- type: "llm";
551
- model: PendingLLMSpan["model"];
552
- params: PendingLLMSpan["params"];
553
-
554
- constructor(params: Partial<PendingLLMSpan> & { trace: LangWatchTrace }) {
555
- super({ ...params });
556
- this.type = "llm";
557
- this.model = params.model ?? "unknown";
558
- this.params = params.params ?? {};
559
- }
560
-
561
- update(params: Partial<PendingLLMSpan>) {
562
- super.update(params);
563
- if (params.model) {
564
- this.model = params.model;
565
- }
566
- if (params.params) {
567
- this.params = params.params;
568
- }
569
- }
570
-
571
- end(params?: Partial<PendingLLMSpan>) {
572
- super.end(params);
573
- }
574
- }
575
-
576
- export class LangWatchRAGSpan extends LangWatchSpan implements PendingRAGSpan {
577
- type: "rag";
578
- contexts: PendingRAGSpan["contexts"];
579
-
580
- constructor(params: Partial<PendingRAGSpan> & { trace: LangWatchTrace }) {
581
- super({ ...params });
582
- this.type = "rag";
583
- this.contexts = params.contexts ?? [];
584
- }
585
-
586
- update(params: Partial<PendingRAGSpan>) {
587
- super.update(params);
588
- if (params.contexts) {
589
- this.contexts = params.contexts;
590
- }
591
- }
592
-
593
- end(params?: Partial<PendingRAGSpan>) {
594
- super.end(params);
595
- }
596
- }