raindrop-ai 0.0.73 → 0.0.74-otelv2

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.
@@ -0,0 +1,424 @@
1
+ // src/tracing/tracer-core.ts
2
+ import { context, trace as trace2 } from "@opentelemetry/api";
3
+ import { AnthropicInstrumentation } from "@traceloop/instrumentation-anthropic";
4
+ import { BedrockInstrumentation } from "@traceloop/instrumentation-bedrock";
5
+ import { ChromaDBInstrumentation } from "@traceloop/instrumentation-chromadb";
6
+ import { CohereInstrumentation } from "@traceloop/instrumentation-cohere";
7
+ import { OpenAIInstrumentation } from "@traceloop/instrumentation-openai";
8
+ import { PineconeInstrumentation } from "@traceloop/instrumentation-pinecone";
9
+ import { QdrantInstrumentation } from "@traceloop/instrumentation-qdrant";
10
+ import { TogetherInstrumentation } from "@traceloop/instrumentation-together";
11
+ import {
12
+ AIPlatformInstrumentation,
13
+ VertexAIInstrumentation
14
+ } from "@traceloop/instrumentation-vertexai";
15
+ import * as traceloop3 from "@traceloop/node-server-sdk";
16
+ import { WeakValueMap } from "weakref";
17
+
18
+ // src/tracing/liveInteraction.ts
19
+ import { trace } from "@opentelemetry/api";
20
+ import * as traceloop from "@traceloop/node-server-sdk";
21
+ function getPropertiesFromContext(context2) {
22
+ const properties = {
23
+ ...context2.userId && { user_id: context2.userId },
24
+ ...context2.convoId && { convo_id: context2.convoId },
25
+ ...context2.eventId && { event_id: context2.eventId },
26
+ ...context2.properties || {}
27
+ };
28
+ if (context2.attachments && context2.attachments.length > 0) {
29
+ properties.attachments = JSON.stringify(context2.attachments);
30
+ }
31
+ return properties;
32
+ }
33
+ var LiveInteraction = class {
34
+ constructor(context2, traceId, analytics) {
35
+ this.context = context2;
36
+ this.analytics = analytics;
37
+ this.tracer = trace.getTracer("traceloop.tracer");
38
+ this.traceId = traceId;
39
+ }
40
+ async withSpan(params, fn, thisArg, ...args) {
41
+ var _a;
42
+ const taskName = typeof params === "string" ? params : params.name;
43
+ const properties = typeof params === "string" ? {
44
+ ...getPropertiesFromContext(this.context)
45
+ } : {
46
+ ...getPropertiesFromContext(this.context),
47
+ ...params.properties || {}
48
+ };
49
+ const inputParameters = typeof params === "string" ? void 0 : params.inputParameters;
50
+ if ((_a = this.analytics) == null ? void 0 : _a.debugLogs) {
51
+ console.log("[raindrop] using withSpan in liveInteraction");
52
+ }
53
+ return traceloop.withTask(
54
+ {
55
+ name: taskName,
56
+ associationProperties: properties,
57
+ inputParameters,
58
+ traceContent: params.traceContent,
59
+ suppressTracing: params.suppressTracing
60
+ },
61
+ fn,
62
+ thisArg,
63
+ ...args
64
+ );
65
+ }
66
+ async withTool(params, fn, thisArg, ...args) {
67
+ var _a;
68
+ const toolName = params.name;
69
+ const properties = {
70
+ ...getPropertiesFromContext(this.context),
71
+ ...params.properties || {}
72
+ };
73
+ const inputParams = params.inputParameters ? [params.inputParameters] : void 0;
74
+ if ((_a = this.analytics) == null ? void 0 : _a.debugLogs) {
75
+ console.log("[raindrop] using withTool in liveInteraction");
76
+ }
77
+ return traceloop.withTool(
78
+ {
79
+ name: toolName,
80
+ associationProperties: properties,
81
+ inputParameters: inputParams,
82
+ version: params.version,
83
+ traceContent: params.traceContent,
84
+ suppressTracing: params.suppressTracing
85
+ },
86
+ fn,
87
+ thisArg,
88
+ ...args
89
+ );
90
+ }
91
+ startSpan(params) {
92
+ const { name, properties = {} } = params;
93
+ const span = this.tracer.startSpan(name);
94
+ span.setAttributes(getPropertiesFromContext(this.context));
95
+ span.setAttribute("traceloop.span.kind", "task");
96
+ Object.entries(properties).forEach(([key, value]) => {
97
+ span.setAttribute("traceloop.association.properties." + key, String(value));
98
+ });
99
+ return span;
100
+ }
101
+ setProperties(properties) {
102
+ var _a;
103
+ this.context.properties = { ...this.context.properties, ...properties };
104
+ (_a = this.analytics) == null ? void 0 : _a._trackAiPartial({
105
+ eventId: this.context.eventId,
106
+ properties
107
+ });
108
+ }
109
+ setProperty(key, value) {
110
+ var _a;
111
+ this.context.properties = { ...this.context.properties, [key]: value };
112
+ (_a = this.analytics) == null ? void 0 : _a._trackAiPartial({
113
+ eventId: this.context.eventId,
114
+ properties: { [key]: value }
115
+ });
116
+ }
117
+ addAttachments(attachments) {
118
+ var _a;
119
+ if (!this.context.attachments) {
120
+ this.context.attachments = [];
121
+ }
122
+ this.context.attachments.push(...attachments);
123
+ (_a = this.analytics) == null ? void 0 : _a._trackAiPartial({
124
+ eventId: this.context.eventId,
125
+ attachments
126
+ });
127
+ }
128
+ setInput(input) {
129
+ var _a;
130
+ this.context.input = input;
131
+ (_a = this.analytics) == null ? void 0 : _a._trackAiPartial({
132
+ eventId: this.context.eventId,
133
+ input
134
+ });
135
+ }
136
+ finish(resultEvent) {
137
+ var _a;
138
+ if (this.traceId) {
139
+ this.setProperty("trace_id", this.traceId);
140
+ }
141
+ (_a = this.analytics) == null ? void 0 : _a._trackAiPartial({
142
+ ...resultEvent,
143
+ eventId: resultEvent.eventId || this.context.eventId,
144
+ isPending: false
145
+ });
146
+ }
147
+ };
148
+
149
+ // src/tracing/liveTracer.ts
150
+ import * as traceloop2 from "@traceloop/node-server-sdk";
151
+ var LiveTracer = class {
152
+ constructor(globalProperties) {
153
+ this.globalProperties = globalProperties || {};
154
+ }
155
+ async withSpan(params, fn, thisArg, ...args) {
156
+ const taskName = typeof params === "string" ? params : params.name;
157
+ const properties = typeof params === "string" ? {
158
+ ...this.globalProperties
159
+ } : {
160
+ ...this.globalProperties,
161
+ ...params.properties || {}
162
+ };
163
+ const inputParameters = typeof params === "string" ? void 0 : params.inputParameters;
164
+ return traceloop2.withTask(
165
+ {
166
+ name: taskName,
167
+ associationProperties: properties,
168
+ inputParameters,
169
+ traceContent: params.traceContent,
170
+ suppressTracing: params.suppressTracing
171
+ },
172
+ fn,
173
+ thisArg,
174
+ ...args
175
+ );
176
+ }
177
+ };
178
+
179
+ // src/tracing/tracer-core.ts
180
+ function createDefaultInstrumentations() {
181
+ return [
182
+ new OpenAIInstrumentation(),
183
+ new AnthropicInstrumentation(),
184
+ new CohereInstrumentation(),
185
+ new BedrockInstrumentation(),
186
+ new VertexAIInstrumentation(),
187
+ new AIPlatformInstrumentation(),
188
+ new PineconeInstrumentation(),
189
+ new TogetherInstrumentation(),
190
+ new ChromaDBInstrumentation(),
191
+ new QdrantInstrumentation()
192
+ ];
193
+ }
194
+ function createManualInstrumentations(instrumentModules) {
195
+ const instrumentations = [];
196
+ if (instrumentModules.openAI) {
197
+ const inst = new OpenAIInstrumentation();
198
+ inst.manuallyInstrument(instrumentModules.openAI);
199
+ instrumentations.push(inst);
200
+ }
201
+ if (instrumentModules.anthropic) {
202
+ const inst = new AnthropicInstrumentation();
203
+ inst.manuallyInstrument(instrumentModules.anthropic);
204
+ instrumentations.push(inst);
205
+ }
206
+ if (instrumentModules.cohere) {
207
+ const inst = new CohereInstrumentation();
208
+ inst.manuallyInstrument(instrumentModules.cohere);
209
+ instrumentations.push(inst);
210
+ }
211
+ if (instrumentModules.bedrock) {
212
+ const inst = new BedrockInstrumentation();
213
+ inst.manuallyInstrument(instrumentModules.bedrock);
214
+ instrumentations.push(inst);
215
+ }
216
+ if (instrumentModules.google_vertexai) {
217
+ const inst = new VertexAIInstrumentation();
218
+ inst.manuallyInstrument(instrumentModules.google_vertexai);
219
+ instrumentations.push(inst);
220
+ }
221
+ if (instrumentModules.google_aiplatform) {
222
+ const inst = new AIPlatformInstrumentation();
223
+ inst.manuallyInstrument(instrumentModules.google_aiplatform);
224
+ instrumentations.push(inst);
225
+ }
226
+ if (instrumentModules.pinecone) {
227
+ const inst = new PineconeInstrumentation();
228
+ inst.manuallyInstrument(instrumentModules.pinecone);
229
+ instrumentations.push(inst);
230
+ }
231
+ if (instrumentModules.together) {
232
+ const inst = new TogetherInstrumentation();
233
+ inst.manuallyInstrument(instrumentModules.together);
234
+ instrumentations.push(inst);
235
+ }
236
+ if (instrumentModules.chromadb) {
237
+ const inst = new ChromaDBInstrumentation();
238
+ inst.manuallyInstrument(instrumentModules.chromadb);
239
+ instrumentations.push(inst);
240
+ }
241
+ if (instrumentModules.qdrant) {
242
+ const inst = new QdrantInstrumentation();
243
+ inst.manuallyInstrument(instrumentModules.qdrant);
244
+ instrumentations.push(inst);
245
+ }
246
+ return instrumentations;
247
+ }
248
+ var activeInteractions = new WeakValueMap();
249
+ var activeInteractionsByEventId = new WeakValueMap();
250
+ function getCurrentTraceId() {
251
+ var _a;
252
+ return (_a = trace2.getSpan(context.active())) == null ? void 0 : _a.spanContext().traceId;
253
+ }
254
+ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
255
+ const { logLevel, useExternalOtel, tracingEnabled, ...otherOptions } = options;
256
+ if (isDebug) {
257
+ const mode = useExternalOtel ? "(external OTEL mode)" : tracingEnabled === false ? "(tracing disabled)" : "";
258
+ console.log("[raindrop] Initializing tracing", mode);
259
+ }
260
+ let traceloopInitialized = false;
261
+ try {
262
+ if (useExternalOtel) {
263
+ traceloop3.initialize({
264
+ baseUrl: apiUrl,
265
+ apiKey: writeKey,
266
+ logLevel,
267
+ tracingEnabled: false
268
+ // DO NOT create NodeSDK - customer has their own
269
+ });
270
+ traceloopInitialized = true;
271
+ if (isDebug) {
272
+ console.log(
273
+ "[raindrop] External OTEL mode active. Add raindrop.createSpanProcessor() to your NodeSDK's spanProcessors. Register instrumentations (AnthropicInstrumentation, etc.) on your NodeSDK."
274
+ );
275
+ }
276
+ if (otherOptions.instrumentModules && Object.keys(otherOptions.instrumentModules).length > 0) {
277
+ if (isDebug) {
278
+ console.log(
279
+ "[raindrop] instrumentModules configured. Call raindrop.getInstrumentations() to get instrumentation instances for your NodeSDK."
280
+ );
281
+ }
282
+ }
283
+ } else {
284
+ traceloop3.initialize({
285
+ baseUrl: apiUrl,
286
+ apiKey: writeKey,
287
+ ...otherOptions,
288
+ logLevel,
289
+ tracingEnabled: tracingEnabled !== false
290
+ });
291
+ traceloopInitialized = true;
292
+ }
293
+ } catch (error) {
294
+ console.warn(
295
+ "[raindrop] Failed to initialize traceloop. Spans will not be sent.",
296
+ error instanceof Error ? error.message : error
297
+ );
298
+ }
299
+ return {
300
+ /**
301
+ * Returns instrumentation instances for your NodeSDK.
302
+ * Add these to your NodeSDK when using useExternalOtel: true.
303
+ *
304
+ * - If `instrumentModules` is provided: returns only those specific instrumentations
305
+ * - If `instrumentModules` is NOT provided: returns ALL default instrumentations (auto-instrumentation)
306
+ *
307
+ * @example
308
+ * ```typescript
309
+ * const raindrop = new Raindrop({
310
+ * useExternalOtel: true,
311
+ * // instrumentModules is optional - if omitted, all instrumentations are returned
312
+ * });
313
+ *
314
+ * const sdk = new NodeSDK({
315
+ * spanProcessors: [raindrop.createSpanProcessor()],
316
+ * instrumentations: raindrop.getInstrumentations(),
317
+ * });
318
+ * sdk.start();
319
+ * ```
320
+ */
321
+ getInstrumentations() {
322
+ if (!useExternalOtel) {
323
+ console.warn(
324
+ "[raindrop] getInstrumentations() is meant for useExternalOtel: true. In default mode, instrumentations are automatically registered."
325
+ );
326
+ }
327
+ if (otherOptions.instrumentModules && Object.keys(otherOptions.instrumentModules).length > 0) {
328
+ return createManualInstrumentations(
329
+ otherOptions.instrumentModules
330
+ );
331
+ }
332
+ return createDefaultInstrumentations();
333
+ },
334
+ /**
335
+ * Creates a span processor to add to your NodeSDK.
336
+ * This sends spans to Raindrop.
337
+ *
338
+ * @example
339
+ * ```typescript
340
+ * const sdk = new NodeSDK({
341
+ * spanProcessors: [raindrop.createSpanProcessor(), yourOtherProcessor],
342
+ * instrumentations: raindrop.getInstrumentations(),
343
+ * });
344
+ * ```
345
+ */
346
+ createSpanProcessor(processorOptions) {
347
+ if (!useExternalOtel) {
348
+ console.warn(
349
+ "[raindrop] createSpanProcessor() is meant for useExternalOtel: true. In default mode, spans are automatically sent to Raindrop."
350
+ );
351
+ }
352
+ if (!traceloopInitialized) {
353
+ console.error("[raindrop] Cannot create span processor - traceloop failed to initialize.");
354
+ return {
355
+ forceFlush: async () => {
356
+ },
357
+ onStart: () => {
358
+ },
359
+ onEnd: () => {
360
+ },
361
+ shutdown: async () => {
362
+ }
363
+ };
364
+ }
365
+ return traceloop3.createSpanProcessor({
366
+ baseUrl: apiUrl,
367
+ apiKey: writeKey,
368
+ ...processorOptions != null ? processorOptions : {}
369
+ });
370
+ },
371
+ begin(traceContext) {
372
+ if (!traceContext.eventId) {
373
+ traceContext.eventId = crypto.randomUUID();
374
+ }
375
+ const traceId = getCurrentTraceId();
376
+ analytics._trackAiPartial({
377
+ ...traceContext
378
+ });
379
+ const interaction = new LiveInteraction(
380
+ traceContext,
381
+ traceId,
382
+ analytics
383
+ );
384
+ if (traceId) {
385
+ activeInteractions.set(traceId, interaction);
386
+ }
387
+ activeInteractionsByEventId.set(traceContext.eventId, interaction);
388
+ return interaction;
389
+ },
390
+ getActiveInteraction(eventId) {
391
+ const interactionByEventId = activeInteractionsByEventId.get(eventId);
392
+ if (interactionByEventId) {
393
+ return interactionByEventId;
394
+ }
395
+ const traceId = getCurrentTraceId();
396
+ if (traceId) {
397
+ const interactionByTraceId = activeInteractions.get(traceId);
398
+ if (interactionByTraceId) {
399
+ return interactionByTraceId;
400
+ }
401
+ }
402
+ const interaction = new LiveInteraction({ eventId }, traceId, analytics);
403
+ activeInteractionsByEventId.set(eventId, interaction);
404
+ return interaction;
405
+ },
406
+ tracer(globalProperties) {
407
+ return new LiveTracer(globalProperties);
408
+ },
409
+ async close() {
410
+ activeInteractions.clear();
411
+ activeInteractionsByEventId.clear();
412
+ if (traceloopInitialized) {
413
+ try {
414
+ await traceloop3.forceFlush();
415
+ } catch (e) {
416
+ }
417
+ }
418
+ }
419
+ };
420
+ };
421
+
422
+ export {
423
+ tracing
424
+ };
package/dist/index.d.mts CHANGED
@@ -1,3 +1,4 @@
1
+ import * as _opentelemetry_instrumentation from '@opentelemetry/instrumentation';
1
2
  import { Span } from '@opentelemetry/api';
