@raindrop-ai/ai-sdk 0.0.28 → 0.0.30

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.
@@ -4,7 +4,7 @@ var async_hooks = require('async_hooks');
4
4
 
5
5
  // src/index.node.ts
6
6
 
7
- // ../core/dist/chunk-LMIWKHOH.js
7
+ // ../core/dist/chunk-VUNUOE2X.js
8
8
  function getCrypto() {
9
9
  const c = globalThis.crypto;
10
10
  return c;
@@ -227,6 +227,114 @@ function buildExportTraceServiceRequest(spans, serviceName = "raindrop.core", se
227
227
  ]
228
228
  };
229
229
  }
230
+ var LOCAL_DEBUGGER_ENV_VAR = "RAINDROP_LOCAL_DEBUGGER";
231
+ var WORKSHOP_ENV_VAR = "RAINDROP_WORKSHOP";
232
+ var DEFAULT_LOCAL_WORKSHOP_URL = "http://localhost:5899/v1/";
233
+ function readEnvVar(name) {
234
+ var _a;
235
+ try {
236
+ const env = (_a = globalThis == null ? void 0 : globalThis.process) == null ? void 0 : _a.env;
237
+ if (env && typeof env[name] === "string" && env[name].length > 0) {
238
+ return env[name];
239
+ }
240
+ } catch (e) {
241
+ }
242
+ return void 0;
243
+ }
244
+ function readWorkshopEnv() {
245
+ const raw = readEnvVar(WORKSHOP_ENV_VAR);
246
+ if (raw === void 0) return void 0;
247
+ const trimmed = raw.trim();
248
+ if (trimmed.length === 0) return void 0;
249
+ if (/^https?:\/\//i.test(trimmed)) return { url: trimmed };
250
+ if (/^(1|true|yes|on)$/i.test(trimmed)) return "enable";
251
+ if (/^(0|false|no|off)$/i.test(trimmed)) return "disable";
252
+ return void 0;
253
+ }
254
+ function isLocalDevHost(hostname) {
255
+ if (!hostname) return false;
256
+ if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "0.0.0.0" || hostname === "::1") {
257
+ return true;
258
+ }
259
+ if (hostname.endsWith(".localhost")) return true;
260
+ return false;
261
+ }
262
+ function readRuntimeHostname() {
263
+ try {
264
+ const loc = globalThis == null ? void 0 : globalThis.location;
265
+ if (loc && typeof loc.hostname === "string" && loc.hostname.length > 0) {
266
+ return loc.hostname;
267
+ }
268
+ } catch (e) {
269
+ }
270
+ return void 0;
271
+ }
272
+ function shouldAutoEnableLocalWorkshop() {
273
+ if (isLocalDevHost(readRuntimeHostname())) return true;
274
+ if (readEnvVar("NODE_ENV") === "development") return true;
275
+ return false;
276
+ }
277
+ function resolveLocalDebuggerBaseUrl(baseUrl) {
278
+ var _a, _b, _c;
279
+ if (baseUrl === null) return null;
280
+ if (typeof baseUrl === "string" && baseUrl.length > 0) {
281
+ return (_a = formatEndpoint(baseUrl)) != null ? _a : null;
282
+ }
283
+ const explicitUrlEnv = readEnvVar(LOCAL_DEBUGGER_ENV_VAR);
284
+ if (explicitUrlEnv) return (_b = formatEndpoint(explicitUrlEnv)) != null ? _b : null;
285
+ const workshopEnv = readWorkshopEnv();
286
+ if (workshopEnv === "disable") return null;
287
+ if (workshopEnv === "enable") return DEFAULT_LOCAL_WORKSHOP_URL;
288
+ if (workshopEnv && "url" in workshopEnv) return (_c = formatEndpoint(workshopEnv.url)) != null ? _c : null;
289
+ if (shouldAutoEnableLocalWorkshop()) return DEFAULT_LOCAL_WORKSHOP_URL;
290
+ return null;
291
+ }
292
+ function localDebuggerEnabled(baseUrl) {
293
+ return resolveLocalDebuggerBaseUrl(baseUrl) !== null;
294
+ }
295
+ function mirrorTraceExportToLocalDebugger(body, options = {}) {
296
+ var _a;
297
+ const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
298
+ if (!baseUrl) return;
299
+ void postJson(`${baseUrl}traces`, body, {}, {
300
+ maxAttempts: 1,
301
+ debug: (_a = options.debug) != null ? _a : false,
302
+ sdkName: options.sdkName
303
+ }).catch(() => {
304
+ });
305
+ }
306
+ function mirrorPartialEventToLocalDebugger(event, options = {}) {
307
+ var _a;
308
+ const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
309
+ if (!baseUrl) return;
310
+ const headers = options.writeKey ? { Authorization: `Bearer ${options.writeKey}` } : {};
311
+ void postJson(`${baseUrl}events/track_partial`, event, headers, {
312
+ maxAttempts: 1,
313
+ debug: (_a = options.debug) != null ? _a : false,
314
+ sdkName: options.sdkName
315
+ }).catch(() => {
316
+ });
317
+ }
318
+ function sendLocalDebuggerLiveEvent(event, options = {}) {
319
+ var _a, _b;
320
+ const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
321
+ if (!baseUrl) return;
322
+ void postJson(
323
+ `${baseUrl}live`,
324
+ {
325
+ ...event,
326
+ type: event.type,
327
+ timestamp: (_a = event.timestamp) != null ? _a : Date.now()
328
+ },
329
+ {},
330
+ {
331
+ maxAttempts: 1,
332
+ debug: (_b = options.debug) != null ? _b : false,
333
+ sdkName: options.sdkName
334
+ }
335
+ ).catch(() => {
336
+ });
337
+ }
230
338
  function mergePatches(target, source) {
231
339
  var _a, _b, _c, _d;
232
340
  const out = { ...target, ...source };
@@ -244,7 +352,7 @@ var EventShipper = class {
244
352
  this.sticky = /* @__PURE__ */ new Map();
245
353
  this.timers = /* @__PURE__ */ new Map();
246
354
  this.inFlight = /* @__PURE__ */ new Set();
247
- var _a, _b, _c, _d, _e, _f, _g;
355
+ var _a, _b, _c, _d, _e, _f, _g, _h;
248
356
  this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
249
357
  this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
250
358
  this.enabled = opts.enabled !== false;
@@ -253,11 +361,15 @@ var EventShipper = class {
253
361
  this.sdkName = (_d = opts.sdkName) != null ? _d : "core";
254
362
  this.prefix = `[raindrop-ai/${this.sdkName}]`;
255
363
  this.defaultEventName = (_e = opts.defaultEventName) != null ? _e : "ai_generation";
364
+ this.localDebuggerUrl = (_f = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _f : void 0;
365
+ if (this.debug && this.localDebuggerUrl) {
366
+ console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
367
+ }
256
368
  const isNode = typeof process !== "undefined" && typeof process.version === "string";
257
369
  this.context = {
258
370
  library: {
259
- name: (_f = opts.libraryName) != null ? _f : "@raindrop-ai/core",
260
- version: (_g = opts.libraryVersion) != null ? _g : "0.0.0"
371
+ name: (_g = opts.libraryName) != null ? _g : "@raindrop-ai/core",
372
+ version: (_h = opts.libraryVersion) != null ? _h : "0.0.0"
261
373
  },
262
374
  metadata: {
263
375
  jsRuntime: isNode ? "node" : "web",
@@ -343,6 +455,7 @@ var EventShipper = class {
343
455
  }
344
456
  }
345
457
  ];
458
+ if (!this.writeKey) return;
346
459
  const url = `${this.baseUrl}signals/track`;
347
460
  try {
348
461
  await postJson(url, body, this.authHeaders(), {
@@ -373,6 +486,7 @@ var EventShipper = class {
373
486
  traits: (_a = user.traits) != null ? _a : {}
374
487
  };
375
488
  });
489
+ if (!this.writeKey) return;
376
490
  if (body.length === 0) return;
377
491
  const url = `${this.baseUrl}users/identify`;
378
492
  try {
@@ -449,6 +563,18 @@ var EventShipper = class {
449
563
  endpoint: url
450
564
  });
451
565
  }
566
+ if (this.localDebuggerUrl) {
567
+ mirrorPartialEventToLocalDebugger(payload, {
568
+ baseUrl: this.localDebuggerUrl,
569
+ writeKey: this.writeKey,
570
+ debug: this.debug,
571
+ sdkName: this.sdkName
572
+ });
573
+ }
574
+ if (!this.writeKey) {
575
+ if (!isPending) this.sticky.delete(eventId);
576
+ return;
577
+ }
452
578
  const p = postJson(url, payload, this.authHeaders(), {
453
579
  maxAttempts: 3,
454
580
  debug: this.debug,
@@ -473,101 +599,94 @@ var EventShipper = class {
473
599
  }
474
600
  }
475
601
  };
476
- var LOCAL_DEBUGGER_ENV_VAR = "RAINDROP_LOCAL_DEBUGGER";
477
- var WORKSHOP_ENV_VAR = "RAINDROP_WORKSHOP";
478
- var DEFAULT_LOCAL_WORKSHOP_URL = "http://localhost:5899/v1/";
479
- function readEnvVar(name) {
480
- var _a;
481
- try {
482
- const env = (_a = globalThis == null ? void 0 : globalThis.process) == null ? void 0 : _a.env;
483
- if (env && typeof env[name] === "string" && env[name].length > 0) {
484
- return env[name];
602
+ var DEFAULT_SECRET_KEY_NAMES = [
603
+ "apikey",
604
+ "apisecret",
605
+ "apitoken",
606
+ "secretaccesskey",
607
+ "sessiontoken",
608
+ "privatekey",
609
+ "privatekeyid",
610
+ "clientsecret",
611
+ "accesstoken",
612
+ "refreshtoken",
613
+ "oauthtoken",
614
+ "bearertoken",
615
+ "authorization",
616
+ "password",
617
+ "passphrase"
618
+ ];
619
+ var REDACTED_PLACEHOLDER = "[REDACTED]";
620
+ function normalizeKeyName(name) {
621
+ return name.toLowerCase().replace(/[-_.]/g, "");
622
+ }
623
+ function redactSecretsInObject(value, options) {
624
+ var _a, _b;
625
+ const normalizedSecretSet = buildSecretSet((_a = options == null ? void 0 : options.secretKeyNames) != null ? _a : DEFAULT_SECRET_KEY_NAMES);
626
+ const placeholder = (_b = options == null ? void 0 : options.placeholder) != null ? _b : REDACTED_PLACEHOLDER;
627
+ const seen = /* @__PURE__ */ new WeakSet();
628
+ const walk = (node) => {
629
+ if (node === null || typeof node !== "object") return node;
630
+ if (seen.has(node)) return "[CIRCULAR]";
631
+ seen.add(node);
632
+ if (Array.isArray(node)) {
633
+ return node.map((item) => walk(item));
485
634
  }
635
+ const out = {};
636
+ for (const [k, v] of Object.entries(node)) {
637
+ if (normalizedSecretSet.has(normalizeKeyName(k))) {
638
+ out[k] = placeholder;
639
+ } else {
640
+ out[k] = walk(v);
641
+ }
642
+ }
643
+ return out;
644
+ };
645
+ return walk(value);
646
+ }
647
+ function buildSecretSet(names) {
648
+ const set = /* @__PURE__ */ new Set();
649
+ for (const name of names) set.add(normalizeKeyName(name));
650
+ return set;
651
+ }
652
+ var DEFAULT_REDACT_ATTRIBUTE_KEYS = [
653
+ "ai.request.providerOptions",
654
+ "ai.response.providerMetadata"
655
+ ];
656
+ function defaultTransformSpan(span) {
657
+ const attrs = span.attributes;
658
+ if (!attrs || attrs.length === 0) return span;
659
+ let nextAttrs;
660
+ for (let i = 0; i < attrs.length; i++) {
661
+ const attr = attrs[i];
662
+ const redacted = redactJsonAttributeValue(attr.key, attr.value);
663
+ if (redacted === void 0) continue;
664
+ if (!nextAttrs) nextAttrs = attrs.slice();
665
+ nextAttrs[i] = { key: attr.key, value: redacted };
666
+ }
667
+ if (!nextAttrs) return span;
668
+ return { ...span, attributes: nextAttrs };
669
+ }
670
+ var REDACT_JSON_ATTRIBUTE_KEYS = new Set(DEFAULT_REDACT_ATTRIBUTE_KEYS);
671
+ function redactJsonAttributeValue(key, value) {
672
+ if (!REDACT_JSON_ATTRIBUTE_KEYS.has(key)) return void 0;
673
+ const json = value.stringValue;
674
+ if (typeof json !== "string" || json.length === 0) return void 0;
675
+ let parsed;
676
+ try {
677
+ parsed = JSON.parse(json);
486
678
  } catch (e) {
679
+ return void 0;
487
680
  }
488
- return void 0;
489
- }
490
- function readWorkshopEnv() {
491
- const raw = readEnvVar(WORKSHOP_ENV_VAR);
492
- if (raw === void 0) return void 0;
493
- const trimmed = raw.trim();
494
- if (trimmed.length === 0) return void 0;
495
- if (/^https?:\/\//i.test(trimmed)) return { url: trimmed };
496
- if (/^(1|true|yes|on)$/i.test(trimmed)) return "enable";
497
- if (/^(0|false|no|off)$/i.test(trimmed)) return "disable";
498
- return void 0;
499
- }
500
- function isLocalDevHost(hostname) {
501
- if (!hostname) return false;
502
- if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "0.0.0.0" || hostname === "::1") {
503
- return true;
504
- }
505
- if (hostname.endsWith(".localhost")) return true;
506
- return false;
507
- }
508
- function readRuntimeHostname() {
681
+ const scrubbed = redactSecretsInObject(parsed);
682
+ let scrubbedJson;
509
683
  try {
510
- const loc = globalThis == null ? void 0 : globalThis.location;
511
- if (loc && typeof loc.hostname === "string" && loc.hostname.length > 0) {
512
- return loc.hostname;
513
- }
684
+ scrubbedJson = JSON.stringify(scrubbed);
514
685
  } catch (e) {
686
+ return void 0;
515
687
  }
516
- return void 0;
517
- }
518
- function shouldAutoEnableLocalWorkshop() {
519
- if (isLocalDevHost(readRuntimeHostname())) return true;
520
- if (readEnvVar("NODE_ENV") === "development") return true;
521
- return false;
522
- }
523
- function resolveLocalDebuggerBaseUrl(baseUrl) {
524
- var _a, _b, _c;
525
- if (baseUrl === null) return null;
526
- if (typeof baseUrl === "string" && baseUrl.length > 0) {
527
- return (_a = formatEndpoint(baseUrl)) != null ? _a : null;
528
- }
529
- const explicitUrlEnv = readEnvVar(LOCAL_DEBUGGER_ENV_VAR);
530
- if (explicitUrlEnv) return (_b = formatEndpoint(explicitUrlEnv)) != null ? _b : null;
531
- const workshopEnv = readWorkshopEnv();
532
- if (workshopEnv === "disable") return null;
533
- if (workshopEnv === "enable") return DEFAULT_LOCAL_WORKSHOP_URL;
534
- if (workshopEnv && "url" in workshopEnv) return (_c = formatEndpoint(workshopEnv.url)) != null ? _c : null;
535
- if (shouldAutoEnableLocalWorkshop()) return DEFAULT_LOCAL_WORKSHOP_URL;
536
- return null;
537
- }
538
- function localDebuggerEnabled(baseUrl) {
539
- return resolveLocalDebuggerBaseUrl(baseUrl) !== null;
540
- }
541
- function mirrorTraceExportToLocalDebugger(body, options = {}) {
542
- var _a;
543
- const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
544
- if (!baseUrl) return;
545
- void postJson(`${baseUrl}traces`, body, {}, {
546
- maxAttempts: 1,
547
- debug: (_a = options.debug) != null ? _a : false,
548
- sdkName: options.sdkName
549
- }).catch(() => {
550
- });
551
- }
552
- function sendLocalDebuggerLiveEvent(event, options = {}) {
553
- var _a, _b;
554
- const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
555
- if (!baseUrl) return;
556
- void postJson(
557
- `${baseUrl}live`,
558
- {
559
- ...event,
560
- type: event.type,
561
- timestamp: (_a = event.timestamp) != null ? _a : Date.now()
562
- },
563
- {},
564
- {
565
- maxAttempts: 1,
566
- debug: (_b = options.debug) != null ? _b : false,
567
- sdkName: options.sdkName
568
- }
569
- ).catch(() => {
570
- });
688
+ if (scrubbedJson === json) return void 0;
689
+ return { stringValue: scrubbedJson };
571
690
  }
572
691
  var TraceShipper = class {
573
692
  constructor(opts) {
@@ -590,6 +709,42 @@ var TraceShipper = class {
590
709
  if (this.debug && this.localDebuggerUrl) {
591
710
  console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
592
711
  }
712
+ this.transformSpanHook = opts.transformSpan;
713
+ this.disableDefaultRedaction = opts.disableDefaultRedaction === true;
714
+ }
715
+ /**
716
+ * Apply the user `transformSpan` hook (if any) followed by the default
717
+ * redactor (unless disabled). Returns either the (possibly new) span to
718
+ * ship, or `null` to drop the span entirely.
719
+ *
720
+ * Ordering: user hook runs first so callers can rewrite the span freely
721
+ * (rename attrs, add new ones, scrub things the default doesn't know
722
+ * about). The default redactor then runs on whatever the user produced,
723
+ * acting as the always-on floor for documented BYOK secrets. If the user
724
+ * sets `disableDefaultRedaction: true`, the floor is skipped.
725
+ *
726
+ * Fail-closed: if the user hook throws, the span is dropped — a buggy
727
+ * hook can never accidentally ship raw, un-redacted spans.
728
+ */
729
+ redactSpan(span) {
730
+ let current = span;
731
+ if (this.transformSpanHook) {
732
+ try {
733
+ const result = this.transformSpanHook(current);
734
+ if (result === null) return null;
735
+ if (result !== void 0) current = result;
736
+ } catch (err) {
737
+ if (this.debug) {
738
+ const msg = err instanceof Error ? err.message : String(err);
739
+ console.warn(`${this.prefix} transformSpan hook threw: ${msg}`);
740
+ }
741
+ return null;
742
+ }
743
+ }
744
+ if (!this.disableDefaultRedaction) {
745
+ current = defaultTransformSpan(current);
746
+ }
747
+ return current;
593
748
  }
594
749
  isDebugEnabled() {
595
750
  return this.debug;
@@ -607,8 +762,8 @@ var TraceShipper = class {
607
762
  ];
608
763
  if ((_b = args.attributes) == null ? void 0 : _b.length) attrs.push(...args.attributes);
609
764
  const span = { ids, name: args.name, startTimeUnixNano: started, attributes: attrs };
610
- if (this.localDebuggerUrl) {
611
- const openSpan = buildOtlpSpan({
765
+ this.mirrorToLocalDebugger(
766
+ buildOtlpSpan({
612
767
  ids: span.ids,
613
768
  name: span.name,
614
769
  startTimeUnixNano: span.startTimeUnixNano,
@@ -616,16 +771,21 @@ var TraceShipper = class {
616
771
  // placeholder — will be updated on endSpan
617
772
  attributes: span.attributes,
618
773
  status: { code: SpanStatusCode.UNSET }
619
- });
620
- const body = buildExportTraceServiceRequest([openSpan], this.serviceName, this.serviceVersion);
621
- mirrorTraceExportToLocalDebugger(body, {
622
- baseUrl: this.localDebuggerUrl,
623
- debug: false,
624
- sdkName: this.sdkName
625
- });
626
- }
774
+ })
775
+ );
627
776
  return span;
628
777
  }
778
+ mirrorToLocalDebugger(span) {
779
+ if (!this.localDebuggerUrl) return;
780
+ const redacted = this.redactSpan(span);
781
+ if (redacted === null) return;
782
+ const body = buildExportTraceServiceRequest([redacted], this.serviceName, this.serviceVersion);
783
+ mirrorTraceExportToLocalDebugger(body, {
784
+ baseUrl: this.localDebuggerUrl,
785
+ debug: false,
786
+ sdkName: this.sdkName
787
+ });
788
+ }
629
789
  endSpan(span, extra) {
630
790
  var _a, _b;
631
791
  if (span.endTimeUnixNano) return;
@@ -647,14 +807,7 @@ var TraceShipper = class {
647
807
  status
648
808
  });
649
809
  this.enqueue(otlp);
650
- if (this.localDebuggerUrl) {
651
- const body = buildExportTraceServiceRequest([otlp], this.serviceName, this.serviceVersion);
652
- mirrorTraceExportToLocalDebugger(body, {
653
- baseUrl: this.localDebuggerUrl,
654
- debug: false,
655
- sdkName: this.sdkName
656
- });
657
- }
810
+ this.mirrorToLocalDebugger(otlp);
658
811
  }
659
812
  createSpan(args) {
660
813
  var _a;
@@ -672,14 +825,7 @@ var TraceShipper = class {
672
825
  status: args.status
673
826
  });
674
827
  this.enqueue(otlp);
675
- if (this.localDebuggerUrl) {
676
- const body = buildExportTraceServiceRequest([otlp], this.serviceName, this.serviceVersion);
677
- mirrorTraceExportToLocalDebugger(body, {
678
- baseUrl: this.localDebuggerUrl,
679
- debug: false,
680
- sdkName: this.sdkName
681
- });
682
- }
828
+ this.mirrorToLocalDebugger(otlp);
683
829
  }
684
830
  enqueue(span) {
685
831
  if (!this.enabled) return;
@@ -691,10 +837,12 @@ var TraceShipper = class {
691
837
  )}`
692
838
  );
693
839
  }
840
+ const redacted = this.redactSpan(span);
841
+ if (redacted === null) return;
694
842
  if (this.queue.length >= this.maxQueueSize) {
695
843
  this.queue.shift();
696
844
  }
697
- this.queue.push(span);
845
+ this.queue.push(redacted);
698
846
  if (this.queue.length >= this.maxBatchSize) {
699
847
  void this.flush().catch(() => {
700
848
  });
@@ -716,6 +864,7 @@ var TraceShipper = class {
716
864
  }
717
865
  while (this.queue.length > 0) {
718
866
  const batch = this.queue.splice(0, this.maxBatchSize);
867
+ if (!this.writeKey) continue;
719
868
  const body = buildExportTraceServiceRequest(batch, this.serviceName, this.serviceVersion);
720
869
  const url = `${this.baseUrl}traces`;
721
870
  if (this.debug) {
@@ -875,7 +1024,7 @@ globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = async_hooks.AsyncLocalStorage;
875
1024
  // package.json
876
1025
  var package_default = {
877
1026
  name: "@raindrop-ai/ai-sdk",
878
- version: "0.0.28"};
1027
+ version: "0.0.30"};
879
1028
 
880
1029
  // src/internal/version.ts
881
1030
  var libraryName = package_default.name;
@@ -1591,13 +1740,76 @@ function readRaindropCallMetadataFromArgs(args) {
1591
1740
  return meta;
1592
1741
  }
1593
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
+
1594
1790
  // src/internal/raindrop-telemetry-integration.ts
1595
1791
  var RaindropTelemetryIntegration = class {
1596
1792
  constructor(opts) {
1597
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();
1598
1810
  // ── onStart ─────────────────────────────────────────────────────────────
1599
1811
  this.onStart = (event) => {
1600
- var _a, _b, _c, _d;
1812
+ var _a, _b, _c, _d, _e;
1601
1813
  if (event.isEnabled === false) return;
1602
1814
  const isEmbed = event.operationId === "ai.embed" || event.operationId === "ai.embedMany";
1603
1815
  const recordInputs = event.recordInputs !== false;
@@ -1616,6 +1828,47 @@ var RaindropTelemetryIntegration = class {
1616
1828
  event.operationId,
1617
1829
  functionId
1618
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
+ }
1619
1872
  let rootSpan;
1620
1873
  if (this.sendTraces) {
1621
1874
  const promptAttrs = !isEmbed && recordInputs ? [
@@ -1636,7 +1889,7 @@ var RaindropTelemetryIntegration = class {
1636
1889
  ] : [attrString("ai.value", safeJsonWithUint8(event.value))] : [];
1637
1890
  rootSpan = this.traceShipper.startSpan({
1638
1891
  name: event.operationId,
1639
- parent: inheritedParent,
1892
+ parent: rootParentOverride != null ? rootParentOverride : inheritedParent,
1640
1893
  eventId,
1641
1894
  operationId: event.operationId,
1642
1895
  attributes: [
@@ -1664,18 +1917,21 @@ var RaindropTelemetryIntegration = class {
1664
1917
  operationId: event.operationId,
1665
1918
  eventId,
1666
1919
  rootSpan,
1667
- rootParent: rootSpan ? this.spanParentRef(rootSpan) : inheritedParent,
1920
+ rootParent: rootSpan ? this.spanParentRef(rootSpan) : rootParentOverride != null ? rootParentOverride : inheritedParent,
1668
1921
  stepSpan: void 0,
1669
1922
  stepParent: void 0,
1670
1923
  toolSpans: /* @__PURE__ */ new Map(),
1671
1924
  embedSpans: /* @__PURE__ */ new Map(),
1925
+ parentContextToolCallIds: /* @__PURE__ */ new Set(),
1672
1926
  recordInputs,
1673
1927
  recordOutputs,
1674
1928
  functionId,
1675
1929
  metadata,
1676
1930
  accumulatedText: "",
1677
1931
  inputText: isEmbed ? void 0 : this.extractInputText(event),
1678
- toolCallCount: 0
1932
+ toolCallCount: 0,
1933
+ subagentName,
1934
+ subagentToolCallSpan
1679
1935
  });
1680
1936
  };
1681
1937
  // ── onStepStart ─────────────────────────────────────────────────────────
@@ -1899,6 +2155,9 @@ var RaindropTelemetryIntegration = class {
1899
2155
  } else {
1900
2156
  this.finishGenerate(event, state);
1901
2157
  }
2158
+ if (state.subagentToolCallSpan) {
2159
+ this.traceShipper.endSpan(state.subagentToolCallSpan);
2160
+ }
1902
2161
  this.cleanup(event.callId);
1903
2162
  };
1904
2163
  // ── onError ─────────────────────────────────────────────────────────────
@@ -1916,6 +2175,10 @@ var RaindropTelemetryIntegration = class {
1916
2175
  this.traceShipper.endSpan(embedSpan, { error: actualError });
1917
2176
  }
1918
2177
  state.embedSpans.clear();
2178
+ for (const toolCallId of state.parentContextToolCallIds) {
2179
+ this.priorParentContexts.delete(toolCallId);
2180
+ }
2181
+ state.parentContextToolCallIds.clear();
1919
2182
  for (const toolSpan of state.toolSpans.values()) {
1920
2183
  this.traceShipper.endSpan(toolSpan, { error: actualError });
1921
2184
  }
@@ -1923,6 +2186,9 @@ var RaindropTelemetryIntegration = class {
1923
2186
  if (state.rootSpan) {
1924
2187
  this.traceShipper.endSpan(state.rootSpan, { error: actualError });
1925
2188
  }
2189
+ if (state.subagentToolCallSpan) {
2190
+ this.traceShipper.endSpan(state.subagentToolCallSpan, { error: actualError });
2191
+ }
1926
2192
  this.cleanup(event.callId);
1927
2193
  };
1928
2194
  // ── executeTool ─────────────────────────────────────────────────────────
@@ -1947,6 +2213,7 @@ var RaindropTelemetryIntegration = class {
1947
2213
  this.eventShipper = opts.eventShipper;
1948
2214
  this.sendTraces = opts.sendTraces !== false;
1949
2215
  this.sendEvents = opts.sendEvents !== false;
2216
+ this.subagentWrapping = opts.subagentWrapping !== false;
1950
2217
  this.debug = opts.debug === true;
1951
2218
  this.defaultContext = opts.context;
1952
2219
  }
@@ -2028,9 +2295,20 @@ var RaindropTelemetryIntegration = class {
2028
2295
  // (see https://github.com/vercel/ai/pull/14589). Event shape is identical.
2029
2296
  // Both names are exposed and forward to a single implementation.
2030
2297
  toolExecutionStart(event) {
2298
+ const { toolCall } = event;
2299
+ const priorParent = getCurrentParentToolContext();
2300
+ this.priorParentContexts.set(
2301
+ toolCall.toolCallId,
2302
+ priorParent != null ? priorParent : null
2303
+ );
2304
+ enterParentToolContext({
2305
+ parentCallId: event.callId,
2306
+ toolCallId: toolCall.toolCallId,
2307
+ toolName: toolCall.toolName
2308
+ });
2031
2309
  const state = this.getState(event.callId);
2310
+ state == null ? void 0 : state.parentContextToolCallIds.add(toolCall.toolCallId);
2032
2311
  if (!(state == null ? void 0 : state.stepParent)) return;
2033
- const { toolCall } = event;
2034
2312
  const { operationName, resourceName } = opName(
2035
2313
  "ai.toolCall",
2036
2314
  state.functionId
@@ -2054,6 +2332,17 @@ var RaindropTelemetryIntegration = class {
2054
2332
  this.emitLive(state, "tool_start", toolCall.toolName, { args: toolCall.input });
2055
2333
  }
2056
2334
  toolExecutionEnd(event) {
2335
+ var _a;
2336
+ const toolCallId = (_a = event.toolCall) == null ? void 0 : _a.toolCallId;
2337
+ if (toolCallId && this.priorParentContexts.has(toolCallId)) {
2338
+ const prior = this.priorParentContexts.get(toolCallId);
2339
+ this.priorParentContexts.delete(toolCallId);
2340
+ if (prior) {
2341
+ enterParentToolContext(prior);
2342
+ } else {
2343
+ clearParentToolContext();
2344
+ }
2345
+ }
2057
2346
  const state = this.getState(event.callId);
2058
2347
  if (!state) return;
2059
2348
  const toolSpan = state.toolSpans.get(event.toolCall.toolCallId);
@@ -2117,7 +2406,8 @@ var RaindropTelemetryIntegration = class {
2117
2406
  );
2118
2407
  this.traceShipper.endSpan(state.rootSpan, { attributes: outputAttrs });
2119
2408
  }
2120
- if (this.sendEvents) {
2409
+ const suppressSubagentEvent = state.subagentName !== void 0 && state.subagentToolCallSpan !== void 0;
2410
+ if (this.sendEvents && !suppressSubagentEvent) {
2121
2411
  const callMeta = this.extractRaindropMetadata(state.metadata);
2122
2412
  const userId = (_f = callMeta.userId) != null ? _f : (_e = this.defaultContext) == null ? void 0 : _e.userId;
2123
2413
  if (userId) {
@@ -4275,16 +4565,20 @@ function envDebugEnabled() {
4275
4565
  return flag === "1" || flag === "true";
4276
4566
  }
4277
4567
  function createRaindropAISDK(opts) {
4278
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
4568
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
4279
4569
  const writeKey = opts.writeKey;
4280
4570
  const eventsRequested = ((_a = opts.events) == null ? void 0 : _a.enabled) !== false;
4281
4571
  const tracesRequested = ((_b = opts.traces) == null ? void 0 : _b.enabled) !== false;
4282
- const eventsEnabled = eventsRequested && !!writeKey;
4283
- const tracesEnabled = tracesRequested && !!writeKey;
4284
4572
  const envDebug = envDebugEnabled();
4285
- if (!writeKey && (eventsRequested || tracesRequested)) {
4573
+ const localWorkshopInput = opts.localWorkshopUrl === false ? null : opts.localWorkshopUrl;
4574
+ const resolvedLocalDebuggerUrl = resolveLocalDebuggerBaseUrl(localWorkshopInput);
4575
+ const localDebuggerUrl = localWorkshopInput === null ? null : resolvedLocalDebuggerUrl != null ? resolvedLocalDebuggerUrl : void 0;
4576
+ const hasDestination = !!writeKey || !!resolvedLocalDebuggerUrl;
4577
+ const eventsEnabled = eventsRequested && hasDestination;
4578
+ const tracesEnabled = tracesRequested && hasDestination;
4579
+ if (!hasDestination && (eventsRequested || tracesRequested)) {
4286
4580
  console.warn(
4287
- "[raindrop-ai/ai-sdk] writeKey not provided; telemetry shipping is disabled"
4581
+ "[raindrop-ai/ai-sdk] writeKey not provided and no local Workshop reachable; telemetry shipping is disabled"
4288
4582
  );
4289
4583
  }
4290
4584
  const eventShipper = new EventShipper2({
@@ -4292,9 +4586,9 @@ function createRaindropAISDK(opts) {
4292
4586
  endpoint: opts.endpoint,
4293
4587
  enabled: eventsEnabled,
4294
4588
  debug: ((_c = opts.events) == null ? void 0 : _c.debug) === true || envDebug,
4295
- partialFlushMs: (_d = opts.events) == null ? void 0 : _d.partialFlushMs
4589
+ partialFlushMs: (_d = opts.events) == null ? void 0 : _d.partialFlushMs,
4590
+ localDebuggerUrl
4296
4591
  });
4297
- const localDebuggerUrl = opts.localWorkshopUrl === false ? null : opts.localWorkshopUrl;
4298
4592
  const traceShipper = new TraceShipper2({
4299
4593
  writeKey,
4300
4594
  endpoint: opts.endpoint,
@@ -4304,7 +4598,9 @@ function createRaindropAISDK(opts) {
4304
4598
  flushIntervalMs: (_g = opts.traces) == null ? void 0 : _g.flushIntervalMs,
4305
4599
  maxBatchSize: (_h = opts.traces) == null ? void 0 : _h.maxBatchSize,
4306
4600
  maxQueueSize: (_i = opts.traces) == null ? void 0 : _i.maxQueueSize,
4307
- localDebuggerUrl
4601
+ localDebuggerUrl,
4602
+ transformSpan: (_j = opts.traces) == null ? void 0 : _j.transformSpan,
4603
+ disableDefaultRedaction: (_k = opts.traces) == null ? void 0 : _k.disableDefaultRedaction
4308
4604
  });
4309
4605
  return {
4310
4606
  wrap(aiSDK, options) {
@@ -4314,12 +4610,30 @@ function createRaindropAISDK(opts) {
4314
4610
  traceShipper
4315
4611
  });
4316
4612
  },
4317
- createTelemetryIntegration(context) {
4613
+ createTelemetryIntegration(contextOrOptions) {
4614
+ const FLAT_CONTEXT_KEYS = [
4615
+ "userId",
4616
+ "eventId",
4617
+ "eventName",
4618
+ "convoId",
4619
+ "properties"
4620
+ ];
4621
+ let context;
4622
+ let subagentWrapping;
4623
+ if (contextOrOptions === void 0) ; else if ("context" in contextOrOptions) {
4624
+ context = contextOrOptions.context;
4625
+ subagentWrapping = contextOrOptions.subagentWrapping;
4626
+ } else if ("subagentWrapping" in contextOrOptions && !FLAT_CONTEXT_KEYS.some((k) => k in contextOrOptions)) {
4627
+ subagentWrapping = contextOrOptions.subagentWrapping;
4628
+ } else {
4629
+ context = contextOrOptions;
4630
+ }
4318
4631
  return new RaindropTelemetryIntegration({
4319
4632
  traceShipper,
4320
4633
  eventShipper,
4321
4634
  sendTraces: tracesEnabled,
4322
4635
  sendEvents: eventsEnabled,
4636
+ subagentWrapping,
4323
4637
  debug: envDebug,
4324
4638
  context
4325
4639
  });
@@ -4430,15 +4744,26 @@ function createRaindropAISDK(opts) {
4430
4744
  // src/index.node.ts
4431
4745
  globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = async_hooks.AsyncLocalStorage;
4432
4746
 
4747
+ exports.DEFAULT_REDACT_ATTRIBUTE_KEYS = DEFAULT_REDACT_ATTRIBUTE_KEYS;
4748
+ exports.DEFAULT_SECRET_KEY_NAMES = DEFAULT_SECRET_KEY_NAMES;
4749
+ exports.REDACTED_PLACEHOLDER = REDACTED_PLACEHOLDER;
4433
4750
  exports.RaindropTelemetryIntegration = RaindropTelemetryIntegration;
4751
+ exports._resetParentToolContextStorage = _resetParentToolContextStorage;
4434
4752
  exports._resetRaindropCallMetadataStorage = _resetRaindropCallMetadataStorage;
4435
4753
  exports._resetWarnedMissingUserId = _resetWarnedMissingUserId;
4754
+ exports.clearParentToolContext = clearParentToolContext;
4436
4755
  exports.createRaindropAISDK = createRaindropAISDK;
4437
4756
  exports.currentSpan = currentSpan;
4757
+ exports.defaultTransformSpan = defaultTransformSpan;
4758
+ exports.enterParentToolContext = enterParentToolContext;
4438
4759
  exports.eventMetadata = eventMetadata;
4439
4760
  exports.eventMetadataFromChatRequest = eventMetadataFromChatRequest;
4440
4761
  exports.getContextManager = getContextManager;
4762
+ exports.getCurrentParentToolContext = getCurrentParentToolContext;
4441
4763
  exports.getCurrentRaindropCallMetadata = getCurrentRaindropCallMetadata;
4442
4764
  exports.readRaindropCallMetadataFromArgs = readRaindropCallMetadataFromArgs;
4765
+ exports.redactJsonAttributeValue = redactJsonAttributeValue;
4766
+ exports.redactSecretsInObject = redactSecretsInObject;
4767
+ exports.runWithParentToolContext = runWithParentToolContext;
4443
4768
  exports.runWithRaindropCallMetadata = runWithRaindropCallMetadata;
4444
4769
  exports.withCurrent = withCurrent;