@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.
@@ -1024,7 +1024,7 @@ globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = async_hooks.AsyncLocalStorage;
1024
1024
  // package.json
1025
1025
  var package_default = {
1026
1026
  name: "@raindrop-ai/ai-sdk",
1027
- version: "0.0.29"};
1027
+ version: "0.0.31"};
1028
1028
 
1029
1029
  // src/internal/version.ts
1030
1030
  var libraryName = package_default.name;
@@ -1740,13 +1740,76 @@ function readRaindropCallMetadataFromArgs(args) {
1740
1740
  return meta;
1741
1741
  }
1742
1742
 
1743
+ // src/internal/parent-tool-context.ts
1744
+ var SyncFallbackStorage2 = class {
1745
+ constructor() {
1746
+ this._stack = [];
1747
+ }
1748
+ getStore() {
1749
+ return this._stack[this._stack.length - 1];
1750
+ }
1751
+ run(store, callback) {
1752
+ this._stack.push(store);
1753
+ try {
1754
+ return callback();
1755
+ } finally {
1756
+ this._stack.pop();
1757
+ }
1758
+ }
1759
+ // `enterWith` is intentionally absent on the sync fallback — the
1760
+ // event-driven enter/clear pattern only makes sense when the runtime
1761
+ // can propagate state across awaits, which the sync stack cannot.
1762
+ };
1763
+ var _storage2 = null;
1764
+ function getStorage2() {
1765
+ if (_storage2) return _storage2;
1766
+ const Ctor = globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
1767
+ _storage2 = Ctor ? new Ctor() : new SyncFallbackStorage2();
1768
+ return _storage2;
1769
+ }
1770
+ function _resetParentToolContextStorage() {
1771
+ _storage2 = null;
1772
+ }
1773
+ function getCurrentParentToolContext() {
1774
+ return getStorage2().getStore();
1775
+ }
1776
+ function enterParentToolContext(ctx) {
1777
+ var _a;
1778
+ const storage = getStorage2();
1779
+ (_a = storage.enterWith) == null ? void 0 : _a.call(storage, ctx);
1780
+ }
1781
+ function clearParentToolContext() {
1782
+ var _a;
1783
+ const storage = getStorage2();
1784
+ (_a = storage.enterWith) == null ? void 0 : _a.call(storage, void 0);
1785
+ }
1786
+ function runWithParentToolContext(ctx, fn) {
1787
+ return getStorage2().run(ctx, fn);
1788
+ }
1789
+
1743
1790
  // src/internal/raindrop-telemetry-integration.ts
