@raindrop-ai/ai-sdk 0.0.29 → 0.0.31

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.
@@ -1019,7 +1019,7 @@ async function* asyncGeneratorWithCurrent(span, gen) {
1019
1019
  // package.json
1020
1020
  var package_default = {
1021
1021
  name: "@raindrop-ai/ai-sdk",
1022
- version: "0.0.29"};
1022
+ version: "0.0.31"};
1023
1023
 
1024
1024
  // src/internal/version.ts
1025
1025
  var libraryName = package_default.name;
@@ -1735,13 +1735,76 @@ function readRaindropCallMetadataFromArgs(args) {
1735
1735
  return meta;
1736
1736
  }
1737
1737
 
1738
+ // src/internal/parent-tool-context.ts
1739
+ var SyncFallbackStorage2 = class {
1740
+ constructor() {
1741
+ this._stack = [];
1742
+ }
1743
+ getStore() {
1744
+ return this._stack[this._stack.length - 1];
1745
+ }
1746
+ run(store, callback) {
1747
+ this._stack.push(store);
1748
+ try {
1749
+ return callback();
1750
+ } finally {
1751
+ this._stack.pop();
1752
+ }
1753
+ }
1754
+ // `enterWith` is intentionally absent on the sync fallback — the
1755
+ // event-driven enter/clear pattern only makes sense when the runtime
1756
+ // can propagate state across awaits, which the sync stack cannot.
1757
+ };
1758
+ var _storage2 = null;
1759
+ function getStorage2() {
1760
+ if (_storage2) return _storage2;
1761
+ const Ctor = globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
1762
+ _storage2 = Ctor ? new Ctor() : new SyncFallbackStorage2();
1763
+ return _storage2;
1764
+ }
1765
+ function _resetParentToolContextStorage() {
1766
+ _storage2 = null;
1767
+ }
1768
+ function getCurrentParentToolContext() {
1769
+ return getStorage2().getStore();
1770
+ }
1771
+ function enterParentToolContext(ctx) {
1772
+ var _a;
1773
+ const storage = getStorage2();
1774
+ (_a = storage.enterWith) == null ? void 0 : _a.call(storage, ctx);
1775
+ }
1776
+ function clearParentToolContext() {
1777
+ var _a;
1778
+ const storage = getStorage2();
1779
+ (_a = storage.enterWith) == null ? void 0 : _a.call(storage, void 0);
1780
+ }
1781
+ function runWithParentToolContext(ctx, fn) {
1782
+ return getStorage2().run(ctx, fn);
1783
+ }
1784
+
1738
1785
  // src/internal/raindrop-telemetry-integration.ts
