@raindrop-ai/ai-sdk 0.0.20 → 0.0.22

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,6 +5,7 @@ Standalone Vercel AI SDK integration for Raindrop:
5
5
  - **Events**: sends a `track_partial` payload to `POST /v1/events/track_partial` when the model finishes
6
6
  - **Standalone traces**: ships spans directly to `POST /v1/traces` as **OTLP/HTTP JSON**
7
7
  - **No OpenTelemetry SDK init**: avoids global OTEL registration conflicts
8
+ - **Native v7 telemetry**: opt-in callback-based integration via AI SDK v7's `TelemetryIntegration` interface (no Proxy wrapping)
8
9
 
9
10
  ## Install
10
11
 
@@ -54,6 +55,27 @@ await raindrop.users.identify({
54
55
  await raindrop.flush();
55
56
  ```
56
57
 
58
+ ### AI SDK v7+ native telemetry (opt-in)
59
+
60
+ On AI SDK v7+, you can use the native `TelemetryIntegration` callback interface instead of Proxy wrapping. This avoids Proxy overhead and works with all AI SDK entry points (including `ToolLoopAgent`).
61
+
62
+ ```ts
63
+ // Option A: wrap() with nativeTelemetry flag
64
+ const { generateText } = raindrop.wrap(ai, {
65
+ context: { userId: "user_123" },
66
+ nativeTelemetry: true,
67
+ });
68
+
69
+ // Option B: direct registration (no wrap needed)
70
+ import { registerTelemetryIntegration } from "ai";
71
+
72
+ registerTelemetryIntegration(
73
+ raindrop.createTelemetryIntegration({ userId: "user_123" })
74
+ );
75
+ ```
76
+
77
+ Setting `nativeTelemetry: true` on pre-v7 throws a clear error. The Proxy path remains the default and supports features not yet available on the native path (`buildEvent`, output attachment extraction).
78
+
57
79
  If `userId` is missing from both `wrap()` context and `eventMetadata()`, the SDK logs a warning (once) and skips sending events.
58
80
 
59
81
  ## Runtime support
@@ -101,11 +123,12 @@ but it uses the same synchronous fallback described above rather than real
101
123
 
102
124
  This package is tested against multiple Vercel AI SDK versions:
103
125
 
104
- | Version | Status |
105
- |---------|--------|
106
- | v4.x | ✅ Supported |
107
- | v5.x | ✅ Supported |
108
- | v6.x | ✅ Supported |
126
+ | Version | Status | Integration |
127
+ |---------|--------|-------------|
128
+ | v4.x | ✅ Supported | Proxy |
129
+ | v5.x | ✅ Supported | Proxy |
130
+ | v6.x | ✅ Supported | Proxy |
131
+ | v7.x (beta) | ✅ Supported | Proxy (default) or native `TelemetryIntegration` (opt-in) |
109
132
 
110
133
  ### Version Differences Handled
111
134
 
@@ -130,10 +153,15 @@ packages/ai-sdk/
130
153
  │ │ ├── ai-sdk.v5.test.ts
131
154
  │ │ ├── wrapper.test.ts
132
155
  │ │ └── http-payloads.test.ts
133
- └── v6/ # AI SDK v6 (pins ai@^6.0.0)
134
- ├── ai-sdk.v6.test.ts
135
- ├── wrapper.test.ts
136
- └── http-payloads.test.ts
156
+ ├── v6/ # AI SDK v6 (pins ai@^6.0.0)
157
+ ├── ai-sdk.v6.test.ts
158
+ ├── wrapper.test.ts
159
+ └── http-payloads.test.ts
160
+ │ └── v7/ # AI SDK v7 beta (native telemetry + proxy)
161
+ │ ├── telemetry-integration.test.ts # Unit tests for all callbacks
162
+ │ ├── e2e-native-telemetry.test.ts # E2E with real AI SDK + MSW
163
+ │ ├── e2e-subagent-nesting.test.ts # Subagent span hierarchy
164
+ │ └── wrapper.test.ts
137
165
  ```
138
166
 
139
167
  ### Running Tests
@@ -146,6 +174,7 @@ pnpm test
146
174
  pnpm test:v4
147
175
  pnpm test:v5
148
176
  pnpm test:v6
177
+ pnpm test:v7
149
178
 
150
179
  # Quick smoke test (real LLM calls, single version)
151
180
  pnpm smoke:min
@@ -158,6 +187,11 @@ Each version runs:
158
187
  - **HTTP payload tests** - MSW-based payload validation for each spec version
159
188
  - **Version-specific tests** - API differences (finishReason format, usage naming)
160
189
 
190
+ v7 additionally runs:
191
+ - **Telemetry integration tests** - All callback lifecycles with mock shippers
192
+ - **E2E native telemetry** - Real AI SDK v7 with MSW-intercepted payloads
193
+ - **Subagent nesting** - Span hierarchy for nested generateText inside tool execution
194
+
161
195
  ## Notes
162
196
 
163
197
  - Spans include `ai.telemetry.metadata.raindrop.eventId` for correlation, and **omit** `ai.telemetry.metadata.raindrop.userId` to prevent duplicate span→event creation server-side.
@@ -1,6 +1,6 @@
1
1
  import { AsyncLocalStorage } from 'async_hooks';
2
2
 
3
- // ../core/dist/chunk-H6VSZSLN.js
3
+ // ../core/dist/chunk-4UCYIEH4.js
4
4
  function getCrypto() {
5
5
  const c = globalThis.crypto;
6
6
  return c;
@@ -145,6 +145,7 @@ async function postJson(url, body, headers, opts) {
145
145
  );
146
146
  }
147
147
  var SpanStatusCode = {
148
+ UNSET: 0,
148
149
  ERROR: 2
149
150
  };
150
151
  function createSpanIds(parent) {
@@ -159,6 +160,9 @@ function createSpanIds(parent) {
159
160
  function nowUnixNanoString() {
160
161
  return Date.now().toString() + "000000";
161
162
  }
163
+ function unixMsToNanoString(ms) {
164
+ return String(Math.floor(ms)) + "000000";
165
+ }
162
166
  function attrString(key, value) {
163
167
  if (value === void 0) return void 0;
164
168
  return { key, value: { stringValue: value } };
@@ -465,11 +469,66 @@ var EventShipper = class {
465
469
  }
466
470
  }
467
471
  };
472
+ var LOCAL_DEBUGGER_ENV_VAR = "RAINDROP_LOCAL_DEBUGGER";
473
+ function resolveLocalDebuggerBaseUrl(baseUrl) {
474
+ var _a, _b, _c;
475
+ const resolved = (_b = baseUrl != null ? baseUrl : typeof process !== "undefined" ? (_a = process.env) == null ? void 0 : _a[LOCAL_DEBUGGER_ENV_VAR] : void 0) != null ? _b : null;
476
+ return resolved ? (_c = formatEndpoint(resolved)) != null ? _c : null : null;
477
+ }
478
+ function localDebuggerEnabled(baseUrl) {
479
+ return resolveLocalDebuggerBaseUrl(baseUrl) !== null;
480
+ }
481
+ function normalizeLocalDebuggerLiveEventType(type) {
482
+ switch (type) {
483
+ case "text-delta":
484
+ return "text_delta";
485
+ case "reasoning":
486
+ case "reasoning-delta":
487
+ return "reasoning_delta";
488
+ case "tool-call":
489
+ return "tool_start";
490
+ case "tool-result":
491
+ return "tool_result";
492
+ default:
493
+ return type;
494
+ }
495
+ }
496
+ function mirrorTraceExportToLocalDebugger(body, options = {}) {
497
+ var _a;
498
+ const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
499
+ if (!baseUrl) return;
500
+ void postJson(`${baseUrl}traces`, body, {}, {
501
+ maxAttempts: 1,
502
+ debug: (_a = options.debug) != null ? _a : false,
503
+ sdkName: options.sdkName
504
+ }).catch(() => {
505
+ });
506
+ }
507
+ function sendLocalDebuggerLiveEvent(event, options = {}) {
508
+ var _a, _b;
509
+ const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
510
+ if (!baseUrl) return;
511
+ void postJson(
512
+ `${baseUrl}live`,
513
+ {
514
+ ...event,
515
+ type: normalizeLocalDebuggerLiveEventType(event.type),
516
+ timestamp: (_a = event.timestamp) != null ? _a : Date.now()
517
+ },
518
+ {},
519
+ {
520
+ maxAttempts: 1,
521
+ debug: (_b = options.debug) != null ? _b : false,
522
+ sdkName: options.sdkName
523
+ }
524
+ ).catch(() => {
525
+ });
526
+ }
468
527
  var TraceShipper = class {
469
528
  constructor(opts) {
470
529
  this.queue = [];
471
530
  this.inFlight = /* @__PURE__ */ new Set();
472
- var _a, _b, _c, _d, _e, _f, _g, _h;
531
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
473
532
  this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
474
533
  this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
475
534
  this.enabled = opts.enabled !== false;
@@ -482,6 +541,13 @@ var TraceShipper = class {
482
541
  this.prefix = `[raindrop-ai/${this.sdkName}]`;
483
542
  this.serviceName = (_g = opts.serviceName) != null ? _g : "raindrop.core";
484
543
  this.serviceVersion = (_h = opts.serviceVersion) != null ? _h : "0.0.0";
544
+ const localDebugger = typeof process !== "undefined" ? (_i = process.env) == null ? void 0 : _i.RAINDROP_LOCAL_DEBUGGER : void 0;
545
+ if (localDebugger) {
546
+ this.localDebuggerUrl = (_j = resolveLocalDebuggerBaseUrl(localDebugger)) != null ? _j : void 0;
547
+ if (this.debug) {
548
+ console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
549
+ }
550
+ }
485
551
  }
486
552
  isDebugEnabled() {
487
553
  return this.debug;
@@ -498,7 +564,25 @@ var TraceShipper = class {
498
564
  attrString("ai.operationId", args.operationId)
499
565
  ];
500
566
  if ((_b = args.attributes) == null ? void 0 : _b.length) attrs.push(...args.attributes);
501
- return { ids, name: args.name, startTimeUnixNano: started, attributes: attrs };
567
+ const span = { ids, name: args.name, startTimeUnixNano: started, attributes: attrs };
568
+ if (this.localDebuggerUrl) {
569
+ const openSpan = buildOtlpSpan({
570
+ ids: span.ids,
571
+ name: span.name,
572
+ startTimeUnixNano: span.startTimeUnixNano,
573
+ endTimeUnixNano: span.startTimeUnixNano,
574
+ // placeholder — will be updated on endSpan
575
+ attributes: span.attributes,
576
+ status: { code: SpanStatusCode.UNSET }
577
+ });
578
+ const body = buildExportTraceServiceRequest([openSpan], this.serviceName, this.serviceVersion);
579
+ mirrorTraceExportToLocalDebugger(body, {
580
+ baseUrl: this.localDebuggerUrl,
581
+ debug: false,
582
+ sdkName: this.sdkName
583
+ });
584
+ }
585
+ return span;
502
586
  }
503
587
  endSpan(span, extra) {
504
588
  var _a, _b;
@@ -521,6 +605,14 @@ var TraceShipper = class {
521
605
  status
522
606
  });
523
607
  this.enqueue(otlp);
608
+ if (this.localDebuggerUrl) {
609
+ const body = buildExportTraceServiceRequest([otlp], this.serviceName, this.serviceVersion);
610
+ mirrorTraceExportToLocalDebugger(body, {
611
+ baseUrl: this.localDebuggerUrl,
612
+ debug: false,
613
+ sdkName: this.sdkName
614
+ });
615
+ }
524
616
  }
525
617
  createSpan(args) {
526
618
  var _a;
@@ -538,6 +630,14 @@ var TraceShipper = class {
538
630
  status: args.status
539
631
  });
540
632
  this.enqueue(otlp);
633
+ if (this.localDebuggerUrl) {
634
+ const body = buildExportTraceServiceRequest([otlp], this.serviceName, this.serviceVersion);
635
+ mirrorTraceExportToLocalDebugger(body, {
636
+ baseUrl: this.localDebuggerUrl,
637
+ debug: false,
638
+ sdkName: this.sdkName
639
+ });
640
+ }
541
641
  }
542
642
  enqueue(span) {
543
643
  if (!this.enabled) return;
@@ -1517,6 +1617,7 @@ var RaindropTelemetryIntegration = class {
1517
1617
  ]
1518
1618
  });
1519
1619
  state.toolSpans.set(toolCall.toolCallId, toolSpan);
1620
+ this.emitLive(state, "tool_start", toolCall.toolName, { args: toolCall.input });
1520
1621
  };
1521
1622
  // ── onToolCallFinish ────────────────────────────────────────────────────
1522
1623
  this.onToolCallFinish = (event) => {
@@ -1531,11 +1632,12 @@ var RaindropTelemetryIntegration = class {
1531
1632
  } else {
1532
1633
  this.traceShipper.endSpan(toolSpan, { error: event.error });
1533
1634
  }
1635
+ this.emitLive(state, "tool_result", event.toolCall.toolName);
1534
1636
  state.toolSpans.delete(event.toolCall.toolCallId);
1535
1637
  };
1536
1638
  // ── onChunk (streaming) ─────────────────────────────────────────────────
1537
1639
  this.onChunk = (event) => {
1538
- var _a, _b, _c;
1640
+ var _a, _b, _c, _d, _e;
1539
1641
  const callId = (_b = event.callId) != null ? _b : (_a = event.chunk) == null ? void 0 : _a.callId;
1540
1642
  if (!callId) return;
1541
1643
  const state = this.getState(callId);
@@ -1546,6 +1648,12 @@ var RaindropTelemetryIntegration = class {
1546
1648
  const delta = (_c = chunk.textDelta) != null ? _c : chunk.delta;
1547
1649
  if (typeof delta === "string") {
1548
1650
  state.accumulatedText += delta;
1651
+ this.emitLive(state, "text_delta", delta);
1652
+ }
1653
+ } else if (chunk.type === "reasoning" || chunk.type === "reasoning-delta") {
1654
+ const text = (_e = (_d = chunk.textDelta) != null ? _d : chunk.text) != null ? _e : chunk.delta;
1655
+ if (typeof text === "string") {
1656
+ this.emitLive(state, "reasoning_delta", text);
1549
1657
  }
1550
1658
  }
1551
1659
  };
@@ -1733,6 +1841,23 @@ var RaindropTelemetryIntegration = class {
1733
1841
  spanParentRef(span) {
1734
1842
  return { traceIdB64: span.ids.traceIdB64, spanIdB64: span.ids.spanIdB64 };
1735
1843
  }
1844
+ emitLive(state, type, content, extra) {
1845
+ var _a, _b, _c, _d, _e, _f;
1846
+ if (!localDebuggerEnabled() || !state.rootSpan) return;
1847
+ const callMeta = this.extractRaindropMetadata(state.metadata);
1848
+ sendLocalDebuggerLiveEvent({
1849
+ traceId: state.rootSpan.ids.traceIdB64,
1850
+ type,
1851
+ content,
1852
+ metadata: {
1853
+ userId: (_b = callMeta.userId) != null ? _b : (_a = this.defaultContext) == null ? void 0 : _a.userId,
1854
+ convoId: (_d = callMeta.convoId) != null ? _d : (_c = this.defaultContext) == null ? void 0 : _c.convoId,
1855
+ eventName: (_f = callMeta.eventName) != null ? _f : (_e = this.defaultContext) == null ? void 0 : _e.eventName,
1856
+ eventId: state.eventId,
1857
+ ...extra
1858
+ }
1859
+ });
1860
+ }
1736
1861
  extractRaindropMetadata(metadata) {
1737
1862
  if (!metadata) return {};
1738
1863
  const result = {};
@@ -2265,6 +2390,36 @@ function shouldKeepEventPending(params) {
2265
2390
  if (params.error != null || !params.canKeepEventPending) return false;
2266
2391
  return params.finishReason === "tool-calls" || params.finishReason === "tool_calls";
2267
2392
  }
2393
+ function normalizePromptAttr(arg) {
2394
+ if (!isRecord(arg)) return arg;
2395
+ const system = arg["system"];
2396
+ const prompt = arg["prompt"];
2397
+ const messages = arg["messages"];
2398
+ if (Array.isArray(messages)) {
2399
+ if (system) {
2400
+ const sysContent = typeof system === "string" ? system : JSON.stringify(system);
2401
+ return [{ role: "system", content: sysContent }, ...messages];
2402
+ }
2403
+ return messages;
2404
+ }
2405
+ if (typeof prompt === "string") {
2406
+ const msgs = [];
2407
+ if (system) {
2408
+ msgs.push({ role: "system", content: typeof system === "string" ? system : JSON.stringify(system) });
2409
+ }
2410
+ msgs.push({ role: "user", content: prompt });
2411
+ return msgs;
2412
+ }
2413
+ return { system, prompt, messages };
2414
+ }
2415
+ function getLocalDebuggerMetadata(ctx) {
2416
+ return {
2417
+ eventId: ctx.eventId,
2418
+ ...ctx.eventName ? { eventName: ctx.eventName } : {},
2419
+ ...ctx.userId ? { userId: ctx.userId } : {},
2420
+ ...ctx.convoId ? { convoId: ctx.convoId } : {}
2421
+ };
2422
+ }
2268
2423
  async function safeFinalize(finalize, debug, result, error) {
2269
2424
  try {
2270
2425
  await finalize(result, error);
@@ -2337,17 +2492,17 @@ function setupOperation(params) {
2337
2492
  attrString("ai.telemetry.functionId", telemetry == null ? void 0 : telemetry.functionId),
2338
2493
  attrString("ai.model.provider", modelInfoFromArgs.provider),
2339
2494
  attrString("ai.model.id", modelInfoFromArgs.modelId),
2495
+ attrString("ai.telemetry.metadata.raindrop.eventId", eventId),
2496
+ attrString("ai.telemetry.metadata.raindrop.eventName", mergedCtx.eventName),
2497
+ attrString("ai.telemetry.metadata.raindrop.userId", mergedCtx.userId),
2498
+ attrString("ai.telemetry.metadata.raindrop.convoId", mergedCtx.convoId),
2340
2499
  ...attrsFromTelemetryMetadata(telemetry == null ? void 0 : telemetry.metadata),
2341
2500
  ...attrsFromHeaders(isRecord(arg) ? arg["headers"] : void 0),
2342
2501
  ...attrsFromSettings(arg),
2343
2502
  ...(telemetry == null ? void 0 : telemetry.recordInputs) === false ? [] : [
2344
2503
  attrString(
2345
2504
  "ai.prompt",
2346
- safeJsonWithUint8({
2347
- system: isRecord(arg) ? arg["system"] : void 0,
2348
- prompt: isRecord(arg) ? arg["prompt"] : void 0,
2349
- messages: isRecord(arg) ? arg["messages"] : void 0
2350
- })
2505
+ safeJsonWithUint8(normalizePromptAttr(arg))
2351
2506
  )
2352
2507
  ]
2353
2508
  ]
@@ -2356,6 +2511,7 @@ function setupOperation(params) {
2356
2511
  const operationSelfDiagnostics = isObjectOperation(operation) ? void 0 : selfDiagnostics;
2357
2512
  const wrapCtx = {
2358
2513
  eventId,
2514
+ context: mergedCtx,
2359
2515
  telemetry,
2360
2516
  sendTraces,
2361
2517
  debug,
@@ -2730,6 +2886,7 @@ function wrapAISDK(aiSDK, deps) {
2730
2886
  const perCallEventIdGenerated = !perCallEventIdExplicit;
2731
2887
  const perCallCtx = {
2732
2888
  eventId: perCallEventId,
2889
+ context: wrapTimeCtx,
2733
2890
  telemetry,
2734
2891
  sendTraces: false,
2735
2892
  debug,
@@ -2884,7 +3041,7 @@ function wrapAgentGenerate(generate, instance, agentSettings, className, aiSDK,
2884
3041
  if (!mergedCtx.userId) warnMissingUserIdOnce();
2885
3042
  const inherited = await getCurrentParentSpanContext();
2886
3043
  const eventId = (_c = (_b2 = (_a2 = callTimeCtx.eventId) != null ? _a2 : mergedCtx.eventId) != null ? _b2 : inherited == null ? void 0 : inherited.eventId) != null ? _c : randomUUID();
2887
- const ctx = { ...mergedCtx};
3044
+ const ctx = { ...mergedCtx, eventId };
2888
3045
  const inheritedParent = inherited && inherited.eventId === eventId ? { traceIdB64: inherited.traceIdB64, spanIdB64: inherited.spanIdB64 } : void 0;
2889
3046
  const outerOperationId = `ai.${operation}`;
2890
3047
  const { operationName, resourceName } = opName(outerOperationId, telemetry == null ? void 0 : telemetry.functionId);
@@ -2900,17 +3057,17 @@ function wrapAgentGenerate(generate, instance, agentSettings, className, aiSDK,
2900
3057
  attrString("ai.telemetry.functionId", telemetry == null ? void 0 : telemetry.functionId),
2901
3058
  attrString("ai.model.provider", modelInfoFromArgs.provider),
2902
3059
  attrString("ai.model.id", modelInfoFromArgs.modelId),
3060
+ attrString("ai.telemetry.metadata.raindrop.eventId", eventId),
3061
+ attrString("ai.telemetry.metadata.raindrop.eventName", ctx.eventName),
3062
+ attrString("ai.telemetry.metadata.raindrop.userId", ctx.userId),
3063
+ attrString("ai.telemetry.metadata.raindrop.convoId", ctx.convoId),
2903
3064
  ...attrsFromTelemetryMetadata(telemetry == null ? void 0 : telemetry.metadata),
2904
3065
  ...attrsFromHeaders(mergedArgs["headers"]),
2905
3066
  ...attrsFromSettings(mergedArgs),
2906
3067
  ...(telemetry == null ? void 0 : telemetry.recordInputs) === false ? [] : [
2907
3068
  attrString(
2908
3069
  "ai.prompt",
2909
- safeJsonWithUint8({
2910
- system: (_d = mergedArgs["system"]) != null ? _d : mergedArgs["instructions"],
2911
- prompt: mergedArgs["prompt"],
2912
- messages: mergedArgs["messages"]
2913
- })
3070
+ safeJsonWithUint8(normalizePromptAttr({ system: (_d = mergedArgs["system"]) != null ? _d : mergedArgs["instructions"], prompt: mergedArgs["prompt"], messages: mergedArgs["messages"] }))
2914
3071
  )
2915
3072
  ]
2916
3073
  ]
@@ -2918,6 +3075,7 @@ function wrapAgentGenerate(generate, instance, agentSettings, className, aiSDK,
2918
3075
  const rootParentForChildren = rootSpan ? { traceIdB64: rootSpan.ids.traceIdB64, spanIdB64: rootSpan.ids.spanIdB64 } : inheritedParent;
2919
3076
  const wrapCtx = {
2920
3077
  eventId,
3078
+ context: ctx,
2921
3079
  telemetry,
2922
3080
  sendTraces,
2923
3081
  debug,
@@ -3091,7 +3249,7 @@ function wrapAgentStream(stream, instance, agentSettings, className, aiSDK, deps
3091
3249
  if (!mergedCtx.userId) warnMissingUserIdOnce();
3092
3250
  const inherited = await getCurrentParentSpanContext();
3093
3251
  const eventId = (_c = (_b2 = (_a2 = callTimeCtx.eventId) != null ? _a2 : mergedCtx.eventId) != null ? _b2 : inherited == null ? void 0 : inherited.eventId) != null ? _c : randomUUID();
3094
- const ctx = { ...mergedCtx};
3252
+ const ctx = { ...mergedCtx, eventId };
3095
3253
  const inheritedParent = inherited && inherited.eventId === eventId ? { traceIdB64: inherited.traceIdB64, spanIdB64: inherited.spanIdB64 } : void 0;
3096
3254
  const outerOperationId = `ai.${operation}`;
3097
3255
  const { operationName, resourceName } = opName(outerOperationId, telemetry == null ? void 0 : telemetry.functionId);
@@ -3107,17 +3265,17 @@ function wrapAgentStream(stream, instance, agentSettings, className, aiSDK, deps
3107
3265
  attrString("ai.telemetry.functionId", telemetry == null ? void 0 : telemetry.functionId),
3108
3266
  attrString("ai.model.provider", modelInfoFromArgs.provider),
3109
3267
  attrString("ai.model.id", modelInfoFromArgs.modelId),
3268
+ attrString("ai.telemetry.metadata.raindrop.eventId", eventId),
3269
+ attrString("ai.telemetry.metadata.raindrop.eventName", ctx.eventName),
3270
+ attrString("ai.telemetry.metadata.raindrop.userId", ctx.userId),
3271
+ attrString("ai.telemetry.metadata.raindrop.convoId", ctx.convoId),
3110
3272
  ...attrsFromTelemetryMetadata(telemetry == null ? void 0 : telemetry.metadata),
3111
3273
  ...attrsFromHeaders(mergedArgs["headers"]),
3112
3274
  ...attrsFromSettings(mergedArgs),
3113
3275
  ...(telemetry == null ? void 0 : telemetry.recordInputs) === false ? [] : [
3114
3276
  attrString(
3115
3277
  "ai.prompt",
3116
- safeJsonWithUint8({
3117
- system: (_d = mergedArgs["system"]) != null ? _d : mergedArgs["instructions"],
3118
- prompt: mergedArgs["prompt"],
3119
- messages: mergedArgs["messages"]
3120
- })
3278
+ safeJsonWithUint8(normalizePromptAttr({ system: (_d = mergedArgs["system"]) != null ? _d : mergedArgs["instructions"], prompt: mergedArgs["prompt"], messages: mergedArgs["messages"] }))
3121
3279
  )
3122
3280
  ]
3123
3281
  ]
@@ -3125,6 +3283,7 @@ function wrapAgentStream(stream, instance, agentSettings, className, aiSDK, deps
3125
3283
  const rootParentForChildren = rootSpan ? { traceIdB64: rootSpan.ids.traceIdB64, spanIdB64: rootSpan.ids.spanIdB64 } : inheritedParent;
3126
3284
  const wrapCtx = {
3127
3285
  eventId,
3286
+ context: ctx,
3128
3287
  telemetry,
3129
3288
  sendTraces,
3130
3289
  debug,
@@ -3348,6 +3507,21 @@ function wrapToolExecute(name, tool, ctx, toolCalls) {
3348
3507
  });
3349
3508
  }
3350
3509
  };
3510
+ const sendToolLiveEvent = (parent, type, metadata) => {
3511
+ if (!localDebuggerEnabled() || !parent) return;
3512
+ sendLocalDebuggerLiveEvent({
3513
+ traceId: parent.traceIdB64,
3514
+ type,
3515
+ content: name,
3516
+ metadata: {
3517
+ ...getLocalDebuggerMetadata({
3518
+ ...ctx.context,
3519
+ eventId: ctx.eventId
3520
+ }),
3521
+ ...metadata
3522
+ }
3523
+ });
3524
+ };
3351
3525
  const createContextSpan = (span) => ({
3352
3526
  traceIdB64: span.ids.traceIdB64,
3353
3527
  spanIdB64: span.ids.spanIdB64,
@@ -3363,6 +3537,7 @@ function wrapToolExecute(name, tool, ctx, toolCalls) {
3363
3537
  const parentCtx = await getCurrentParentSpanContext();
3364
3538
  const parent = parentCtx && parentCtx.eventId === ctx.eventId ? { traceIdB64: parentCtx.traceIdB64, spanIdB64: parentCtx.spanIdB64 } : ctx.rootParentForChildren;
3365
3539
  const toolSpan = createToolSpan(toolCallId, toolArgs, parent);
3540
+ sendToolLiveEvent(parent, "tool_start", { args: toolArgs });
3366
3541
  try {
3367
3542
  let lastValue;
3368
3543
  const iterator = result[Symbol.asyncIterator]();
@@ -3378,9 +3553,13 @@ function wrapToolExecute(name, tool, ctx, toolCalls) {
3378
3553
  }
3379
3554
  toolCalls.push({ id: toolCallId, name, args: toolArgs, result: lastValue, status: "OK" });
3380
3555
  endToolSpan(toolSpan, lastValue);
3556
+ sendToolLiveEvent(parent, "tool_result", { result: lastValue });
3381
3557
  } catch (error) {
3382
3558
  toolCalls.push({ id: toolCallId, name, args: toolArgs, status: "ERROR" });
3383
3559
  endToolSpan(toolSpan, void 0, error);
3560
+ sendToolLiveEvent(parent, "tool_result", {
3561
+ error: error instanceof Error ? error.message : String(error)
3562
+ });
3384
3563
  throw error;
3385
3564
  }
3386
3565
  })();
@@ -3389,6 +3568,7 @@ function wrapToolExecute(name, tool, ctx, toolCalls) {
3389
3568
  const parentCtx = await getCurrentParentSpanContext();
3390
3569
  const parent = parentCtx && parentCtx.eventId === ctx.eventId ? { traceIdB64: parentCtx.traceIdB64, spanIdB64: parentCtx.spanIdB64 } : ctx.rootParentForChildren;
3391
3570
  const toolSpan = createToolSpan(toolCallId, toolArgs, parent);
3571
+ sendToolLiveEvent(parent, "tool_start", { args: toolArgs });
3392
3572
  const run = async () => {
3393
3573
  try {
3394
3574
  const awaitedResult = await result;
@@ -3400,10 +3580,14 @@ function wrapToolExecute(name, tool, ctx, toolCalls) {
3400
3580
  status: "OK"
3401
3581
  });
3402
3582
  endToolSpan(toolSpan, awaitedResult);
3583
+ sendToolLiveEvent(parent, "tool_result", { result: awaitedResult });
3403
3584
  return awaitedResult;
3404
3585
  } catch (error) {
3405
3586
  toolCalls.push({ id: toolCallId, name, args: toolArgs, status: "ERROR" });
3406
3587
  endToolSpan(toolSpan, void 0, error);
3588
+ sendToolLiveEvent(parent, "tool_result", {
3589
+ error: error instanceof Error ? error.message : String(error)
3590
+ });
3407
3591
  throw error;
3408
3592
  }
3409
3593
  };
@@ -3443,6 +3627,7 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
3443
3627
  const original = Reflect.get(target, prop, receiver);
3444
3628
  if (prop === "doGenerate" && isFunction(original)) {
3445
3629
  return async (...callArgs) => {
3630
+ var _a, _b;
3446
3631
  const options = callArgs[0];
3447
3632
  const parentCtx = await getCurrentParentSpanContext();
3448
3633
  const parent = parentCtx && parentCtx.eventId === ctx.eventId ? { traceIdB64: parentCtx.traceIdB64, spanIdB64: parentCtx.spanIdB64 } : ctx.rootParentForChildren;
@@ -3450,6 +3635,22 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
3450
3635
  try {
3451
3636
  const result = await original.apply(target, callArgs);
3452
3637
  if (span) endDoGenerateSpan(span, result, modelInfo, ctx);
3638
+ if (localDebuggerEnabled() && ctx.rootParentForChildren && isRecord(result)) {
3639
+ const traceId = ctx.rootParentForChildren.traceIdB64;
3640
+ const liveMeta = getLocalDebuggerMetadata({ ...ctx.context, eventId: ctx.eventId });
3641
+ const content = result["content"];
3642
+ if (Array.isArray(content)) {
3643
+ for (const part of content) {
3644
+ if (isRecord(part)) {
3645
+ if ((part["type"] === "reasoning" || part["type"] === "thinking") && typeof ((_a = part["text"]) != null ? _a : part["thinking"]) === "string") {
3646
+ sendLocalDebuggerLiveEvent({ traceId, type: "reasoning_delta", content: (_b = part["text"]) != null ? _b : part["thinking"], metadata: liveMeta });
3647
+ } else if (part["type"] === "text" && typeof part["text"] === "string") {
3648
+ sendLocalDebuggerLiveEvent({ traceId, type: "text_delta", content: part["text"], metadata: liveMeta });
3649
+ }
3650
+ }
3651
+ }
3652
+ }
3653
+ }
3453
3654
  return result;
3454
3655
  } catch (error) {
3455
3656
  if (span)
@@ -3589,6 +3790,23 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
3589
3790
  }
3590
3791
  if ("usage" in value) usage = value["usage"];
3591
3792
  if ("providerMetadata" in value) providerMetadata = value["providerMetadata"];
3793
+ if (localDebuggerEnabled() && ctx.rootParentForChildren) {
3794
+ const traceId = ctx.rootParentForChildren.traceIdB64;
3795
+ const liveMeta = getLocalDebuggerMetadata({ ...ctx.context, eventId: ctx.eventId });
3796
+ if (type === "text-delta") {
3797
+ const text = typeof value["delta"] === "string" ? value["delta"] : typeof value["textDelta"] === "string" ? value["textDelta"] : typeof value["text"] === "string" ? value["text"] : void 0;
3798
+ if (typeof text === "string" && text) sendLocalDebuggerLiveEvent({ traceId, type: "text_delta", content: text, metadata: liveMeta });
3799
+ } else if (type === "reasoning" || type === "reasoning-delta") {
3800
+ const text = typeof value["delta"] === "string" ? value["delta"] : typeof value["text"] === "string" ? value["text"] : typeof value["thinking"] === "string" ? value["thinking"] : void 0;
3801
+ if (typeof text === "string" && text) sendLocalDebuggerLiveEvent({ traceId, type: "reasoning_delta", content: text, metadata: liveMeta });
3802
+ } else if (type === "tool-call") {
3803
+ const toolName = typeof value["toolName"] === "string" ? value["toolName"] : "tool";
3804
+ sendLocalDebuggerLiveEvent({ traceId, type: "tool_start", content: toolName, metadata: { ...liveMeta, args: value["args"] } });
3805
+ } else if (type === "tool-result") {
3806
+ const toolName = typeof value["toolName"] === "string" ? value["toolName"] : "tool";
3807
+ sendLocalDebuggerLiveEvent({ traceId, type: "tool_result", content: toolName, metadata: { ...liveMeta, result: value["result"] } });
3808
+ }
3809
+ }
3592
3810
  }
3593
3811
  controller.enqueue(value);
3594
3812
  } catch (error) {
@@ -3789,7 +4007,7 @@ function extractNestedTokens(usage, key) {
3789
4007
  // package.json
3790
4008
  var package_default = {
3791
4009
  name: "@raindrop-ai/ai-sdk",
3792
- version: "0.0.20"};
4010
+ version: "0.0.22"};
3793
4011
 
3794
4012
  // src/internal/version.ts
3795
4013
  var libraryName = package_default.name;
@@ -3861,6 +4079,14 @@ function eventMetadataFromChatRequest(options) {
3861
4079
  ...eventId ? { eventId } : {}
3862
4080
  });
3863
4081
  }
4082
+ function stringify(v) {
4083
+ if (typeof v === "string") return v;
4084
+ return JSON.stringify(v);
4085
+ }
4086
+ function userAttrsToOtlp(attrs) {
4087
+ if (!attrs) return [];
4088
+ return Object.entries(attrs).map(([key, value]) => attrString(key, value));
4089
+ }
3864
4090
  function envDebugEnabled() {
3865
4091
  var _a;
3866
4092
  if (typeof process === "undefined") return false;
@@ -3929,6 +4155,76 @@ function createRaindropAISDK(opts) {
3929
4155
  await eventShipper.finish(eventId, patch);
3930
4156
  }
3931
4157
  },
4158
+ traces: /* @__PURE__ */ (() => {
4159
+ const openSpans = /* @__PURE__ */ new Map();
4160
+ function toTraceSpan(internal) {
4161
+ return { traceId: internal.ids.traceIdB64, spanId: internal.ids.spanIdB64 };
4162
+ }
4163
+ return {
4164
+ startSpan(args) {
4165
+ const parent = args.parent ? { traceIdB64: args.parent.traceId, spanIdB64: args.parent.spanId } : void 0;
4166
+ const attrs = userAttrsToOtlp(args.attributes);
4167
+ if (args.operationId === "ai.toolCall") {
4168
+ attrs.push(attrString("ai.toolCall.name", args.name));
4169
+ }
4170
+ const internal = traceShipper.startSpan({
4171
+ name: args.name,
4172
+ eventId: args.eventId,
4173
+ parent,
4174
+ operationId: args.operationId,
4175
+ attributes: attrs
4176
+ });
4177
+ const handle = toTraceSpan(internal);
4178
+ openSpans.set(handle.spanId, internal);
4179
+ return handle;
4180
+ },
4181
+ endSpan(span, extra) {
4182
+ const internal = openSpans.get(span.spanId);
4183
+ if (!internal) return;
4184
+ openSpans.delete(span.spanId);
4185
+ const errorValue = extra == null ? void 0 : extra.error;
4186
+ const error = errorValue instanceof Error ? errorValue : typeof errorValue === "string" ? new Error(errorValue) : void 0;
4187
+ traceShipper.endSpan(internal, {
4188
+ attributes: userAttrsToOtlp(extra == null ? void 0 : extra.attributes),
4189
+ error
4190
+ });
4191
+ },
4192
+ createSpan(args) {
4193
+ var _a2;
4194
+ const parent = args.parent ? { traceIdB64: args.parent.traceId, spanIdB64: args.parent.spanId } : void 0;
4195
+ const startMs = (_a2 = args.startTime) != null ? _a2 : Date.now() - args.durationMs;
4196
+ const startAttrs = [...userAttrsToOtlp(args.attributes)];
4197
+ if (args.operationId === "ai.toolCall") {
4198
+ startAttrs.push(attrString("ai.toolCall.name", args.name));
4199
+ }
4200
+ if (args.input !== void 0) startAttrs.push(attrString("traceloop.entity.input", stringify(args.input)));
4201
+ if (args.operationId === "ai.toolCall" && args.input !== void 0) {
4202
+ startAttrs.push(attrString("ai.toolCall.args", stringify(args.input)));
4203
+ }
4204
+ const internal = traceShipper.startSpan({
4205
+ name: args.name,
4206
+ eventId: args.eventId,
4207
+ parent,
4208
+ operationId: args.operationId,
4209
+ attributes: startAttrs,
4210
+ startTimeUnixNano: unixMsToNanoString(startMs)
4211
+ });
4212
+ const endAttrs = [];
4213
+ if (args.output !== void 0) endAttrs.push(attrString("traceloop.entity.output", stringify(args.output)));
4214
+ if (args.operationId === "ai.toolCall" && args.output !== void 0) {
4215
+ endAttrs.push(attrString("ai.toolCall.result", stringify(args.output)));
4216
+ }
4217
+ const errorValue = args.error;
4218
+ const error = errorValue instanceof Error ? errorValue : typeof errorValue === "string" ? new Error(errorValue) : void 0;
4219
+ traceShipper.endSpan(internal, {
4220
+ attributes: endAttrs,
4221
+ error,
4222
+ endTimeUnixNano: unixMsToNanoString(startMs + args.durationMs)
4223
+ });
4224
+ return toTraceSpan(internal);
4225
+ }
4226
+ };
4227
+ })(),
3932
4228
  users: {
3933
4229
  async identify(users) {
3934
4230
  await eventShipper.identify(users);