langwatch 0.3.0-prerelease.1 → 0.3.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.
Files changed (184) hide show
  1. package/dist/chunk-4BZATFKJ.mjs +181 -0
  2. package/dist/chunk-4BZATFKJ.mjs.map +1 -0
  3. package/dist/chunk-76KNOWLS.js +39 -0
  4. package/dist/chunk-76KNOWLS.js.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-OM7VY3XT.mjs.map +1 -0
  19. package/dist/chunk-PCQVQ7SB.js +45 -0
  20. package/dist/chunk-PCQVQ7SB.js.map +1 -0
  21. package/dist/chunk-PMBEK6YE.mjs +424 -0
  22. package/dist/chunk-PMBEK6YE.mjs.map +1 -0
  23. package/dist/chunk-PR3JDWC3.mjs +50 -0
  24. package/dist/chunk-PR3JDWC3.mjs.map +1 -0
  25. package/dist/chunk-PTJ6AAI7.js +360 -0
  26. package/dist/chunk-PTJ6AAI7.js.map +1 -0
  27. package/dist/chunk-QEWDG5QE.mjs +45 -0
  28. package/dist/chunk-QEWDG5QE.mjs.map +1 -0
  29. package/dist/chunk-SVJ7SCGB.js +424 -0
  30. package/dist/chunk-SVJ7SCGB.js.map +1 -0
  31. package/dist/chunk-VJSOCNPA.js +181 -0
  32. package/dist/chunk-VJSOCNPA.js.map +1 -0
  33. package/dist/chunk-X62YT4WB.mjs +39 -0
  34. package/dist/chunk-X62YT4WB.mjs.map +1 -0
  35. package/dist/chunk-Z5J5UI5E.mjs +360 -0
  36. package/dist/chunk-Z5J5UI5E.mjs.map +1 -0
  37. package/dist/client-B2HqIKg6.d.ts +51 -0
  38. package/dist/client-XyCqclCi.d.mts +51 -0
  39. package/dist/client-browser.d.mts +8 -0
  40. package/dist/client-browser.d.ts +8 -0
  41. package/dist/client-browser.js +83 -0
  42. package/dist/client-browser.js.map +1 -0
  43. package/dist/client-browser.mjs +83 -0
  44. package/dist/client-browser.mjs.map +1 -0
  45. package/dist/client-node.d.mts +8 -0
  46. package/dist/client-node.d.ts +8 -0
  47. package/dist/client-node.js +90 -0
  48. package/dist/client-node.js.map +1 -0
  49. package/dist/client-node.mjs +90 -0
  50. package/dist/client-node.mjs.map +1 -0
  51. package/dist/evaluation/index.d.mts +897 -0
  52. package/dist/evaluation/index.d.ts +897 -0
  53. package/dist/evaluation/index.js +13 -0
  54. package/dist/evaluation/index.js.map +1 -0
  55. package/dist/evaluation/index.mjs +13 -0
  56. package/dist/evaluation/index.mjs.map +1 -0
  57. package/dist/filterable-batch-span-processor-zO5kcjBY.d.mts +64 -0
  58. package/dist/filterable-batch-span-processor-zO5kcjBY.d.ts +64 -0
  59. package/dist/index.d.mts +48 -0
  60. package/{src/observability/exporters/langwatch-exporter.ts → dist/index.d.ts} +13 -18
  61. package/dist/index.js +30 -0
  62. package/dist/index.js.map +1 -0
  63. package/dist/index.mjs +30 -0
  64. package/dist/index.mjs.map +1 -0
  65. package/dist/observability/index.d.mts +260 -0
  66. package/dist/observability/index.d.ts +260 -0
  67. package/dist/observability/index.js +20 -0
  68. package/dist/observability/index.js.map +1 -0
  69. package/dist/observability/index.mjs +20 -0
  70. package/dist/observability/index.mjs.map +1 -0
  71. package/dist/observability/instrumentation/langchain/index.d.mts +40 -0
  72. package/dist/observability/instrumentation/langchain/index.d.ts +40 -0
  73. package/dist/observability/instrumentation/langchain/index.js +666 -0
  74. package/dist/observability/instrumentation/langchain/index.js.map +1 -0
  75. package/dist/observability/instrumentation/langchain/index.mjs +666 -0
  76. package/dist/observability/instrumentation/langchain/index.mjs.map +1 -0
  77. package/dist/prompt/index.d.mts +10 -0
  78. package/dist/prompt/index.d.ts +10 -0
  79. package/dist/prompt/index.js +18 -0
  80. package/dist/prompt/index.js.map +1 -0
  81. package/dist/prompt/index.mjs +18 -0
  82. package/dist/prompt/index.mjs.map +1 -0
  83. package/dist/prompt-BXJWdbQp.d.mts +1967 -0
  84. package/dist/prompt-BXJWdbQp.d.ts +1967 -0
  85. package/dist/record-evaluation-CmxMXa-3.d.mts +25 -0
  86. package/dist/record-evaluation-CmxMXa-3.d.ts +25 -0
  87. package/dist/trace-D-bZOuqb.d.mts +622 -0
  88. package/dist/trace-G2312klE.d.ts +622 -0
  89. package/package.json +9 -4
  90. package/.editorconfig +0 -16
  91. package/.eslintrc.cjs +0 -37
  92. package/copy-types.sh +0 -28
  93. package/examples/langchain/.env.example +0 -2
  94. package/examples/langchain/README.md +0 -42
  95. package/examples/langchain/package-lock.json +0 -2930
  96. package/examples/langchain/package.json +0 -27
  97. package/examples/langchain/src/cli-markdown.d.ts +0 -137
  98. package/examples/langchain/src/index.ts +0 -109
  99. package/examples/langchain/tsconfig.json +0 -25
  100. package/examples/langgraph/.env.example +0 -2
  101. package/examples/langgraph/README.md +0 -42
  102. package/examples/langgraph/package-lock.json +0 -3031
  103. package/examples/langgraph/package.json +0 -28
  104. package/examples/langgraph/src/cli-markdown.d.ts +0 -137
  105. package/examples/langgraph/src/index.ts +0 -196
  106. package/examples/langgraph/tsconfig.json +0 -25
  107. package/examples/mastra/.env.example +0 -2
  108. package/examples/mastra/README.md +0 -57
  109. package/examples/mastra/package-lock.json +0 -5296
  110. package/examples/mastra/package.json +0 -32
  111. package/examples/mastra/src/cli-markdown.d.ts +0 -137
  112. package/examples/mastra/src/index.ts +0 -120
  113. package/examples/mastra/src/mastra/agents/weather-agent.ts +0 -30
  114. package/examples/mastra/src/mastra/index.ts +0 -21
  115. package/examples/mastra/src/mastra/tools/weather-tool.ts +0 -102
  116. package/examples/mastra/tsconfig.json +0 -25
  117. package/examples/vercel-ai/.env.example +0 -2
  118. package/examples/vercel-ai/README.md +0 -38
  119. package/examples/vercel-ai/package-lock.json +0 -2571
  120. package/examples/vercel-ai/package.json +0 -27
  121. package/examples/vercel-ai/src/cli-markdown.d.ts +0 -137
  122. package/examples/vercel-ai/src/index.ts +0 -110
  123. package/examples/vercel-ai/src/instrumentation.ts +0 -9
  124. package/examples/vercel-ai/tsconfig.json +0 -25
  125. package/src/__tests__/client-browser.test.ts +0 -92
  126. package/src/__tests__/client-node.test.ts +0 -76
  127. package/src/__tests__/client.test.ts +0 -71
  128. package/src/__tests__/integration/client-browser.test.ts +0 -46
  129. package/src/__tests__/integration/client-node.test.ts +0 -46
  130. package/src/client-browser.ts +0 -70
  131. package/src/client-node.ts +0 -82
  132. package/src/client-shared.ts +0 -72
  133. package/src/client.ts +0 -119
  134. package/src/evaluation/__tests__/record-evaluation.test.ts +0 -112
  135. package/src/evaluation/__tests__/run-evaluation.test.ts +0 -171
  136. package/src/evaluation/index.ts +0 -2
  137. package/src/evaluation/record-evaluation.ts +0 -101
  138. package/src/evaluation/run-evaluation.ts +0 -133
  139. package/src/evaluation/tracer.ts +0 -3
  140. package/src/evaluation/types.ts +0 -23
  141. package/src/index.ts +0 -13
  142. package/src/internal/api/__tests__/errors.test.ts +0 -98
  143. package/src/internal/api/client.ts +0 -30
  144. package/src/internal/api/errors.ts +0 -32
  145. package/src/internal/generated/openapi/.gitkeep +0 -0
  146. package/src/internal/generated/types/.gitkeep +0 -0
  147. package/src/observability/__tests__/integration/base.test.ts +0 -74
  148. package/src/observability/__tests__/integration/browser-setup-ordering.test.ts +0 -60
  149. package/src/observability/__tests__/integration/complex-nested-spans.test.ts +0 -29
  150. package/src/observability/__tests__/integration/error-handling.test.ts +0 -24
  151. package/src/observability/__tests__/integration/langwatch-disabled-otel.test.ts +0 -24
  152. package/src/observability/__tests__/integration/langwatch-first-then-vercel.test.ts +0 -24
  153. package/src/observability/__tests__/integration/multiple-setup-attempts.test.ts +0 -27
  154. package/src/observability/__tests__/integration/otel-ordering.test.ts +0 -27
  155. package/src/observability/__tests__/integration/vercel-configurations.test.ts +0 -20
  156. package/src/observability/__tests__/integration/vercel-first-then-langwatch.test.ts +0 -27
  157. package/src/observability/__tests__/span.test.ts +0 -214
  158. package/src/observability/__tests__/trace.test.ts +0 -180
  159. package/src/observability/exporters/index.ts +0 -1
  160. package/src/observability/index.ts +0 -4
  161. package/src/observability/instrumentation/langchain/__tests__/integration/langchain-chatbot.test.ts +0 -112
  162. package/src/observability/instrumentation/langchain/__tests__/langchain.test.ts +0 -284
  163. package/src/observability/instrumentation/langchain/index.ts +0 -624
  164. package/src/observability/processors/__tests__/filterable-batch-span-exporter.test.ts +0 -98
  165. package/src/observability/processors/filterable-batch-span-processor.ts +0 -99
  166. package/src/observability/processors/index.ts +0 -1
  167. package/src/observability/semconv/attributes.ts +0 -185
  168. package/src/observability/semconv/events.ts +0 -42
  169. package/src/observability/semconv/index.ts +0 -16
  170. package/src/observability/semconv/values.ts +0 -159
  171. package/src/observability/span.ts +0 -728
  172. package/src/observability/trace.ts +0 -301
  173. package/src/prompt/__tests__/prompt.test.ts +0 -139
  174. package/src/prompt/get-prompt-version.ts +0 -49
  175. package/src/prompt/get-prompt.ts +0 -44
  176. package/src/prompt/index.ts +0 -3
  177. package/src/prompt/prompt.ts +0 -133
  178. package/src/prompt/service.ts +0 -221
  179. package/src/prompt/tracer.ts +0 -3
  180. package/src/prompt/types.ts +0 -0
  181. package/ts-to-zod.config.js +0 -35
  182. package/tsconfig.json +0 -26
  183. package/tsup.config.ts +0 -20
  184. package/vitest.config.ts +0 -9