2
3
  import { z } from 'zod';
3
4
  import { SpanProcessorOptions } from '@traceloop/node-server-sdk';
@@ -398,10 +399,37 @@ interface AnalyticsConfig {
398
399
  endpoint?: string;
399
400
  redactPii?: boolean;
400
401
  /**
401
- * false by default. If true, raindrop doesn't initialize OTEL tracing.
402
- * you can then use the span processor using raindrop.createSpanProcessor()
402
+ * @deprecated Renamed to `useExternalOtel`. Use that instead.
403
+ * This option will be removed in a future version.
403
404
  */
404
405
  disableTracing?: boolean;
406
+ /**
407
+ * Set to true if you have your own OpenTelemetry setup (e.g., Sentry, Datadog).
408
+ *
409
+ * When true:
410
+ * - Raindrop won't create its own NodeSDK (avoids conflicts)
411
+ * - Use `raindrop.createSpanProcessor()` to get a processor for your NodeSDK
412
+ * - Use `raindrop.getInstrumentations()` to get configured LLM instrumentations
413
+ *
414
+ * @example
415
+ * ```ts
416
+ * import { NodeSDK } from "@opentelemetry/sdk-node";
417
+ * import Anthropic from "@anthropic-ai/sdk";
418
+ *
419
+ * const raindrop = new Raindrop({
420
+ * writeKey: "xxx",
421
+ * useExternalOtel: true,
422
+ * instrumentModules: { anthropic: Anthropic },
423
+ * });
424
+ *
425
+ * const sdk = new NodeSDK({
426
+ * spanProcessors: [raindrop.createSpanProcessor(), yourSentryProcessor],
427
+ * instrumentations: raindrop.getInstrumentations(),
428
+ * });
429
+ * sdk.start();
430
+ * ```
431
+ */
432
+ useExternalOtel?: boolean;
405
433
  /**
406
434
  * false by default. If true, the SDK will not send any events or initialize tracing.
407
435
  * Useful for development/test environments.
@@ -479,6 +507,29 @@ declare class Raindrop {
479
507
  */
480
508
  tracer(globalProperties?: Record<string, string>): Tracer;
481
509
  createSpanProcessor(processorOptions?: SpanProcessorOptions): RaindropSpanProcessor;
510
+ /**
511
+ * Returns configured instrumentation instances based on instrumentModules.
512
+ * Add these to your NodeSDK when using useExternalOtel: true.
513
+ *
514
+ * @example
515
+ * ```ts
516
+ * import { NodeSDK } from "@opentelemetry/sdk-node";
517
+ * import Anthropic from "@anthropic-ai/sdk";
518
+ *
519
+ * const raindrop = new Raindrop({
520
+ * writeKey: "xxx",
521
+ * useExternalOtel: true,
522
+ * instrumentModules: { anthropic: Anthropic },
523
+ * });
524
+ *
525
+ * const sdk = new NodeSDK({
526
+ * spanProcessors: [raindrop.createSpanProcessor()],
527
+ * instrumentations: raindrop.getInstrumentations(),
528
+ * });
529
+ * sdk.start();
530
+ * ```
531
+ */
532
+ getInstrumentations(): _opentelemetry_instrumentation.Instrumentation<_opentelemetry_instrumentation.InstrumentationConfig>[];
482
533
  /**
483
534
  * Resumes an existing interaction.
484
535
  *
package/dist/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import * as _opentelemetry_instrumentation from '@opentelemetry/instrumentation';
1
2
  import { Span } from '@opentelemetry/api';
2
3
  import { z } from 'zod';
3
4
  import { SpanProcessorOptions } from '@traceloop/node-server-sdk';
@@ -398,10 +399,37 @@ interface AnalyticsConfig {
398
399
  endpoint?: string;
399
400
  redactPii?: boolean;
400
401
  /**
401
- * false by default. If true, raindrop doesn't initialize OTEL tracing.
402
- * you can then use the span processor using raindrop.createSpanProcessor()
402
+ * @deprecated Renamed to `useExternalOtel`. Use that instead.
403
+ * This option will be removed in a future version.
403
404
  */
404
405
  disableTracing?: boolean;
406
+ /**
407
+ * Set to true if you have your own OpenTelemetry setup (e.g., Sentry, Datadog).
408
+ *
409
+ * When true:
410
+ * - Raindrop won't create its own NodeSDK (avoids conflicts)
411
+ * - Use `raindrop.createSpanProcessor()` to get a processor for your NodeSDK
412
+ * - Use `raindrop.getInstrumentations()` to get configured LLM instrumentations
413
+ *
414
+ * @example
415
+ * ```ts
416
+ * import { NodeSDK } from "@opentelemetry/sdk-node";
417
+ * import Anthropic from "@anthropic-ai/sdk";
418
+ *
419
+ * const raindrop = new Raindrop({
420
+ * writeKey: "xxx",
421
+ * useExternalOtel: true,
422
+ * instrumentModules: { anthropic: Anthropic },
423
+ * });
424
+ *
425
+ * const sdk = new NodeSDK({
426
+ * spanProcessors: [raindrop.createSpanProcessor(), yourSentryProcessor],
427
+ * instrumentations: raindrop.getInstrumentations(),
428
+ * });
429
+ * sdk.start();
430
+ * ```
431
+ */
432
+ useExternalOtel?: boolean;
405
433
  /**
406
434
  * false by default. If true, the SDK will not send any events or initialize tracing.
407
435
  * Useful for development/test environments.
@@ -479,6 +507,29 @@ declare class Raindrop {
479
507
  */
480
508
  tracer(globalProperties?: Record<string, string>): Tracer;
481
509
  createSpanProcessor(processorOptions?: SpanProcessorOptions): RaindropSpanProcessor;
510
+ /**
511
+ * Returns configured instrumentation instances based on instrumentModules.
512
+ * Add these to your NodeSDK when using useExternalOtel: true.
513
+ *
514
+ * @example
515
+ * ```ts
516
+ * import { NodeSDK } from "@opentelemetry/sdk-node";
517
+ * import Anthropic from "@anthropic-ai/sdk";
518
+ *
519
+ * const raindrop = new Raindrop({
520
+ * writeKey: "xxx",
521
+ * useExternalOtel: true,
522
+ * instrumentModules: { anthropic: Anthropic },
523
+ * });
524
+ *
525
+ * const sdk = new NodeSDK({
526
+ * spanProcessors: [raindrop.createSpanProcessor()],
527
+ * instrumentations: raindrop.getInstrumentations(),
528
+ * });
529
+ * sdk.start();
530
+ * ```
531
+ */
532
+ getInstrumentations(): _opentelemetry_instrumentation.Instrumentation<_opentelemetry_instrumentation.InstrumentationConfig>[];
482
533
  /**
483
534
  * Resumes an existing interaction.
484
535
  *