1739
1786
  var RaindropTelemetryIntegration = class {
1740
1787
  constructor(opts) {
1741
1788
  this.callStates = /* @__PURE__ */ new Map();
1789
+ /**
1790
+ * Per-tool-call snapshot of the parent-tool ALS context taken right
1791
+ * before `enterParentToolContext` overwrites it in `toolExecutionStart`.
1792
+ * Kept at the integration level (rather than on `CallState`) so the
1793
+ * snapshot survives even when the parent generation has no tracked
1794
+ * `CallState` — e.g. the AI SDK dispatches a tool callback for a
1795
+ * `callId` we never registered via `onStart`. Without this, the
1796
+ * unconditional ALS enter in `toolExecutionStart` would leave
1797
+ * `toolExecutionEnd` no way to restore the prior context, so it would
1798
+ * clear and wipe whatever the outer scope had set.
1799
+ *
1800
+ * Keyed by `toolCallId` because that's the only identifier guaranteed
1801
+ * to round-trip between `toolExecutionStart` and `toolExecutionEnd`
1802
+ * (the `event.callId` can be the same for parallel sibling tools).
1803
+ */
1804
+ this.priorParentContexts = /* @__PURE__ */ new Map();
1742
1805
  // ── onStart ─────────────────────────────────────────────────────────────
1743
1806
  this.onStart = (event) => {
1744
- var _a, _b, _c, _d;
1807
+ var _a, _b, _c, _d, _e;
1745
1808
  if (event.isEnabled === false) return;
1746
1809
  const isEmbed = event.operationId === "ai.embed" || event.operationId === "ai.embedMany";
1747
1810
  const recordInputs = event.recordInputs !== false;
@@ -1760,6 +1823,47 @@ var RaindropTelemetryIntegration = class {
1760
1823
  event.operationId,
1761
1824
  functionId
1762
1825
  );
1826
+ const parentToolContext = !isEmbed && this.subagentWrapping ? getCurrentParentToolContext() : void 0;
1827
+ const metadataSubagentName = !isEmbed && this.subagentWrapping && parentToolContext === void 0 ? typeof (metadata == null ? void 0 : metadata["ash.subagent.name"]) === "string" ? metadata["ash.subagent.name"] : void 0 : void 0;
1828
+ const subagentName = (_e = parentToolContext == null ? void 0 : parentToolContext.toolName) != null ? _e : metadataSubagentName;
1829
+ let subagentToolCallSpan;
1830
+ let rootParentOverride;
1831
+ if (subagentName && this.sendTraces) {
1832
+ const parentAttrs = parentToolContext ? [
1833
+ attrString("raindrop.parent.callId", parentToolContext.parentCallId),
1834
+ attrString("raindrop.parent.toolCallId", parentToolContext.toolCallId),
1835
+ attrString("raindrop.parent.toolName", parentToolContext.toolName)
1836
+ ] : [];
1837
+ subagentToolCallSpan = this.traceShipper.startSpan({
1838
+ name: subagentName,
1839
+ parent: inheritedParent,
1840
+ eventId,
1841
+ operationId: "ai.toolCall",
1842
+ attributes: [
1843
+ attrString("operation.name", "ai.toolCall"),
1844
+ attrString("resource.name", subagentName),
1845
+ attrString("raindrop.span.kind", "tool_call"),
1846
+ attrString("ai.toolCall.name", subagentName),
1847
+ attrString("raindrop.subagent.name", subagentName),
1848
+ attrString("raindrop.agent.role", "subagent"),
1849
+ ...parentAttrs
1850
+ ]
1851
+ });
1852
+ const subagentParentRef = this.spanParentRef(subagentToolCallSpan);
1853
+ const markerSpan = this.traceShipper.startSpan({
1854
+ name: "agent.subagent",
1855
+ parent: subagentParentRef,
1856
+ eventId,
1857
+ operationId: "agent.subagent",
1858
+ attributes: [
1859
+ attrString("operation.name", "agent.subagent"),
1860
+ attrString("raindrop.span.kind", "llm_call"),
1861
+ attrString("raindrop.subagent.name", subagentName)
1862
+ ]
1863
+ });
1864
+ this.traceShipper.endSpan(markerSpan);
1865
+ rootParentOverride = subagentParentRef;
1866
+ }
1763
1867
  let rootSpan;
1764
1868
  if (this.sendTraces) {
1765
1869
  const promptAttrs = !isEmbed && recordInputs ? [
@@ -1780,7 +1884,7 @@ var RaindropTelemetryIntegration = class {
1780
1884
  ] : [attrString("ai.value", safeJsonWithUint8(event.value))] : [];
1781
1885
  rootSpan = this.traceShipper.startSpan({
1782
1886
  name: event.operationId,
1783
- parent: inheritedParent,
1887
+ parent: rootParentOverride != null ? rootParentOverride : inheritedParent,
1784
1888
  eventId,
1785
1889
  operationId: event.operationId,
1786
1890
  attributes: [
@@ -1808,18 +1912,21 @@ var RaindropTelemetryIntegration = class {
1808
1912
  operationId: event.operationId,
1809
1913
  eventId,
1810
1914
  rootSpan,
1811
- rootParent: rootSpan ? this.spanParentRef(rootSpan) : inheritedParent,
1915
+ rootParent: rootSpan ? this.spanParentRef(rootSpan) : rootParentOverride != null ? rootParentOverride : inheritedParent,
1812
1916
  stepSpan: void 0,
1813
1917
  stepParent: void 0,
1814
1918
  toolSpans: /* @__PURE__ */ new Map(),
1815
1919
  embedSpans: /* @__PURE__ */ new Map(),
1920
+ parentContextToolCallIds: /* @__PURE__ */ new Set(),
1816
1921
  recordInputs,
1817
1922
  recordOutputs,
1818
1923
  functionId,
1819
1924
  metadata,
1820
1925
  accumulatedText: "",
1821
1926
  inputText: isEmbed ? void 0 : this.extractInputText(event),
1822
- toolCallCount: 0
1927
+ toolCallCount: 0,
1928
+ subagentName,
1929
+ subagentToolCallSpan
1823
1930
  });
1824
1931
  };
1825
1932
  // ── onStepStart ─────────────────────────────────────────────────────────
@@ -2033,6 +2140,10 @@ var RaindropTelemetryIntegration = class {
2033
2140
  this.traceShipper.endSpan(embedSpan, { attributes: outputAttrs });
2034
2141
  state.embedSpans.delete(event.embedCallId);
2035
2142
  };
2143
+ // v7 canary.159 renamed `onEmbedFinish` -> `onEmbedEnd`. Both names forward
2144
+ // to the same implementation; the installed SDK only wires up whichever it
2145
+ // knows about, so there is no double dispatch.
2146
+ this.onEmbedEnd = (event) => this.onEmbedFinish(event);
2036
2147
  // ── onFinish ────────────────────────────────────────────────────────────
2037
2148
  this.onFinish = (event) => {
2038
2149
  const state = this.getState(event.callId);
@@ -2043,8 +2154,17 @@ var RaindropTelemetryIntegration = class {
2043
2154
  } else {
2044
2155
  this.finishGenerate(event, state);
2045
2156
  }
2157
+ if (state.subagentToolCallSpan) {
2158
+ this.traceShipper.endSpan(state.subagentToolCallSpan);
2159
+ }
2046
2160
  this.cleanup(event.callId);
2047
2161
  };
2162
+ // v7 < canary.159 dispatched `onFinish` as the operation finalizer; canary.159
2163
+ // renamed it to `onEnd` (the same change renamed onEmbedFinish -> onEmbedEnd
2164
+ // and onRerankFinish -> onRerankEnd). The event shape is unchanged, so this
2165
+ // is a thin alias to one implementation. The installed SDK wires up whichever
2166
+ // name it knows about, so old and new names never double dispatch.
2167
+ this.onEnd = (event) => this.onFinish(event);
2048
2168
  // ── onError ─────────────────────────────────────────────────────────────
2049
2169
  this.onError = (error) => {
2050
2170
  var _a;
@@ -2060,6 +2180,10 @@ var RaindropTelemetryIntegration = class {
2060
2180
  this.traceShipper.endSpan(embedSpan, { error: actualError });
2061
2181
  }
2062
2182
  state.embedSpans.clear();
2183
+ for (const toolCallId of state.parentContextToolCallIds) {
2184
+ this.priorParentContexts.delete(toolCallId);
2185
+ }
2186
+ state.parentContextToolCallIds.clear();
2063
2187
  for (const toolSpan of state.toolSpans.values()) {
2064
2188
  this.traceShipper.endSpan(toolSpan, { error: actualError });
2065
2189
  }
@@ -2067,6 +2191,9 @@ var RaindropTelemetryIntegration = class {
2067
2191
  if (state.rootSpan) {
2068
2192
  this.traceShipper.endSpan(state.rootSpan, { error: actualError });
2069
2193
  }
2194
+ if (state.subagentToolCallSpan) {
2195
+ this.traceShipper.endSpan(state.subagentToolCallSpan, { error: actualError });
2196
+ }
2070
2197
  this.cleanup(event.callId);
2071
2198
  };
2072
2199
  // ── executeTool ─────────────────────────────────────────────────────────
@@ -2091,6 +2218,7 @@ var RaindropTelemetryIntegration = class {
2091
2218
  this.eventShipper = opts.eventShipper;
2092
2219
  this.sendTraces = opts.sendTraces !== false;
2093
2220
  this.sendEvents = opts.sendEvents !== false;
2221
+ this.subagentWrapping = opts.subagentWrapping !== false;
2094
2222
  this.debug = opts.debug === true;
2095
2223
  this.defaultContext = opts.context;
2096
2224
  }
@@ -2172,9 +2300,20 @@ var RaindropTelemetryIntegration = class {
2172
2300
  // (see https://github.com/vercel/ai/pull/14589). Event shape is identical.
2173
2301
  // Both names are exposed and forward to a single implementation.
2174
2302
  toolExecutionStart(event) {
2303
+ const { toolCall } = event;
2304
+ const priorParent = getCurrentParentToolContext();
2305
+ this.priorParentContexts.set(
2306
+ toolCall.toolCallId,
2307
+ priorParent != null ? priorParent : null
2308
+ );
2309
+ enterParentToolContext({
2310
+ parentCallId: event.callId,
2311
+ toolCallId: toolCall.toolCallId,
2312
+ toolName: toolCall.toolName
2313
+ });
2175
2314
  const state = this.getState(event.callId);
2315
+ state == null ? void 0 : state.parentContextToolCallIds.add(toolCall.toolCallId);
2176
2316
  if (!(state == null ? void 0 : state.stepParent)) return;
2177
- const { toolCall } = event;
2178
2317
  const { operationName, resourceName } = opName(
2179
2318
  "ai.toolCall",
2180
2319
  state.functionId
@@ -2198,6 +2337,17 @@ var RaindropTelemetryIntegration = class {
2198
2337
  this.emitLive(state, "tool_start", toolCall.toolName, { args: toolCall.input });
2199
2338
  }
2200
2339
  toolExecutionEnd(event) {
2340
+ var _a;
2341
+ const toolCallId = (_a = event.toolCall) == null ? void 0 : _a.toolCallId;
2342
+ if (toolCallId && this.priorParentContexts.has(toolCallId)) {
2343
+ const prior = this.priorParentContexts.get(toolCallId);
2344
+ this.priorParentContexts.delete(toolCallId);
2345
+ if (prior) {
2346
+ enterParentToolContext(prior);
2347
+ } else {
2348
+ clearParentToolContext();
2349
+ }
2350
+ }
2201
2351
  const state = this.getState(event.callId);
2202
2352
  if (!state) return;
2203
2353
  const toolSpan = state.toolSpans.get(event.toolCall.toolCallId);
@@ -2261,7 +2411,8 @@ var RaindropTelemetryIntegration = class {
2261
2411
  );
2262
2412
  this.traceShipper.endSpan(state.rootSpan, { attributes: outputAttrs });
2263
2413
  }
2264
- if (this.sendEvents) {
2414
+ const suppressSubagentEvent = state.subagentName !== void 0 && state.subagentToolCallSpan !== void 0;
2415
+ if (this.sendEvents && !suppressSubagentEvent) {
2265
2416
  const callMeta = this.extractRaindropMetadata(state.metadata);
2266
2417
  const userId = (_f = callMeta.userId) != null ? _f : (_e = this.defaultContext) == null ? void 0 : _e.userId;
2267
2418
  if (userId) {
@@ -4423,12 +4574,16 @@ function createRaindropAISDK(opts) {
4423
4574
  const writeKey = opts.writeKey;
4424
4575
  const eventsRequested = ((_a = opts.events) == null ? void 0 : _a.enabled) !== false;
4425
4576
  const tracesRequested = ((_b = opts.traces) == null ? void 0 : _b.enabled) !== false;
4426
- const eventsEnabled = eventsRequested && !!writeKey;
4427
- const tracesEnabled = tracesRequested && !!writeKey;
4428
4577
  const envDebug = envDebugEnabled();
4429
- if (!writeKey && (eventsRequested || tracesRequested)) {
4578
+ const localWorkshopInput = opts.localWorkshopUrl === false ? null : opts.localWorkshopUrl;
4579
+ const resolvedLocalDebuggerUrl = resolveLocalDebuggerBaseUrl(localWorkshopInput);
4580
+ const localDebuggerUrl = localWorkshopInput === null ? null : resolvedLocalDebuggerUrl != null ? resolvedLocalDebuggerUrl : void 0;
4581
+ const hasDestination = !!writeKey || !!resolvedLocalDebuggerUrl;
4582
+ const eventsEnabled = eventsRequested && hasDestination;
4583
+ const tracesEnabled = tracesRequested && hasDestination;
4584
+ if (!hasDestination && (eventsRequested || tracesRequested)) {
4430
4585
  console.warn(
4431
- "[raindrop-ai/ai-sdk] writeKey not provided; telemetry shipping is disabled"
4586
+ "[raindrop-ai/ai-sdk] writeKey not provided and no local Workshop reachable; telemetry shipping is disabled"
4432
4587
  );
4433
4588
  }
4434
4589
  const eventShipper = new EventShipper2({
@@ -4436,9 +4591,9 @@ function createRaindropAISDK(opts) {
4436
4591
  endpoint: opts.endpoint,
4437
4592
  enabled: eventsEnabled,
4438
4593
  debug: ((_c = opts.events) == null ? void 0 : _c.debug) === true || envDebug,
4439
- partialFlushMs: (_d = opts.events) == null ? void 0 : _d.partialFlushMs
4594
+ partialFlushMs: (_d = opts.events) == null ? void 0 : _d.partialFlushMs,
4595
+ localDebuggerUrl
4440
4596
  });
4441
- const localDebuggerUrl = opts.localWorkshopUrl === false ? null : opts.localWorkshopUrl;
4442
4597
  const traceShipper = new TraceShipper2({
4443
4598
  writeKey,
4444
4599
  endpoint: opts.endpoint,
@@ -4460,12 +4615,30 @@ function createRaindropAISDK(opts) {
4460
4615
  traceShipper
4461
4616
  });
4462
4617
  },
4463
- createTelemetryIntegration(context) {
4618
+ createTelemetryIntegration(contextOrOptions) {
4619
+ const FLAT_CONTEXT_KEYS = [
4620
+ "userId",
4621
+ "eventId",
4622
+ "eventName",
4623
+ "convoId",
4624
+ "properties"
4625
+ ];
4626
+ let context;
4627
+ let subagentWrapping;
4628
+ if (contextOrOptions === void 0) ; else if ("context" in contextOrOptions) {
4629
+ context = contextOrOptions.context;
4630
+ subagentWrapping = contextOrOptions.subagentWrapping;
4631
+ } else if ("subagentWrapping" in contextOrOptions && !FLAT_CONTEXT_KEYS.some((k) => k in contextOrOptions)) {
4632
+ subagentWrapping = contextOrOptions.subagentWrapping;
4633
+ } else {
4634
+ context = contextOrOptions;
4635
+ }
4464
4636
  return new RaindropTelemetryIntegration({
4465
4637
  traceShipper,
4466
4638
  eventShipper,
4467
4639
  sendTraces: tracesEnabled,
4468
4640
  sendEvents: eventsEnabled,
4641
+ subagentWrapping,
4469
4642
  debug: envDebug,
4470
4643
  context
4471
4644
  });
@@ -4577,17 +4750,22 @@ exports.DEFAULT_REDACT_ATTRIBUTE_KEYS = DEFAULT_REDACT_ATTRIBUTE_KEYS;
4577
4750
  exports.DEFAULT_SECRET_KEY_NAMES = DEFAULT_SECRET_KEY_NAMES;
4578
4751
  exports.REDACTED_PLACEHOLDER = REDACTED_PLACEHOLDER;
4579
4752
  exports.RaindropTelemetryIntegration = RaindropTelemetryIntegration;
4753
+ exports._resetParentToolContextStorage = _resetParentToolContextStorage;
4580
4754
  exports._resetRaindropCallMetadataStorage = _resetRaindropCallMetadataStorage;
4581
4755
  exports._resetWarnedMissingUserId = _resetWarnedMissingUserId;
4756
+ exports.clearParentToolContext = clearParentToolContext;
4582
4757
  exports.createRaindropAISDK = createRaindropAISDK;
4583
4758
  exports.currentSpan = currentSpan;
4584
4759
  exports.defaultTransformSpan = defaultTransformSpan;
4760
+ exports.enterParentToolContext = enterParentToolContext;
4585
4761
  exports.eventMetadata = eventMetadata;
4586
4762
  exports.eventMetadataFromChatRequest = eventMetadataFromChatRequest;
4587
4763
  exports.getContextManager = getContextManager;
4764
+ exports.getCurrentParentToolContext = getCurrentParentToolContext;
4588
4765
  exports.getCurrentRaindropCallMetadata = getCurrentRaindropCallMetadata;
4589
4766
  exports.readRaindropCallMetadataFromArgs = readRaindropCallMetadataFromArgs;
4590
4767
  exports.redactJsonAttributeValue = redactJsonAttributeValue;
4591
4768
  exports.redactSecretsInObject = redactSecretsInObject;
4769
+ exports.runWithParentToolContext = runWithParentToolContext;
4592
4770
  exports.runWithRaindropCallMetadata = runWithRaindropCallMetadata;
4593
4771
  exports.withCurrent = withCurrent;