@@ -1,624 +0,0 @@
1
- import type { AgentAction, AgentFinish } from "@langchain/core/agents";
2
- import { BaseCallbackHandler } from "@langchain/core/callbacks/base";
3
- import { type DocumentInterface } from "@langchain/core/documents";
4
- import type { Serialized } from "@langchain/core/load/serializable";
5
- import {
6
- AIMessage,
7
- AIMessageChunk,
8
- FunctionMessage,
9
- FunctionMessageChunk,
10
- HumanMessage,
11
- HumanMessageChunk,
12
- SystemMessage,
13
- SystemMessageChunk,
14
- ToolMessage,
15
- ToolMessageChunk,
16
- mapChatMessagesToStoredMessages,
17
- type BaseMessage,
18
- type StoredMessage,
19
- } from "@langchain/core/messages";
20
- import type { ChatGeneration, LLMResult } from "@langchain/core/outputs";
21
- import type { ChainValues } from "@langchain/core/utils/types";
22
- import { getLangWatchTracer } from "../../trace";
23
- import type { LangWatchSpan } from "../../span";
24
- import { context, trace, SpanStatusCode, Attributes } from "@opentelemetry/api";
25
- import { chatMessageSchema } from "../../../internal/generated/types/tracer.generated";
26
- import {
27
- canAutomaticallyCaptureInput,
28
- canAutomaticallyCaptureOutput,
29
- } from "../../../client";
30
- import * as intSemconv from "../../semconv";
31
- import { z } from "zod";
32
-
33
- export class LangWatchCallbackHandler extends BaseCallbackHandler {
34
- name = "LangWatchCallbackHandler";
35
- tracer = getLangWatchTracer("langwatch.instrumentation.langchain");
36
- spans: Record<string, LangWatchSpan | undefined> = {};
37
-
38
- constructor() {
39
- super();
40
- }
41
-
42
- private getParentContext(parentRunId?: string): any {
43
- if (parentRunId && this.spans[parentRunId]) {
44
- return trace.setSpan(context.active(), this.spans[parentRunId]);
45
- }
46
-
47
- return context.active();
48
- }
49
-
50
- private getSpan(runId: string): LangWatchSpan | undefined {
51
- return this.spans[runId];
52
- }
53
-
54
- async handleLLMStart(
55
- llm: Serialized,
56
- prompts: string[],
57
- runId: string,
58
- parentRunId?: string | undefined,
59
- extraParams?: Record<string, unknown> | undefined,
60
- _tags?: string[] | undefined,
61
- metadata?: Record<string, unknown> | undefined,
62
- name?: string,
63
- ): Promise<void> {
64
- const parentContext = this.getParentContext(parentRunId);
65
- const span = this.tracer.startSpan(
66
- name ?? llm.id?.[llm.id.length - 1]?.toString() ?? "llm",
67
- {},
68
- parentContext,
69
- );
70
-
71
- span.setType("llm");
72
-
73
- if (canAutomaticallyCaptureInput()) {
74
- span.setInput(prompts);
75
- }
76
-
77
- if (_tags) {
78
- span.setAttribute(intSemconv.ATTR_LANGWATCH_LANGCHAIN_RUN_TAGS, _tags);
79
- }
80
- if (extraParams) {
81
- span.setAttributes(
82
- Object.fromEntries(
83
- Object.entries(extraParams).map(([key, value]) => [
84
- [`${intSemconv.ATTR_LANGWATCH_LANGCHAIN_RUN_EXTRA_PARAMS}.${key}`],
85
- wrapNonScalarValues(value),
86
- ]),
87
- ),
88
- );
89
- }
90
- if (metadata) {
91
- if (metadata.ls_model_name) {
92
- span.setRequestModel(metadata.ls_model_name as string);
93
- metadata.ls_model_name = void 0;
94
- }
95
-
96
- span.setAttributes(
97
- Object.fromEntries(
98
- Object.entries(metadata).map(([key, value]) => [
99
- [`${intSemconv.ATTR_LANGWATCH_LANGCHAIN_RUN_METADATA}.${key}`],
100
- wrapNonScalarValues(value),
101
- ]),
102
- ),
103
- );
104
- }
105
- this.spans[runId] = span;
106
- }
107
-
108
- async handleChatModelStart(
109
- llm: Serialized,
110
- messages: BaseMessage[][],
111
- runId: string,
112
- parentRunId?: string | undefined,
113
- extraParams?: Record<string, unknown> | undefined,
114
- _tags?: string[] | undefined,
115
- metadata?: Record<string, unknown> | undefined,
116
- name?: string,
117
- ): Promise<void> {
118
- const parentContext = this.getParentContext(parentRunId);
119
- const span = this.tracer.startSpan(
120
- name ?? llm.id?.[llm.id.length - 1]?.toString() ?? "chat_model",
121
- {},
122
- parentContext,
123
- );
124
-
125
- span.setType("llm");
126
-
127
- if (canAutomaticallyCaptureInput()) {
128
- span.setInput(messages.flatMap(convertFromLangChainMessages));
129
- }
130
-
131
- if (_tags) {
132
- span.setAttribute(intSemconv.ATTR_LANGWATCH_LANGCHAIN_RUN_TAGS, _tags);
133
- }
134
- if (extraParams) {
135
- span.setAttributes(
136
- Object.fromEntries(
137
- Object.entries(extraParams).map(([key, value]) => [
138
- [`${intSemconv.ATTR_LANGWATCH_LANGCHAIN_RUN_EXTRA_PARAMS}.${key}`],
139
- wrapNonScalarValues(value),
140
- ]),
141
- ),
142
- );
143
- }
144
- if (metadata) {
145
- if (metadata.ls_model_name) {
146
- span.setRequestModel(metadata.ls_model_name as string);
147
- metadata.ls_model_name = void 0;
148
- }
149
- span.setAttributes(
150
- Object.fromEntries(
151
- Object.entries(metadata).map(([key, value]) => [
152
- [`${intSemconv.ATTR_LANGWATCH_LANGCHAIN_RUN_METADATA}.${key}`],
153
- wrapNonScalarValues(value),
154
- ]),
155
- ),
156
- );
157
- }
158
-
159
- this.spans[runId] = span;
160
- }
161
-
162
- async handleLLMEnd(
163
- response: LLMResult,
164
- runId: string,
165
- _parentRunId?: string | undefined,
166
- ): Promise<void> {
167
- const span = this.getSpan(runId);
168
- if (!span) return;
169
- const outputs: unknown[] = [];
170
- for (const generation of response.generations) {
171
- for (const generation_ of generation) {
172
- if ("message" in generation_ && generation_.message) {
173
- outputs.push(
174
- convertFromLangChainMessages([
175
- (generation_ as ChatGeneration).message,
176
- ]),
177
- );
178
- } else if ("text" in generation_) {
179
- outputs.push(generation_.text);
180
- } else {
181
- outputs.push(JSON.stringify(generation_));
182
- }
183
- }
184
- }
185
- const output = outputs.length === 1 ? outputs[0] : outputs;
186
-
187
- if (canAutomaticallyCaptureOutput()) {
188
- span.setOutput(output);
189
- }
190
-
191
- addLangChainEvent(span, "handleLLMEnd", runId, _parentRunId);
192
- span.end();
193
- this.spans[runId] = void 0;
194
- }
195
-
196
- async handleLLMError(
197
- err: Error,
198
- runId: string,
199
- _parentRunId?: string | undefined,
200
- ): Promise<void> {
201
- const span = this.getSpan(runId);
202
- if (!span) return;
203
-
204
- addLangChainEvent(span, "handleLLMError", runId, _parentRunId);
205
-
206
- span.recordException(err);
207
- span.setStatus({ code: SpanStatusCode.ERROR, message: err.message });
208
- span.end();
209
- this.spans[runId] = void 0;
210
- }
211
-
212
- async handleChainStart(
213
- chain: Serialized,
214
- inputs: ChainValues,
215
- runId: string,
216
- parentRunId?: string | undefined,
217
- _tags?: string[] | undefined,
218
- _metadata?: Record<string, unknown> | undefined,
219
- _runType?: string,
220
- name?: string,
221
- ): Promise<void> {
222
- const parentContext = this.getParentContext(parentRunId);
223
- const span = this.tracer.startSpan(
224
- name ?? chain.id?.[chain.id.length - 1]?.toString() ?? "chain",
225
- {},
226
- parentContext,
227
- );
228
- span.setType("chain");
229
-
230
- if (canAutomaticallyCaptureInput()) {
231
- span.setInput(inputs);
232
- }
233
-
234
- if (_tags) {
235
- span.setAttribute(intSemconv.ATTR_LANGWATCH_LANGCHAIN_RUN_TAGS, _tags);
236
- }
237
- if (_metadata) {
238
- span.setAttributes(
239
- Object.fromEntries(
240
- Object.entries(_metadata).map(([key, value]) => [
241
- [`${intSemconv.ATTR_LANGWATCH_LANGCHAIN_RUN_METADATA}.${key}`],
242
- wrapNonScalarValues(value),
243
- ]),
244
- ),
245
- );
246
- }
247
- if (_runType) {
248
- span.setAttribute(intSemconv.ATTR_LANGWATCH_LANGCHAIN_RUN_TYPE, _runType);
249
- }
250
-
251
- this.spans[runId] = span;
252
- }
253
-
254
- async handleChainEnd(
255
- output: ChainValues,
256
- runId: string,
257
- _parentRunId?: string | undefined,
258
- ): Promise<void> {
259
- const span = this.getSpan(runId);
260
- if (!span) return;
261
-
262
- addLangChainEvent(span, "handleChainEnd", runId, _parentRunId);
263
- span.setOutput(output);
264
- span.end();
265
- this.spans[runId] = void 0;
266
- }
267
-
268
- async handleChainError(
269
- err: Error,
270
- runId: string,
271
- _parentRunId?: string | undefined,
272
- _tags?: string[] | undefined,
273
- _kwargs?: { inputs?: Record<string, unknown> | undefined } | undefined,
274
- ): Promise<void> {
275
- const span = this.getSpan(runId);
276
- if (!span) return;
277
-
278
- addLangChainEvent(span, "handleChainError", runId, _parentRunId);
279
- span.recordException(err);
280
- span.setStatus({ code: SpanStatusCode.ERROR, message: err.message });
281
- span.end();
282
-
283
- this.spans[runId] = void 0;
284
- }
285
-
286
- async handleToolStart(
287
- tool: Serialized,
288
- input: string,
289
- runId: string,
290
- parentRunId?: string | undefined,
291
- _tags?: string[] | undefined,
292
- _metadata?: Record<string, unknown> | undefined,
293
- name?: string,
294
- ): Promise<void> {
295
- const parentContext = this.getParentContext(parentRunId);
296
- const span = this.tracer.startSpan(
297
- name ?? tool.id?.[tool.id.length - 1]?.toString() ?? "tool",
298
- {},
299
- parentContext,
300
- );
301
- span.setType("tool");
302
-
303
- if (canAutomaticallyCaptureInput()) {
304
- span.setInputString(input);
305
- }
306
-
307
- span.setAttributes({
308
- [intSemconv.ATTR_LANGWATCH_LANGCHAIN_RUN_ID]: runId,
309
- [intSemconv.ATTR_LANGWATCH_LANGCHAIN_RUN_PARENT_ID]: parentRunId,
310
- });
311
-
312
- if (_tags) {
313
- span.setAttribute(intSemconv.ATTR_LANGWATCH_LANGCHAIN_RUN_TAGS, _tags);
314
- }
315
- if (_metadata) {
316
- span.setAttributes(
317
- Object.fromEntries(
318
- Object.entries(_metadata).map(([key, value]) => [
319
- [`${intSemconv.ATTR_LANGWATCH_LANGCHAIN_RUN_METADATA}.${key}`],
320
- wrapNonScalarValues(value),
321
- ]),
322
- ),
323
- );
324
- }
325
- this.spans[runId] = span;
326
- }
327
-
328
- async handleToolEnd(
329
- output: string,
330
- runId: string,
331
- _parentRunId?: string | undefined,
332
- ): Promise<void> {
333
- const span = this.getSpan(runId);
334
- if (!span) return;
335
- if (canAutomaticallyCaptureOutput()) {
336
- span.setOutputString(output);
337
- }
338
-
339
- addLangChainEvent(span, "handleToolEnd", runId, _parentRunId);
340
-
341
- span.end();
342
- this.spans[runId] = void 0;
343
- }
344
-
345
- async handleToolError(
346
- err: Error,
347
- runId: string,
348
- _parentRunId?: string | undefined,
349
- _tags?: string[] | undefined,
350
- ): Promise<void> {
351
- const span = this.getSpan(runId);
352
- if (!span) return;
353
-
354
- addLangChainEvent(span, "handleToolError", runId, _parentRunId, _tags);
355
-
356
- span.recordException(err);
357
- span.setStatus({ code: SpanStatusCode.ERROR, message: err.message });
358
- span.end();
359
- this.spans[runId] = void 0;
360
- }
361
-
362
- async handleRetrieverStart(
363
- retriever: Serialized,
364
- query: string,
365
- runId: string,
366
- parentRunId?: string | undefined,
367
- _tags?: string[] | undefined,
368
- _metadata?: Record<string, unknown> | undefined,
369
- name?: string | undefined,
370
- ) {
371
- const parentContext = this.getParentContext(parentRunId);
372
- const span = this.tracer.startSpan(
373
- name ??
374
- retriever.id?.[retriever.id.length - 1]?.toString() ??
375
- "retriever",
376
- {},
377
- parentContext,
378
- );
379
- span.setType("rag");
380
-
381
- if (canAutomaticallyCaptureInput()) {
382
- span.setInputString(query);
383
- }
384
- if (_tags) {
385
- span.setAttribute(intSemconv.ATTR_LANGWATCH_LANGCHAIN_RUN_TAGS, _tags);
386
- }
387
- if (_metadata) {
388
- span.setAttributes(
389
- Object.fromEntries(
390
- Object.entries(_metadata).map(([key, value]) => [
391
- [`${intSemconv.ATTR_LANGWATCH_LANGCHAIN_RUN_METADATA}.${key}`],
392
- wrapNonScalarValues(value),
393
- ]),
394
- ),
395
- );
396
- }
397
-
398
- span.setAttributes({
399
- [intSemconv.ATTR_LANGWATCH_LANGCHAIN_RUN_ID]: runId,
400
- [intSemconv.ATTR_LANGWATCH_LANGCHAIN_RUN_PARENT_ID]: parentRunId,
401
- });
402
-
403
- this.spans[runId] = span;
404
- }
405
-
406
- async handleRetrieverEnd(
407
- documents: DocumentInterface<Record<string, any>>[],
408
- runId: string,
409
- _parentRunId?: string | undefined,
410
- _tags?: string[] | undefined,
411
- ) {
412
- const span = this.getSpan(runId);
413
- if (!span) return;
414
- if (canAutomaticallyCaptureOutput()) {
415
- span.setOutput(documents);
416
- }
417
-
418
- addLangChainEvent(span, "handleRetrieverEnd", runId, _parentRunId, _tags);
419
-
420
- span.setRAGContexts(
421
- documents.map((document) => ({
422
- document_id: document.metadata.id,
423
- chunk_id: document.metadata.chunk_id,
424
- content: canAutomaticallyCaptureInput() ? document.pageContent : "",
425
- })),
426
- );
427
-
428
- span.end();
429
- this.spans[runId] = void 0;
430
- }
431
-
432
- async handleRetrieverError(
433
- err: Error,
434
- runId: string,
435
- _parentRunId?: string | undefined,
436
- _tags?: string[] | undefined,
437
- ) {
438
- const span = this.getSpan(runId);
439
- if (!span) return;
440
-
441
- addLangChainEvent(span, "handleRetrieverError", runId, _parentRunId, _tags);
442
-
443
- span.recordException(err);
444
- span.setStatus({ code: SpanStatusCode.ERROR, message: err.message });
445
- span.end();
446
- this.spans[runId] = void 0;
447
- }
448
-
449
- async handleAgentAction(
450
- _action: AgentAction,
451
- runId: string,
452
- _parentRunId?: string | undefined,
453
- _tags?: string[] | undefined,
454
- ): Promise<void> {
455
- const span = this.getSpan(runId);
456
- if (!span) return;
457
-
458
- addLangChainEvent(span, "handleAgentAction", runId, _parentRunId, _tags);
459
- span.setType("agent");
460
- }
461
-
462
- async handleAgentEnd(
463
- action: AgentFinish,
464
- runId: string,
465
- _parentRunId?: string | undefined,
466
- _tags?: string[] | undefined,
467
- ): Promise<void> {
468
- const span = this.getSpan(runId);
469
- if (!span) return;
470
-
471
- addLangChainEvent(span, "handleAgentEnd", runId, _parentRunId, _tags);
472
-
473
- if (canAutomaticallyCaptureOutput()) {
474
- span.setOutput(action.returnValues);
475
- }
476
-
477
- span.end();
478
- this.spans[runId] = void 0;
479
- }
480
- }
481
-
482
- export const convertFromLangChainMessages = (
483
- messages: BaseMessage[],
484
- ): any[] => {
485
- const chatMessages: any[] = [];
486
- for (const message of messages) {
487
- chatMessages.push(
488
- convertFromLangChainMessage(message as BaseMessage & { id?: string[] }),
489
- );
490
- }
491
- return chatMessages;
492
- };
493
-
494
- const convertFromLangChainMessage = (
495
- message: BaseMessage & { id?: string[] },
496
- ): any => {
497
- let role: string = "user";
498
- const message_: (BaseMessage | StoredMessage) & {
499
- id?: string[];
500
- type?: string;
501
- } = message.lc_serializable
502
- ? mapChatMessagesToStoredMessages([message])[0]!
503
- : message;
504
- if (
505
- message_ instanceof HumanMessage ||
506
- message_ instanceof HumanMessageChunk ||
507
- message_.id?.[message_.id.length - 1] === "HumanMessage" ||
508
- message_.id?.[message_.id.length - 1] === "HumanMessageChunk" ||
509
- message_.type === "human"
510
- ) {
511
- role = "user";
512
- } else if (
513
- message instanceof AIMessage ||
514
- message instanceof AIMessageChunk ||
515
- message.id?.[message.id.length - 1] === "AIMessage" ||
516
- message.id?.[message.id.length - 1] === "AIMessageChunk" ||
517
- message_.type === "ai"
518
- ) {
519
- role = "assistant";
520
- } else if (
521
- message instanceof SystemMessage ||
522
- message instanceof SystemMessageChunk ||
523
- message.id?.[message.id.length - 1] === "SystemMessage" ||
524
- message.id?.[message.id.length - 1] === "SystemMessageChunk" ||
525
- message_.type === "system"
526
- ) {
527
- role = "system";
528
- } else if (
529
- message instanceof FunctionMessage ||
530
- message instanceof FunctionMessageChunk ||
531
- message.id?.[message.id.length - 1] === "FunctionMessage" ||
532
- message.id?.[message.id.length - 1] === "FunctionMessageChunk" ||
533
- message_.type === "function"
534
- ) {
535
- role = "function";
536
- } else if (
537
- message instanceof ToolMessage ||
538
- message instanceof ToolMessageChunk ||
539
- message.id?.[message.id.length - 1] === "ToolMessage" ||
540
- message.id?.[message.id.length - 1] === "ToolMessageChunk" ||
541
- message_.type === "tool"
542
- ) {
543
- role = "tool";
544
- }
545
- const content =
546
- typeof message.content === "string"
547
- ? message.content
548
- : message.content.map((content: any) =>
549
- content.type === "text"
550
- ? { type: "text", text: content.text }
551
- : content.type == "image_url"
552
- ? { type: "image_url", image_url: content.image_url }
553
- : { type: "text", text: JSON.stringify(content) },
554
- );
555
- const functionCall = message.additional_kwargs as any;
556
- return {
557
- role,
558
- content,
559
- ...(functionCall &&
560
- typeof functionCall === "object" &&
561
- Object.keys(functionCall).length > 0
562
- ? { function_call: functionCall }
563
- : {}),
564
- };
565
- };
566
-
567
- function wrapNonScalarValues(value: unknown): string | number | boolean | undefined {
568
- if (value === void 0) {
569
- return void 0;
570
- }
571
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
572
- return value;
573
- }
574
-
575
- const chatMessages = z.array(chatMessageSchema).safeParse(value);
576
- if (Array.isArray(value) && chatMessages.success) {
577
- return JSON.stringify({
578
- type: "chat_messages",
579
- value: chatMessages.data,
580
- });
581
- }
582
-
583
- try {
584
- JSON.stringify(value);
585
-
586
- return JSON.stringify({
587
- type: "json",
588
- value: value as object,
589
- });
590
- } catch (e) {
591
- return JSON.stringify({
592
- type: "raw",
593
- value: value as any,
594
- });
595
- }
596
- }
597
-
598
- function addLangChainEvent(
599
- span: LangWatchSpan,
600
- eventName: string,
601
- runId: string,
602
- parentRunId: string | undefined,
603
- tags?: string[] | undefined,
604
- metadata?: Record<string, unknown> | undefined,
605
- attributes?: Attributes,
606
- ) {
607
- const attrs: Attributes = {
608
- [intSemconv.ATTR_LANGWATCH_LANGCHAIN_RUN_ID]: runId,
609
- [intSemconv.ATTR_LANGWATCH_LANGCHAIN_RUN_PARENT_ID]: parentRunId,
610
- [intSemconv.ATTR_LANGWATCH_LANGCHAIN_EVENT_NAME]: eventName,
611
- ...attributes,
612
- };
613
-
614
- if (tags) {
615
- attrs[intSemconv.ATTR_LANGWATCH_LANGCHAIN_TAGS] = tags;
616
- }
617
- if (metadata) {
618
- Object.entries(metadata).forEach(([key, value]) => {
619
- attrs[key] = wrapNonScalarValues(value);
620
- });
621
- }
622
-
623
- span.addEvent(intSemconv.EVNT_LANGWATCH_LANGCHAIN_CALLBACK, attrs);
624
- }
@@ -1,98 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
- import { FilterableBatchSpanProcessor, SpanProcessingExcludeRule } from '../filterable-batch-span-processor';
3
- import type { ReadableSpan, SpanExporter } from '@opentelemetry/sdk-trace-base';
4
-
5
- function makeSpan({ name, instrumentationScopeName }: { name: string; instrumentationScopeName: string }): ReadableSpan {
6
- return {
7
- name,
8
- instrumentationScope: { name: instrumentationScopeName },
9
- } as any;
10
- }
11
-
12
- describe('FilterableBatchSpanProcessor', () => {
13
- let exporter: SpanExporter;
14
- let onEndSpy: ReturnType<typeof vi.fn>;
15
-
16
- beforeEach(() => {
17
- onEndSpy = vi.fn();
18
- exporter = { export: vi.fn(), shutdown: vi.fn() } as any;
19
- // Patch BatchSpanProcessor's onEnd to spy on calls
20
- (FilterableBatchSpanProcessor.prototype as any).__proto__.onEnd = onEndSpy;
21
- });
22
-
23
- afterEach(() => {
24
- vi.restoreAllMocks();
25
- });
26
-
27
- it('should export span if no filters match', () => {
28
- const filters: SpanProcessingExcludeRule[] = [
29
- { fieldName: 'span_name', matchValue: 'foo', matchOperation: 'exact_match' },
30
- ];
31
- const processor = new FilterableBatchSpanProcessor(exporter, filters);
32
- const span = makeSpan({ name: 'bar', instrumentationScopeName: 'scope' });
33
- processor.onEnd(span);
34
- expect(onEndSpy).toHaveBeenCalledWith(span);
35
- });
36
-
37
- it('should not export span if span_name exact_match filter matches', () => {
38
- const filters: SpanProcessingExcludeRule[] = [
39
- { fieldName: 'span_name', matchValue: 'heartbeat', matchOperation: 'exact_match' },
40
- ];
41
- const processor = new FilterableBatchSpanProcessor(exporter, filters);
42
- const span = makeSpan({ name: 'heartbeat', instrumentationScopeName: 'scope' });
43
- processor.onEnd(span);
44
- expect(onEndSpy).not.toHaveBeenCalled();
45
- });
46
-
47
- it('should not export span if instrumentation_scope_name starts_with filter matches', () => {
48
- const filters: SpanProcessingExcludeRule[] = [
49
- { fieldName: 'instrumentation_scope_name', matchValue: 'internal', matchOperation: 'starts_with' },
50
- ];
51
- const processor = new FilterableBatchSpanProcessor(exporter, filters);
52
- const span = makeSpan({ name: 'foo', instrumentationScopeName: 'internal-logger' });
53
- processor.onEnd(span);
54
- expect(onEndSpy).not.toHaveBeenCalled();
55
- });
56
-
57
- it('should not export span if span_name includes filter matches', () => {
58
- const filters: SpanProcessingExcludeRule[] = [
59
- { fieldName: 'span_name', matchValue: 'api', matchOperation: 'includes' },
60
- ];
61
- const processor = new FilterableBatchSpanProcessor(exporter, filters);
62
- const span = makeSpan({ name: 'call-api-endpoint', instrumentationScopeName: 'scope' });
63
- processor.onEnd(span);
64
- expect(onEndSpy).not.toHaveBeenCalled();
65
- });
66
-
67
- it('should not export span if span_name ends_with filter matches', () => {
68
- const filters: SpanProcessingExcludeRule[] = [
69
- { fieldName: 'span_name', matchValue: 'end', matchOperation: 'ends_with' },
70
- ];
71
- const processor = new FilterableBatchSpanProcessor(exporter, filters);
72
- const span = makeSpan({ name: 'process-end', instrumentationScopeName: 'scope' });
73
- processor.onEnd(span);
74
- expect(onEndSpy).not.toHaveBeenCalled();
75
- });
76
-
77
- it('should export span if multiple filters and none match', () => {
78
- const filters: SpanProcessingExcludeRule[] = [
79
- { fieldName: 'span_name', matchValue: 'foo', matchOperation: 'exact_match' },
80
- { fieldName: 'instrumentation_scope_name', matchValue: 'bar', matchOperation: 'includes' },
81
- ];
82
- const processor = new FilterableBatchSpanProcessor(exporter, filters);
83
- const span = makeSpan({ name: 'baz', instrumentationScopeName: 'scope' });
84
- processor.onEnd(span);
85
- expect(onEndSpy).toHaveBeenCalledWith(span);
86
- });
87
-
88
- it('should not export span if any filter matches (OR logic)', () => {
89
- const filters: SpanProcessingExcludeRule[] = [
90
- { fieldName: 'span_name', matchValue: 'baz', matchOperation: 'exact_match' },
91
- { fieldName: 'instrumentation_scope_name', matchValue: 'scope', matchOperation: 'exact_match' },
92
- ];
93
- const processor = new FilterableBatchSpanProcessor(exporter, filters);
94
- const span = makeSpan({ name: 'baz', instrumentationScopeName: 'scope' });
95
- processor.onEnd(span);
96
- expect(onEndSpy).not.toHaveBeenCalled();
97
- });
98
- });