1744
1791
  var RaindropTelemetryIntegration = class {
1745
1792
  constructor(opts) {
1746
1793
  this.callStates = /* @__PURE__ */ new Map();
1794
+ /**
1795
+ * Per-tool-call snapshot of the parent-tool ALS context taken right
1796
+ * before `enterParentToolContext` overwrites it in `toolExecutionStart`.
1797
+ * Kept at the integration level (rather than on `CallState`) so the
1798
+ * snapshot survives even when the parent generation has no tracked
1799
+ * `CallState` — e.g. the AI SDK dispatches a tool callback for a
1800
+ * `callId` we never registered via `onStart`. Without this, the
1801
+ * unconditional ALS enter in `toolExecutionStart` would leave
1802
+ * `toolExecutionEnd` no way to restore the prior context, so it would
1803
+ * clear and wipe whatever the outer scope had set.
1804
+ *
1805
+ * Keyed by `toolCallId` because that's the only identifier guaranteed
1806
+ * to round-trip between `toolExecutionStart` and `toolExecutionEnd`
1807
+ * (the `event.callId` can be the same for parallel sibling tools).
1808
+ */
1809
+ this.priorParentContexts = /* @__PURE__ */ new Map();
1747
1810
  // ── onStart ─────────────────────────────────────────────────────────────
1748
1811
  this.onStart = (event) => {
1749
- var _a, _b, _c, _d;
1812
+ var _a, _b, _c, _d, _e;
1750
1813
  if (event.isEnabled === false) return;
1751
1814
  const isEmbed = event.operationId === "ai.embed" || event.operationId === "ai.embedMany";
1752
1815
  const recordInputs = event.recordInputs !== false;
@@ -1765,6 +1828,47 @@ var RaindropTelemetryIntegration = class {
1765
1828
  event.operationId,
1766
1829
  functionId
1767
1830
  );
1831
+ const parentToolContext = !isEmbed && this.subagentWrapping ? getCurrentParentToolContext() : void 0;
1832
+ 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;
1833
+ const subagentName = (_e = parentToolContext == null ? void 0 : parentToolContext.toolName) != null ? _e : metadataSubagentName;
1834
+ let subagentToolCallSpan;
1835
+ let rootParentOverride;
1836
+ if (subagentName && this.sendTraces) {
1837
+ const parentAttrs = parentToolContext ? [
1838
+ attrString("raindrop.parent.callId", parentToolContext.parentCallId),
1839
+ attrString("raindrop.parent.toolCallId", parentToolContext.toolCallId),
1840
+ attrString("raindrop.parent.toolName", parentToolContext.toolName)
1841
+ ] : [];
1842
+ subagentToolCallSpan = this.traceShipper.startSpan({
1843
+ name: subagentName,
1844
+ parent: inheritedParent,
1845
+ eventId,
1846
+ operationId: "ai.toolCall",
1847
+ attributes: [
1848
+ attrString("operation.name", "ai.toolCall"),
1849
+ attrString("resource.name", subagentName),
1850
+ attrString("raindrop.span.kind", "tool_call"),
1851
+ attrString("ai.toolCall.name", subagentName),
1852
+ attrString("raindrop.subagent.name", subagentName),
1853
+ attrString("raindrop.agent.role", "subagent"),
1854
+ ...parentAttrs
1855
+ ]
1856
+ });
1857
+ const subagentParentRef = this.spanParentRef(subagentToolCallSpan);
1858
+ const markerSpan = this.traceShipper.startSpan({
1859
+ name: "agent.subagent",
1860
+ parent: subagentParentRef,
1861
+ eventId,
1862
+ operationId: "agent.subagent",
1863
+ attributes: [
1864
+ attrString("operation.name", "agent.subagent"),
1865
+ attrString("raindrop.span.kind", "llm_call"),
1866
+ attrString("raindrop.subagent.name", subagentName)
1867
+ ]
1868
+ });
1869
+ this.traceShipper.endSpan(markerSpan);
1870
+ rootParentOverride = subagentParentRef;
1871
+ }
1768
1872
  let rootSpan;
1769
1873
  if (this.sendTraces) {
1770
1874
  const promptAttrs = !isEmbed && recordInputs ? [
@@ -1785,7 +1889,7 @@ var RaindropTelemetryIntegration = class {
1785
1889
  ] : [attrString("ai.value", safeJsonWithUint8(event.value))] : [];
1786
1890
  rootSpan = this.traceShipper.startSpan({
1787
1891
  name: event.operationId,
1788
- parent: inheritedParent,
1892
+ parent: rootParentOverride != null ? rootParentOverride : inheritedParent,
1789
1893
  eventId,
1790
1894
  operationId: event.operationId,
1791
1895
  attributes: [
@@ -1813,18 +1917,21 @@ var RaindropTelemetryIntegration = class {
1813
1917
  operationId: event.operationId,
1814
1918
  eventId,
1815
1919
  rootSpan,
1816
- rootParent: rootSpan ? this.spanParentRef(rootSpan) : inheritedParent,
1920
+ rootParent: rootSpan ? this.spanParentRef(rootSpan) : rootParentOverride != null ? rootParentOverride : inheritedParent,
1817
1921
  stepSpan: void 0,
1818
1922
  stepParent: void 0,
1819
1923
  toolSpans: /* @__PURE__ */ new Map(),
1820
1924
  embedSpans: /* @__PURE__ */ new Map(),
1925
+ parentContextToolCallIds: /* @__PURE__ */ new Set(),
1821
1926
  recordInputs,
1822
1927
  recordOutputs,
1823
1928
  functionId,
1824
1929
  metadata,
1825
1930
  accumulatedText: "",
1826
1931
  inputText: isEmbed ? void 0 : this.extractInputText(event),
1827
- toolCallCount: 0
1932
+ toolCallCount: 0,
1933
+ subagentName,
1934
+ subagentToolCallSpan
1828
1935
  });
1829
1936
  };
1830
1937
  // ── onStepStart ─────────────────────────────────────────────────────────
@@ -2038,6 +2145,10 @@ var RaindropTelemetryIntegration = class {
2038
2145
  this.traceShipper.endSpan(embedSpan, { attributes: outputAttrs });
2039
2146
  state.embedSpans.delete(event.embedCallId);
2040
2147
  };
2148
+ // v7 canary.159 renamed `onEmbedFinish` -> `onEmbedEnd`. Both names forward
2149
+ // to the same implementation; the installed SDK only wires up whichever it
2150
+ // knows about, so there is no double dispatch.
2151
+ this.onEmbedEnd = (event) => this.onEmbedFinish(event);
2041
2152
  // ── onFinish ────────────────────────────────────────────────────────────
2042
2153
  this.onFinish = (event) => {
2043
2154
  const state = this.getState(event.callId);
@@ -2048,8 +2159,17 @@ var RaindropTelemetryIntegration = class {
2048
2159
  } else {
2049
2160
  this.finishGenerate(event, state);
2050
2161
  }
2162
+ if (state.subagentToolCallSpan) {
2163
+ this.traceShipper.endSpan(state.subagentToolCallSpan);
2164
+ }
2051
2165
  this.cleanup(event.callId);
2052
2166
  };
2167
+ // v7 < canary.159 dispatched `onFinish` as the operation finalizer; canary.159
2168
+ // renamed it to `onEnd` (the same change renamed onEmbedFinish -> onEmbedEnd
2169
+ // and onRerankFinish -> onRerankEnd). The event shape is unchanged, so this
2170
+ // is a thin alias to one implementation. The installed SDK wires up whichever
2171
+ // name it knows about, so old and new names never double dispatch.
2172
+ this.onEnd = (event) => this.onFinish(event);
2053
2173
  // ── onError ─────────────────────────────────────────────────────────────
2054
2174
  this.onError = (error) => {
2055
2175
  var _a;
@@ -2065,6 +2185,10 @@ var RaindropTelemetryIntegration = class {
2065
2185
  this.traceShipper.endSpan(embedSpan, { error: actualError });
2066
2186
  }
2067
2187
  state.embedSpans.clear();
2188
+ for (const toolCallId of state.parentContextToolCallIds) {
2189
+ this.priorParentContexts.delete(toolCallId);
2190
+ }
2191
+ state.parentContextToolCallIds.clear();
2068
2192
  for (const toolSpan of state.toolSpans.values()) {
2069
2193
  this.traceShipper.endSpan(toolSpan, { error: actualError });
2070
2194
  }
@@ -2072,6 +2196,9 @@ var RaindropTelemetryIntegration = class {
2072
2196
  if (state.rootSpan) {
2073
2197
  this.traceShipper.endSpan(state.rootSpan, { error: actualError });
2074
2198
  }
2199
+ if (state.subagentToolCallSpan) {
2200
+ this.traceShipper.endSpan(state.subagentToolCallSpan, { error: actualError });
2201
+ }
2075
2202
  this.cleanup(event.callId);
2076
2203
  };
2077
2204
  // ── executeTool ─────────────────────────────────────────────────────────
@@ -2096,6 +2223,7 @@ var RaindropTelemetryIntegration = class {
2096
2223
  this.eventShipper = opts.eventShipper;
2097
2224
  this.sendTraces = opts.sendTraces !== false;
2098
2225
  this.sendEvents = opts.sendEvents !== false;
2226
+ this.subagentWrapping = opts.subagentWrapping !== false;
2099
2227
  this.debug = opts.debug === true;
2100
2228
  this.defaultContext = opts.context;
2101
2229
  }
@@ -2177,9 +2305,20 @@ var RaindropTelemetryIntegration = class {
2177
2305
  // (see https://github.com/vercel/ai/pull/14589). Event shape is identical.
2178
2306
  // Both names are exposed and forward to a single implementation.
2179
2307
  toolExecutionStart(event) {
2308
+ const { toolCall } = event;
2309
+ const priorParent = getCurrentParentToolContext();
2310
+ this.priorParentContexts.set(
2311
+ toolCall.toolCallId,
2312
+ priorParent != null ? priorParent : null
2313
+ );
2314
+ enterParentToolContext({
2315
+ parentCallId: event.callId,
2316
+ toolCallId: toolCall.toolCallId,
2317
+ toolName: toolCall.toolName
2318
+ });
2180
2319
  const state = this.getState(event.callId);
2320
+ state == null ? void 0 : state.parentContextToolCallIds.add(toolCall.toolCallId);
2181
2321
  if (!(state == null ? void 0 : state.stepParent)) return;
2182
- const { toolCall } = event;
2183
2322
  const { operationName, resourceName } = opName(
2184
2323
  "ai.toolCall",
2185
2324
  state.functionId
@@ -2203,6 +2342,17 @@ var RaindropTelemetryIntegration = class {
2203
2342
  this.emitLive(state, "tool_start", toolCall.toolName, { args: toolCall.input });
2204
2343
  }
2205
2344
  toolExecutionEnd(event) {
2345
+ var _a;
2346
+ const toolCallId = (_a = event.toolCall) == null ? void 0 : _a.toolCallId;
2347
+ if (toolCallId && this.priorParentContexts.has(toolCallId)) {
2348
+ const prior = this.priorParentContexts.get(toolCallId);
2349
+ this.priorParentContexts.delete(toolCallId);
2350
+ if (prior) {
2351
+ enterParentToolContext(prior);
2352
+ } else {
2353
+ clearParentToolContext();
2354
+ }
2355
+ }
2206
2356
  const state = this.getState(event.callId);
2207
2357
  if (!state) return;
2208
2358
  const toolSpan = state.toolSpans.get(event.toolCall.toolCallId);
@@ -2266,7 +2416,8 @@ var RaindropTelemetryIntegration = class {
2266
2416
  );
2267
2417
  this.traceShipper.endSpan(state.rootSpan, { attributes: outputAttrs });
2268
2418
  }
2269
- if (this.sendEvents) {
2419
+ const suppressSubagentEvent = state.subagentName !== void 0 && state.subagentToolCallSpan !== void 0;
2420
+ if (this.sendEvents && !suppressSubagentEvent) {
2270
2421
  const callMeta = this.extractRaindropMetadata(state.metadata);
2271
2422
  const userId = (_f = callMeta.userId) != null ? _f : (_e = this.defaultContext) == null ? void 0 : _e.userId;
2272
2423
  if (userId) {
@@ -4428,12 +4579,16 @@ function createRaindropAISDK(opts) {
4428
4579
  const writeKey = opts.writeKey;
4429
4580
  const eventsRequested = ((_a = opts.events) == null ? void 0 : _a.enabled) !== false;
4430
4581
  const tracesRequested = ((_b = opts.traces) == null ? void 0 : _b.enabled) !== false;
4431
- const eventsEnabled = eventsRequested && !!writeKey;
4432
- const tracesEnabled = tracesRequested && !!writeKey;
4433
4582
  const envDebug = envDebugEnabled();
4434
- if (!writeKey && (eventsRequested || tracesRequested)) {
4583
+ const localWorkshopInput = opts.localWorkshopUrl === false ? null : opts.localWorkshopUrl;
4584
+ const resolvedLocalDebuggerUrl = resolveLocalDebuggerBaseUrl(localWorkshopInput);
4585
+ const localDebuggerUrl = localWorkshopInput === null ? null : resolvedLocalDebuggerUrl != null ? resolvedLocalDebuggerUrl : void 0;
4586
+ const hasDestination = !!writeKey || !!resolvedLocalDebuggerUrl;
4587
+ const eventsEnabled = eventsRequested && hasDestination;
4588
+ const tracesEnabled = tracesRequested && hasDestination;
4589
+ if (!hasDestination && (eventsRequested || tracesRequested)) {
4435
4590
  console.warn(
4436
- "[raindrop-ai/ai-sdk] writeKey not provided; telemetry shipping is disabled"
4591
+ "[raindrop-ai/ai-sdk] writeKey not provided and no local Workshop reachable; telemetry shipping is disabled"
4437
4592
  );
4438
4593
  }
4439
4594
  const eventShipper = new EventShipper2({
@@ -4441,9 +4596,9 @@ function createRaindropAISDK(opts) {
4441
4596
  endpoint: opts.endpoint,
4442
4597
  enabled: eventsEnabled,
4443
4598
  debug: ((_c = opts.events) == null ? void 0 : _c.debug) === true || envDebug,
4444
- partialFlushMs: (_d = opts.events) == null ? void 0 : _d.partialFlushMs
4599
+ partialFlushMs: (_d = opts.events) == null ? void 0 : _d.partialFlushMs,
4600
+ localDebuggerUrl
4445
4601
  });
4446
- const localDebuggerUrl = opts.localWorkshopUrl === false ? null : opts.localWorkshopUrl;
4447
4602
  const traceShipper = new TraceShipper2({
4448
4603
  writeKey,
4449
4604
  endpoint: opts.endpoint,
@@ -4465,12 +4620,30 @@ function createRaindropAISDK(opts) {
4465
4620
  traceShipper
4466
4621
  });
4467
4622
  },
4468
- createTelemetryIntegration(context) {
4623
+ createTelemetryIntegration(contextOrOptions) {
4624
+ const FLAT_CONTEXT_KEYS = [
4625
+ "userId",
4626
+ "eventId",
4627
+ "eventName",
4628
+ "convoId",
4629
+ "properties"
4630
+ ];
4631
+ let context;
4632
+ let subagentWrapping;
4633
+ if (contextOrOptions === void 0) ; else if ("context" in contextOrOptions) {
4634
+ context = contextOrOptions.context;
4635
+ subagentWrapping = contextOrOptions.subagentWrapping;
4636
+ } else if ("subagentWrapping" in contextOrOptions && !FLAT_CONTEXT_KEYS.some((k) => k in contextOrOptions)) {
4637
+ subagentWrapping = contextOrOptions.subagentWrapping;
4638
+ } else {
4639
+ context = contextOrOptions;
4640
+ }
4469
4641
  return new RaindropTelemetryIntegration({
4470
4642
  traceShipper,
4471
4643
  eventShipper,
4472
4644
  sendTraces: tracesEnabled,
4473
4645
  sendEvents: eventsEnabled,
4646
+ subagentWrapping,
4474
4647
  debug: envDebug,
4475
4648
  context
4476
4649
  });
@@ -4587,17 +4760,22 @@ exports.DEFAULT_REDACT_ATTRIBUTE_KEYS = DEFAULT_REDACT_ATTRIBUTE_KEYS;
4587
4760
  exports.DEFAULT_SECRET_KEY_NAMES = DEFAULT_SECRET_KEY_NAMES;
4588
4761
  exports.REDACTED_PLACEHOLDER = REDACTED_PLACEHOLDER;
4589
4762
  exports.RaindropTelemetryIntegration = RaindropTelemetryIntegration;
4763
+ exports._resetParentToolContextStorage = _resetParentToolContextStorage;
4590
4764
  exports._resetRaindropCallMetadataStorage = _resetRaindropCallMetadataStorage;
4591
4765
  exports._resetWarnedMissingUserId = _resetWarnedMissingUserId;
4766
+ exports.clearParentToolContext = clearParentToolContext;
4592
4767
  exports.createRaindropAISDK = createRaindropAISDK;
4593
4768
  exports.currentSpan = currentSpan;
4594
4769
  exports.defaultTransformSpan = defaultTransformSpan;
4770
+ exports.enterParentToolContext = enterParentToolContext;
4595
4771
  exports.eventMetadata = eventMetadata;
4596
4772
  exports.eventMetadataFromChatRequest = eventMetadataFromChatRequest;
4597
4773
  exports.getContextManager = getContextManager;
4774
+ exports.getCurrentParentToolContext = getCurrentParentToolContext;
4598
4775
  exports.getCurrentRaindropCallMetadata = getCurrentRaindropCallMetadata;
4599
4776
  exports.readRaindropCallMetadataFromArgs = readRaindropCallMetadataFromArgs;
4600
4777
  exports.redactJsonAttributeValue = redactJsonAttributeValue;
4601
4778
  exports.redactSecretsInObject = redactSecretsInObject;
4779
+ exports.runWithParentToolContext = runWithParentToolContext;
4602
4780
  exports.runWithRaindropCallMetadata = runWithRaindropCallMetadata;
4603
4781
  exports.withCurrent = withCurrent;
@@ -1,4 +1,4 @@
1
- export { DEFAULT_REDACT_ATTRIBUTE_KEYS, DEFAULT_SECRET_KEY_NAMES, REDACTED_PLACEHOLDER, RaindropTelemetryIntegration, _resetRaindropCallMetadataStorage, _resetWarnedMissingUserId, createRaindropAISDK, currentSpan, defaultTransformSpan, eventMetadata, eventMetadataFromChatRequest, getContextManager, getCurrentRaindropCallMetadata, readRaindropCallMetadataFromArgs, redactJsonAttributeValue, redactSecretsInObject, runWithRaindropCallMetadata, withCurrent } from './chunk-QGI4SABN.mjs';
1
+ export { DEFAULT_REDACT_ATTRIBUTE_KEYS, DEFAULT_SECRET_KEY_NAMES, REDACTED_PLACEHOLDER, RaindropTelemetryIntegration, _resetParentToolContextStorage, _resetRaindropCallMetadataStorage, _resetWarnedMissingUserId, clearParentToolContext, createRaindropAISDK, currentSpan, defaultTransformSpan, enterParentToolContext, eventMetadata, eventMetadataFromChatRequest, getContextManager, getCurrentParentToolContext, getCurrentRaindropCallMetadata, readRaindropCallMetadataFromArgs, redactJsonAttributeValue, redactSecretsInObject, runWithParentToolContext, runWithRaindropCallMetadata, withCurrent } from './chunk-7VSCLQIX.mjs';
2
2
  import { AsyncLocalStorage } from 'async_hooks';
3
3
 
4
4
  if (!globalThis.RAINDROP_ASYNC_LOCAL_STORAGE) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@raindrop-ai/ai-sdk",
3
- "version": "0.0.29",
3
+ "version": "0.0.31",
4
4
  "description": "Standalone Vercel AI SDK integration for Raindrop (events + OTLP/HTTP JSON traces, no OTEL runtime)",
5
5
  "main": "dist/index.node.js",
6
6
  "module": "dist/index.node.mjs",
@@ -42,7 +42,7 @@
42
42
  "tsup": "^8.4.0",
43
43
  "tsx": "^4.20.3",
44
44
  "typescript": "^5.3.3",
45
- "@raindrop-ai/core": "0.0.1"
45
+ "@raindrop-ai/core": "0.0.2"
46
46
  },
47
47
  "peerDependencies": {
48
48
  "ai": ">=4 <8"