@raindrop-ai/ai-sdk 0.0.32 → 0.0.34

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.
@@ -1,4 +1,4 @@
1
- // ../core/dist/chunk-VUNUOE2X.js
1
+ // ../core/dist/chunk-U5HUTMR5.js
2
2
  function getCrypto() {
3
3
  const c = globalThis.crypto;
4
4
  return c;
@@ -53,6 +53,8 @@ function base64Encode(bytes) {
53
53
  }
54
54
  return out;
55
55
  }
56
+ var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
57
+ var MAX_RETRY_DELAY_MS = 3e4;
56
58
  function wait(ms) {
57
59
  return new Promise((resolve) => setTimeout(resolve, ms));
58
60
  }
@@ -60,6 +62,46 @@ function formatEndpoint(endpoint) {
60
62
  if (!endpoint) return void 0;
61
63
  return endpoint.endsWith("/") ? endpoint : `${endpoint}/`;
62
64
  }
65
+ function redactUrlForLog(url) {
66
+ try {
67
+ const parsed = new URL(url);
68
+ parsed.username = "";
69
+ parsed.password = "";
70
+ parsed.search = "";
71
+ parsed.hash = "";
72
+ return parsed.toString();
73
+ } catch (e) {
74
+ return "<unparseable-url>";
75
+ }
76
+ }
77
+ var RATE_LIMITED_LOG_INTERVAL_MS = 3e4;
78
+ var rateLimitedLogLast = /* @__PURE__ */ new Map();
79
+ function rateLimitedLog(key, log) {
80
+ const now = Date.now();
81
+ const last = rateLimitedLogLast.get(key);
82
+ if (last !== void 0 && now - last < RATE_LIMITED_LOG_INTERVAL_MS) {
83
+ return false;
84
+ }
85
+ rateLimitedLogLast.set(key, now);
86
+ log();
87
+ return true;
88
+ }
89
+ async function raceWithTimeout(promise, timeoutMs) {
90
+ let timer;
91
+ const settledInTime = await Promise.race([
92
+ promise.then(
93
+ () => true,
94
+ () => true
95
+ ),
96
+ new Promise((resolve) => {
97
+ var _a;
98
+ timer = setTimeout(() => resolve(false), Math.max(0, timeoutMs));
99
+ (_a = timer.unref) == null ? void 0 : _a.call(timer);
100
+ })
101
+ ]);
102
+ if (timer) clearTimeout(timer);
103
+ return settledInTime;
104
+ }
63
105
  function parseRetryAfter(headers) {
64
106
  var _a;
65
107
  const value = (_a = headers.get("Retry-After")) != null ? _a : headers.get("retry-after");
@@ -76,12 +118,12 @@ function parseRetryAfter(headers) {
76
118
  function getRetryDelayMs(attemptNumber, previousError) {
77
119
  if (previousError && typeof previousError === "object" && previousError !== null && "retryAfterMs" in previousError) {
78
120
  const v = previousError.retryAfterMs;
79
- if (typeof v === "number") return Math.max(0, v);
121
+ if (typeof v === "number") return Math.min(Math.max(0, v), MAX_RETRY_DELAY_MS);
80
122
  }
81
123
  if (attemptNumber <= 1) return 0;
82
124
  const base = 500;
83
125
  const factor = Math.pow(2, attemptNumber - 2);
84
- return base * factor;
126
+ return Math.min(base * factor, MAX_RETRY_DELAY_MS);
85
127
  }
86
128
  async function withRetry(operation, opName2, opts) {
87
129
  const prefix = opts.sdkName ? `[raindrop-ai/${opts.sdkName}]` : "[raindrop-ai/core]";
@@ -116,7 +158,9 @@ async function withRetry(operation, opName2, opts) {
116
158
  throw lastError instanceof Error ? lastError : new Error(String(lastError));
117
159
  }
118
160
  async function postJson(url, body, headers, opts) {
119
- const opName2 = `POST ${url}`;
161
+ var _a;
162
+ const opName2 = `POST ${redactUrlForLog(url)}`;
163
+ const timeoutMs = (_a = opts.timeoutMs) != null ? _a : DEFAULT_REQUEST_TIMEOUT_MS;
120
164
  await withRetry(
121
165
  async () => {
122
166
  const resp = await fetch(url, {
@@ -125,7 +169,8 @@ async function postJson(url, body, headers, opts) {
125
169
  "Content-Type": "application/json",
126
170
  ...headers
127
171
  },
128
- body: JSON.stringify(body)
172
+ body: JSON.stringify(body),
173
+ signal: AbortSignal.timeout(timeoutMs)
129
174
  });
130
175
  if (!resp.ok) {
131
176
  const text = await resp.text().catch(() => "");
@@ -142,6 +187,27 @@ async function postJson(url, body, headers, opts) {
142
187
  opts
143
188
  );
144
189
  }
190
+ var DEFAULT_MAX_TEXT_FIELD_CHARS = 1e6;
191
+ var TRUNCATION_MARKER = "...[truncated by raindrop]";
192
+ var currentDefaultMaxTextFieldChars = DEFAULT_MAX_TEXT_FIELD_CHARS;
193
+ function resolveMaxTextFieldChars(value) {
194
+ if (typeof value === "number" && Number.isFinite(value) && value > 0) {
195
+ return Math.floor(value);
196
+ }
197
+ return currentDefaultMaxTextFieldChars;
198
+ }
199
+ function truncateToLimit(text, limit) {
200
+ if (limit > TRUNCATION_MARKER.length) {
201
+ return text.slice(0, limit - TRUNCATION_MARKER.length) + TRUNCATION_MARKER;
202
+ }
203
+ return text.slice(0, Math.max(0, limit));
204
+ }
205
+ function capText(value, limit) {
206
+ if (typeof value !== "string") return value;
207
+ const max = limit != null ? limit : currentDefaultMaxTextFieldChars;
208
+ if (value.length <= max) return value;
209
+ return truncateToLimit(value, max);
210
+ }
145
211
  var SpanStatusCode = {
146
212
  UNSET: 0,
147
213
  ERROR: 2
@@ -329,6 +395,8 @@ function sendLocalDebuggerLiveEvent(event, options = {}) {
329
395
  ).catch(() => {
330
396
  });
331
397
  }
398
+ var SHUTDOWN_DEADLINE_MS = 1e4;
399
+ var POST_SHUTDOWN_TIMEOUT_MS = 5e3;
332
400
  function mergePatches(target, source) {
333
401
  var _a, _b, _c, _d;
334
402
  const out = { ...target, ...source };
@@ -346,6 +414,7 @@ var EventShipper = class {
346
414
  this.sticky = /* @__PURE__ */ new Map();
347
415
  this.timers = /* @__PURE__ */ new Map();
348
416
  this.inFlight = /* @__PURE__ */ new Set();
417
+ this.hasShutdown = false;
349
418
  var _a, _b, _c, _d, _e, _f, _g, _h;
350
419
  this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
351
420
  this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
@@ -355,6 +424,7 @@ var EventShipper = class {
355
424
  this.sdkName = (_d = opts.sdkName) != null ? _d : "core";
356
425
  this.prefix = `[raindrop-ai/${this.sdkName}]`;
357
426
  this.defaultEventName = (_e = opts.defaultEventName) != null ? _e : "ai_generation";
427
+ this.maxTextFieldCharsOpt = opts.maxTextFieldChars;
358
428
  this.localDebuggerUrl = (_f = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _f : void 0;
359
429
  if (this.debug && this.localDebuggerUrl) {
360
430
  console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
@@ -377,10 +447,52 @@ var EventShipper = class {
377
447
  authHeaders() {
378
448
  return this.writeKey ? { Authorization: `Bearer ${this.writeKey}` } : {};
379
449
  }
450
+ /**
451
+ * Build the retry/timeout options for one POST, honoring the shutdown
452
+ * deadline. Returns `null` when the shutdown drain window is exhausted —
453
+ * the caller must drop the payload (with a rate-limited warning) instead
454
+ * of issuing a request that could outlive process exit.
455
+ *
456
+ * Checked fresh on EVERY send, so a shutdown that begins while the flush
457
+ * path is mid-drain takes effect immediately: no further retries, and the
458
+ * per-attempt timeout is clamped to the remaining window. After
459
+ * `shutdown()` returns (deadline cleared, `hasShutdown` still set),
460
+ * sends — late callers, or flush work the deadline abandoned mid-drain —
461
+ * run as a single short attempt rather than regaining the full retry
462
+ * schedule.
463
+ */
464
+ requestOpts() {
465
+ if (this.shutdownDeadlineAt !== void 0) {
466
+ const remainingMs = this.shutdownDeadlineAt - Date.now();
467
+ if (remainingMs <= 0) return null;
468
+ return {
469
+ maxAttempts: 1,
470
+ debug: this.debug,
471
+ sdkName: this.sdkName,
472
+ timeoutMs: Math.min(DEFAULT_REQUEST_TIMEOUT_MS, remainingMs)
473
+ };
474
+ }
475
+ if (this.hasShutdown) {
476
+ return {
477
+ maxAttempts: 1,
478
+ debug: this.debug,
479
+ sdkName: this.sdkName,
480
+ timeoutMs: POST_SHUTDOWN_TIMEOUT_MS
481
+ };
482
+ }
483
+ return { maxAttempts: 3, debug: this.debug, sdkName: this.sdkName };
484
+ }
380
485
  async patch(eventId, patch) {
381
486
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
382
487
  if (!this.enabled) return;
383
488
  if (!eventId || !eventId.trim()) return;
489
+ const maxChars = resolveMaxTextFieldChars(this.maxTextFieldCharsOpt);
490
+ if (typeof patch.input === "string" && patch.input.length > maxChars) {
491
+ patch = { ...patch, input: capText(patch.input, maxChars) };
492
+ }
493
+ if (typeof patch.output === "string" && patch.output.length > maxChars) {
494
+ patch = { ...patch, output: capText(patch.output, maxChars) };
495
+ }
384
496
  if (this.debug) {
385
497
  console.log(`${this.prefix} queue patch`, {
386
498
  eventId,
@@ -427,9 +539,16 @@ var EventShipper = class {
427
539
  })));
428
540
  }
429
541
  async shutdown() {
430
- for (const t of this.timers.values()) clearTimeout(t);
431
- this.timers.clear();
432
- await this.flush();
542
+ this.hasShutdown = true;
543
+ this.shutdownDeadlineAt = Date.now() + SHUTDOWN_DEADLINE_MS;
544
+ try {
545
+ for (const t of this.timers.values()) clearTimeout(t);
546
+ this.timers.clear();
547
+ const settled = await raceWithTimeout(this.flush(), SHUTDOWN_DEADLINE_MS);
548
+ if (!settled) this.warnShutdownDrop("in-flight request(s) at shutdown");
549
+ } finally {
550
+ this.shutdownDeadlineAt = void 0;
551
+ }
433
552
  }
434
553
  async trackSignal(signal) {
435
554
  var _a, _b;
@@ -451,15 +570,19 @@ var EventShipper = class {
451
570
  ];
452
571
  if (!this.writeKey) return;
453
572
  const url = `${this.baseUrl}signals/track`;
573
+ const opts = this.requestOpts();
574
+ if (!opts) {
575
+ this.warnShutdownDrop("signal");
576
+ return;
577
+ }
454
578
  try {
455
- await postJson(url, body, this.authHeaders(), {
456
- maxAttempts: 3,
457
- debug: this.debug,
458
- sdkName: this.sdkName
459
- });
579
+ await postJson(url, body, this.authHeaders(), opts);
460
580
  } catch (err) {
461
581
  const msg = err instanceof Error ? err.message : String(err);
462
- console.warn(`${this.prefix} failed to send signal (dropping): ${msg}`);
582
+ rateLimitedLog(
583
+ `${this.prefix}.send_signal_failed`,
584
+ () => console.warn(`${this.prefix} failed to send signal (dropping): ${msg}`)
585
+ );
463
586
  }
464
587
  }
465
588
  async identify(users) {
@@ -483,17 +606,27 @@ var EventShipper = class {
483
606
  if (!this.writeKey) return;
484
607
  if (body.length === 0) return;
485
608
  const url = `${this.baseUrl}users/identify`;
609
+ const opts = this.requestOpts();
610
+ if (!opts) {
611
+ this.warnShutdownDrop("identify");
612
+ return;
613
+ }
486
614
  try {
487
- await postJson(url, body, this.authHeaders(), {
488
- maxAttempts: 3,
489
- debug: this.debug,
490
- sdkName: this.sdkName
491
- });
615
+ await postJson(url, body, this.authHeaders(), opts);
492
616
  } catch (err) {
493
617
  const msg = err instanceof Error ? err.message : String(err);
494
- console.warn(`${this.prefix} failed to send identify (dropping): ${msg}`);
618
+ rateLimitedLog(
619
+ `${this.prefix}.send_identify_failed`,
620
+ () => console.warn(`${this.prefix} failed to send identify (dropping): ${msg}`)
621
+ );
495
622
  }
496
623
  }
624
+ warnShutdownDrop(what) {
625
+ rateLimitedLog(
626
+ `${this.prefix}.shutdown_deadline`,
627
+ () => console.warn(`${this.prefix} shutdown flush deadline exceeded; dropping ${what}`)
628
+ );
629
+ }
497
630
  async flushOne(eventId) {
498
631
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
499
632
  if (!this.enabled) return;
@@ -569,11 +702,13 @@ var EventShipper = class {
569
702
  if (!isPending) this.sticky.delete(eventId);
570
703
  return;
571
704
  }
572
- const p = postJson(url, payload, this.authHeaders(), {
573
- maxAttempts: 3,
574
- debug: this.debug,
575
- sdkName: this.sdkName
576
- });
705
+ const opts = this.requestOpts();
706
+ if (!opts) {
707
+ this.warnShutdownDrop(`track_partial ${eventId}`);
708
+ if (!isPending) this.sticky.delete(eventId);
709
+ return;
710
+ }
711
+ const p = postJson(url, payload, this.authHeaders(), opts);
577
712
  this.inFlight.add(p);
578
713
  try {
579
714
  try {
@@ -583,7 +718,10 @@ var EventShipper = class {
583
718
  }
584
719
  } catch (err) {
585
720
  const msg = err instanceof Error ? err.message : String(err);
586
- console.warn(`${this.prefix} failed to send track_partial (dropping): ${msg}`);
721
+ rateLimitedLog(
722
+ `${this.prefix}.send_track_partial_failed`,
723
+ () => console.warn(`${this.prefix} failed to send track_partial (dropping): ${msg}`)
724
+ );
587
725
  }
588
726
  } finally {
589
727
  this.inFlight.delete(p);
@@ -682,10 +820,24 @@ function redactJsonAttributeValue(key, value) {
682
820
  if (scrubbedJson === json) return void 0;
683
821
  return { stringValue: scrubbedJson };
684
822
  }
823
+ function applyOtelSpanAttributeLimit(limit) {
824
+ var _a, _b;
825
+ try {
826
+ const raw = (_b = (_a = globalThis == null ? void 0 : globalThis.process) == null ? void 0 : _a.env) == null ? void 0 : _b.OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT;
827
+ if (!raw) return limit;
828
+ const parsed = Number.parseInt(raw, 10);
829
+ if (Number.isFinite(parsed) && parsed > 0) {
830
+ return Math.min(limit, parsed);
831
+ }
832
+ } catch (e) {
833
+ }
834
+ return limit;
835
+ }
685
836
  var TraceShipper = class {
686
837
  constructor(opts) {
687
838
  this.queue = [];
688
839
  this.inFlight = /* @__PURE__ */ new Set();
840
+ this.hasShutdown = false;
689
841
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
690
842
  this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
691
843
  this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
@@ -705,6 +857,39 @@ var TraceShipper = class {
705
857
  }
706
858
  this.transformSpanHook = opts.transformSpan;
707
859
  this.disableDefaultRedaction = opts.disableDefaultRedaction === true;
860
+ this.maxTextFieldCharsOpt = opts.maxTextFieldChars;
861
+ }
862
+ /**
863
+ * Cap every string attribute value on the span. O(#attributes) length
864
+ * checks; only oversized values pay a slice. Runs AFTER the redaction
865
+ * pipeline so the default secret-scrub still sees parseable JSON in
866
+ * `ai.request.providerOptions` / `ai.response.providerMetadata` (capping
867
+ * first could cut a JSON blob mid-way, fail the parse, and ship secrets
868
+ * in the surviving prefix).
869
+ *
870
+ * A stricter `OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT` env var is honored
871
+ * for span content, matching the Python SDK and the OTel SDK convention.
872
+ */
873
+ capSpanAttributes(span) {
874
+ var _a;
875
+ const maxChars = applyOtelSpanAttributeLimit(
876
+ resolveMaxTextFieldChars(this.maxTextFieldCharsOpt)
877
+ );
878
+ const attrs = span.attributes;
879
+ if (!attrs || attrs.length === 0) return span;
880
+ let nextAttrs;
881
+ for (let i = 0; i < attrs.length; i++) {
882
+ const attr = attrs[i];
883
+ const value = (_a = attr.value) == null ? void 0 : _a.stringValue;
884
+ if (typeof value !== "string" || value.length <= maxChars) continue;
885
+ if (!nextAttrs) nextAttrs = attrs.slice();
886
+ nextAttrs[i] = {
887
+ key: attr.key,
888
+ value: { ...attr.value, stringValue: capText(value, maxChars) }
889
+ };
890
+ }
891
+ if (!nextAttrs) return span;
892
+ return { ...span, attributes: nextAttrs };
708
893
  }
709
894
  /**
710
895
  * Apply the user `transformSpan` hook (if any) followed by the default
@@ -738,7 +923,7 @@ var TraceShipper = class {
738
923
  if (!this.disableDefaultRedaction) {
739
924
  current = defaultTransformSpan(current);
740
925
  }
741
- return current;
926
+ return this.capSpanAttributes(current);
742
927
  }
743
928
  isDebugEnabled() {
744
929
  return this.debug;
@@ -859,6 +1044,16 @@ var TraceShipper = class {
859
1044
  while (this.queue.length > 0) {
860
1045
  const batch = this.queue.splice(0, this.maxBatchSize);
861
1046
  if (!this.writeKey) continue;
1047
+ const opts = this.requestOpts();
1048
+ if (!opts) {
1049
+ rateLimitedLog(
1050
+ `${this.prefix}.shutdown_deadline`,
1051
+ () => console.warn(
1052
+ `${this.prefix} shutdown flush deadline exceeded; dropping ${batch.length} spans`
1053
+ )
1054
+ );
1055
+ continue;
1056
+ }
862
1057
  const body = buildExportTraceServiceRequest(batch, this.serviceName, this.serviceVersion);
863
1058
  const url = `${this.baseUrl}traces`;
864
1059
  if (this.debug) {
@@ -867,11 +1062,7 @@ var TraceShipper = class {
867
1062
  endpoint: url
868
1063
  });
869
1064
  }
870
- const p = postJson(url, body, this.authHeaders(), {
871
- maxAttempts: 3,
872
- debug: this.debug,
873
- sdkName: this.sdkName
874
- });
1065
+ const p = postJson(url, body, this.authHeaders(), opts);
875
1066
  this.inFlight.add(p);
876
1067
  try {
877
1068
  try {
@@ -879,21 +1070,61 @@ var TraceShipper = class {
879
1070
  if (this.debug) console.log(`${this.prefix} sent ${batch.length} spans`);
880
1071
  } catch (err) {
881
1072
  const msg = err instanceof Error ? err.message : String(err);
882
- console.warn(`${this.prefix} failed to send ${batch.length} spans: ${msg}`);
1073
+ rateLimitedLog(
1074
+ `${this.prefix}.send_spans_failed`,
1075
+ () => console.warn(`${this.prefix} failed to send ${batch.length} spans: ${msg}`)
1076
+ );
883
1077
  }
884
1078
  } finally {
885
1079
  this.inFlight.delete(p);
886
1080
  }
887
1081
  }
888
1082
  }
1083
+ /** See EventShipper.requestOpts — same shutdown-budget semantics. */
1084
+ requestOpts() {
1085
+ if (this.shutdownDeadlineAt !== void 0) {
1086
+ const remainingMs = this.shutdownDeadlineAt - Date.now();
1087
+ if (remainingMs <= 0) return null;
1088
+ return {
1089
+ maxAttempts: 1,
1090
+ debug: this.debug,
1091
+ sdkName: this.sdkName,
1092
+ timeoutMs: Math.min(DEFAULT_REQUEST_TIMEOUT_MS, remainingMs)
1093
+ };
1094
+ }
1095
+ if (this.hasShutdown) {
1096
+ return {
1097
+ maxAttempts: 1,
1098
+ debug: this.debug,
1099
+ sdkName: this.sdkName,
1100
+ timeoutMs: POST_SHUTDOWN_TIMEOUT_MS
1101
+ };
1102
+ }
1103
+ return { maxAttempts: 3, debug: this.debug, sdkName: this.sdkName };
1104
+ }
889
1105
  async shutdown() {
890
- if (this.timer) {
891
- clearTimeout(this.timer);
892
- this.timer = void 0;
1106
+ this.hasShutdown = true;
1107
+ this.shutdownDeadlineAt = Date.now() + SHUTDOWN_DEADLINE_MS;
1108
+ try {
1109
+ if (this.timer) {
1110
+ clearTimeout(this.timer);
1111
+ this.timer = void 0;
1112
+ }
1113
+ const drain = async () => {
1114
+ await this.flush();
1115
+ await Promise.all([...this.inFlight].map((p) => p.catch(() => {
1116
+ })));
1117
+ };
1118
+ const settled = await raceWithTimeout(drain(), SHUTDOWN_DEADLINE_MS);
1119
+ if (!settled) {
1120
+ rateLimitedLog(
1121
+ `${this.prefix}.shutdown_deadline`,
1122
+ () => console.warn(`${this.prefix} shutdown flush deadline exceeded; abandoning in-flight spans`)
1123
+ );
1124
+ }
1125
+ } finally {
1126
+ this.shutdownDeadlineAt = void 0;
893
1127
  }
894
- await this.flush();
895
- await Promise.all([...this.inFlight].map((p) => p.catch(() => {
896
- })));
897
1128
  }
898
1129
  };
899
1130
  var NOOP_SPAN = {
@@ -1017,7 +1248,7 @@ async function* asyncGeneratorWithCurrent(span, gen) {
1017
1248
  // package.json
1018
1249
  var package_default = {
1019
1250
  name: "@raindrop-ai/ai-sdk",
1020
- version: "0.0.32"};
1251
+ version: "0.0.34"};
1021
1252
 
1022
1253
  // src/internal/version.ts
1023
1254
  var libraryName = package_default.name;
@@ -1036,6 +1267,133 @@ var EventShipper2 = class extends EventShipper {
1036
1267
  }
1037
1268
  };
1038
1269
 
1270
+ // src/internal/truncation.ts
1271
+ var TRUNCATION_MARKER2 = "...[truncated by raindrop]";
1272
+ var DEFAULT_MAX_TEXT_FIELD_CHARS2 = 1e6;
1273
+ var MAX_DEPTH = 12;
1274
+ var configuredMaxTextFieldChars;
1275
+ function setMaxTextFieldChars(limit) {
1276
+ if (limit === void 0) return;
1277
+ if (typeof limit === "number" && Number.isFinite(limit) && limit > 0) {
1278
+ configuredMaxTextFieldChars = Math.floor(limit);
1279
+ } else {
1280
+ console.warn(`[raindrop-ai] maxTextFieldChars=${String(limit)} ignored; must be > 0`);
1281
+ }
1282
+ }
1283
+ function otelEnvLimit() {
1284
+ var _a;
1285
+ if (typeof process === "undefined") return void 0;
1286
+ const raw = (_a = process.env) == null ? void 0 : _a.OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT;
1287
+ if (!raw) return void 0;
1288
+ const parsed = Number.parseInt(raw, 10);
1289
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : void 0;
1290
+ }
1291
+ function effectiveMaxTextFieldChars() {
1292
+ const base = configuredMaxTextFieldChars != null ? configuredMaxTextFieldChars : DEFAULT_MAX_TEXT_FIELD_CHARS2;
1293
+ const env = otelEnvLimit();
1294
+ return env !== void 0 && env < base ? env : base;
1295
+ }
1296
+ function truncateToLimit2(text, limit) {
1297
+ if (limit > TRUNCATION_MARKER2.length) {
1298
+ return text.slice(0, limit - TRUNCATION_MARKER2.length) + TRUNCATION_MARKER2;
1299
+ }
1300
+ return text.slice(0, limit);
1301
+ }
1302
+ function capText2(value, limit) {
1303
+ if (typeof value !== "string") return value;
1304
+ const max = limit != null ? limit : effectiveMaxTextFieldChars();
1305
+ if (value.length <= max) return value;
1306
+ return truncateToLimit2(value, max);
1307
+ }
1308
+ function boundedClone2(value, budget, depth) {
1309
+ var _a, _b;
1310
+ if (budget.remaining <= 0) return TRUNCATION_MARKER2;
1311
+ if (typeof value === "string") {
1312
+ if (value.length > budget.remaining) {
1313
+ const taken = value.slice(0, Math.max(0, budget.remaining)) + TRUNCATION_MARKER2;
1314
+ budget.remaining = 0;
1315
+ return taken;
1316
+ }
1317
+ budget.remaining -= Math.max(value.length, 1);
1318
+ return value;
1319
+ }
1320
+ if (value === null || typeof value === "number" || typeof value === "boolean" || typeof value === "bigint") {
1321
+ budget.remaining -= 8;
1322
+ return value;
1323
+ }
1324
+ if (typeof value !== "object") {
1325
+ budget.remaining -= 1;
1326
+ return value;
1327
+ }
1328
+ if (value instanceof Uint8Array) {
1329
+ const maxBytes = Math.max(0, Math.ceil(budget.remaining * 3 / 4));
1330
+ if (value.byteLength > maxBytes) {
1331
+ const taken = base64Encode(value.subarray(0, maxBytes)) + TRUNCATION_MARKER2;
1332
+ budget.remaining = 0;
1333
+ return taken;
1334
+ }
1335
+ const encoded = base64Encode(value);
1336
+ budget.remaining -= Math.max(encoded.length, 1);
1337
+ return encoded;
1338
+ }
1339
+ if (depth >= MAX_DEPTH) {
1340
+ budget.remaining -= 16;
1341
+ const name = (_b = (_a = value.constructor) == null ? void 0 : _a.name) != null ? _b : "object";
1342
+ return `<max depth: ${name}>`;
1343
+ }
1344
+ const toJSON = value.toJSON;
1345
+ if (typeof toJSON === "function") {
1346
+ budget.remaining -= 2;
1347
+ return boundedClone2(toJSON.call(value), budget, depth + 1);
1348
+ }
1349
+ if (Array.isArray(value)) {
1350
+ budget.remaining -= 2;
1351
+ const out2 = [];
1352
+ for (const item of value) {
1353
+ if (budget.remaining <= 0) {
1354
+ out2.push(TRUNCATION_MARKER2);
1355
+ break;
1356
+ }
1357
+ out2.push(boundedClone2(item, budget, depth + 1));
1358
+ }
1359
+ return out2;
1360
+ }
1361
+ budget.remaining -= 2;
1362
+ const out = {};
1363
+ for (const key in value) {
1364
+ if (!Object.prototype.hasOwnProperty.call(value, key)) continue;
1365
+ if (budget.remaining <= 0) {
1366
+ out["..."] = TRUNCATION_MARKER2;
1367
+ break;
1368
+ }
1369
+ let cappedKey = key;
1370
+ if (key.length > budget.remaining) {
1371
+ cappedKey = key.slice(0, Math.max(0, budget.remaining)) + TRUNCATION_MARKER2;
1372
+ budget.remaining = 0;
1373
+ out[cappedKey] = TRUNCATION_MARKER2;
1374
+ break;
1375
+ }
1376
+ budget.remaining -= Math.max(key.length, 1);
1377
+ out[cappedKey] = boundedClone2(value[key], budget, depth + 1);
1378
+ }
1379
+ return out;
1380
+ }
1381
+ function boundedStringify(value, limit) {
1382
+ const max = limit != null ? limit : effectiveMaxTextFieldChars();
1383
+ try {
1384
+ if (typeof value === "string") {
1385
+ const text2 = JSON.stringify(capText2(value, max));
1386
+ return text2.length <= max ? text2 : truncateToLimit2(text2, max);
1387
+ }
1388
+ const pruned = boundedClone2(value, { remaining: max + TRUNCATION_MARKER2.length + 256 }, 0);
1389
+ const text = JSON.stringify(pruned);
1390
+ if (text === void 0) return void 0;
1391
+ return text.length <= max ? text : truncateToLimit2(text, max);
1392
+ } catch (e) {
1393
+ return void 0;
1394
+ }
1395
+ }
1396
+
1039
1397
  // src/internal/wrap/helpers.ts
1040
1398
  function isRecord(value) {
1041
1399
  return typeof value === "object" && value !== null;
@@ -1060,21 +1418,10 @@ function isModuleNamespace(obj) {
1060
1418
  }
1061
1419
  }
1062
1420
  function safeJson(value) {
1063
- try {
1064
- return JSON.stringify(value);
1065
- } catch (e) {
1066
- return void 0;
1067
- }
1421
+ return boundedStringify(value);
1068
1422
  }
1069
1423
  function safeJsonWithUint8(value) {
1070
- try {
1071
- return JSON.stringify(value, (_key, v) => {
1072
- if (v instanceof Uint8Array) return base64Encode(v);
1073
- return v;
1074
- });
1075
- } catch (e) {
1076
- return void 0;
1077
- }
1424
+ return boundedStringify(value);
1078
1425
  }
1079
1426
  function extractModelInfo(model) {
1080
1427
  if (typeof model === "string") {
@@ -1800,6 +2147,25 @@ var RaindropTelemetryIntegration = class {
1800
2147
  * (the `event.callId` can be the same for parallel sibling tools).
1801
2148
  */
1802
2149
  this.priorParentContexts = /* @__PURE__ */ new Map();
2150
+ // ── lifecycle ─────────────────────────────────────────────────────────────
2151
+ //
2152
+ // The shippers buffer spans/events and flush on a timer, so a short-lived
2153
+ // script (e.g. a single `generateText` then `process.exit`) can exit before
2154
+ // anything ships. Expose `flush`/`shutdown` on the integration itself so the
2155
+ // value returned by `raindrop()` is self-sufficient — callers can keep the
2156
+ // reference they pass to `registerTelemetry` and `await rd.flush()` before
2157
+ // exiting, without also constructing a separate client.
2158
+ /** Flush any buffered events and trace spans to their destinations. */
2159
+ this.flush = async () => {
2160
+ await Promise.all([this.eventShipper.flush(), this.traceShipper.flush()]);
2161
+ };
2162
+ /** Flush and stop the background flush timers. */
2163
+ this.shutdown = async () => {
2164
+ await Promise.all([
2165
+ this.eventShipper.shutdown(),
2166
+ this.traceShipper.shutdown()
2167
+ ]);
2168
+ };
1803
2169
  // ── onStart ─────────────────────────────────────────────────────────────
1804
2170
  this.onStart = (event) => {
1805
2171
  var _a, _b, _c, _d, _e;
@@ -1951,7 +2317,10 @@ var RaindropTelemetryIntegration = class {
1951
2317
  inputAttrs.push(
1952
2318
  attrStringArray(
1953
2319
  "ai.prompt.tools",
1954
- event.stepTools.map((t) => JSON.stringify(t))
2320
+ event.stepTools.map((t) => {
2321
+ var _a;
2322
+ return (_a = safeJsonWithUint8(t)) != null ? _a : "";
2323
+ })
1955
2324
  )
1956
2325
  );
1957
2326
  }
@@ -1959,7 +2328,7 @@ var RaindropTelemetryIntegration = class {
1959
2328
  inputAttrs.push(
1960
2329
  attrString(
1961
2330
  "ai.prompt.toolChoice",
1962
- JSON.stringify(event.stepToolChoice)
2331
+ safeJsonWithUint8(event.stepToolChoice)
1963
2332
  )
1964
2333
  );
1965
2334
  }
@@ -2015,7 +2384,9 @@ var RaindropTelemetryIntegration = class {
2015
2384
  if (chunk.type === "text-delta") {
2016
2385
  const delta = (_c = chunk.textDelta) != null ? _c : chunk.delta;
2017
2386
  if (typeof delta === "string") {
2018
- state.accumulatedText += delta;
2387
+ if (state.accumulatedText.length <= effectiveMaxTextFieldChars()) {
2388
+ state.accumulatedText += delta;
2389
+ }
2019
2390
  this.emitLive(state, "text_delta", delta);
2020
2391
  }
2021
2392
  } else if (chunk.type === "reasoning" || chunk.type === "reasoning-delta") {
@@ -2034,7 +2405,7 @@ var RaindropTelemetryIntegration = class {
2034
2405
  if (state.recordOutputs) {
2035
2406
  outputAttrs.push(
2036
2407
  attrString("ai.response.finishReason", event.finishReason),
2037
- attrString("ai.response.text", (_a = event.text) != null ? _a : void 0),
2408
+ attrString("ai.response.text", capText2((_a = event.text) != null ? _a : void 0)),
2038
2409
  attrString("ai.response.id", (_b = event.response) == null ? void 0 : _b.id),
2039
2410
  attrString("ai.response.model", (_c = event.response) == null ? void 0 : _c.modelId),
2040
2411
  attrString(
@@ -2050,7 +2421,7 @@ var RaindropTelemetryIntegration = class {
2050
2421
  outputAttrs.push(
2051
2422
  attrString(
2052
2423
  "ai.response.toolCalls",
2053
- JSON.stringify(
2424
+ safeJsonWithUint8(
2054
2425
  event.toolCalls.map((tc) => ({
2055
2426
  toolCallId: tc.toolCallId,
2056
2427
  toolName: tc.toolName,
@@ -2063,7 +2434,7 @@ var RaindropTelemetryIntegration = class {
2063
2434
  if (((_g = event.reasoning) == null ? void 0 : _g.length) > 0) {
2064
2435
  const reasoningText = event.reasoning.filter((part) => "text" in part).map((part) => part.text).join("\n");
2065
2436
  if (reasoningText) {
2066
- outputAttrs.push(attrString("ai.response.reasoning", reasoningText));
2437
+ outputAttrs.push(attrString("ai.response.reasoning", capText2(reasoningText)));
2067
2438
  }
2068
2439
  }
2069
2440
  }
@@ -2193,8 +2564,56 @@ var RaindropTelemetryIntegration = class {
2193
2564
  if (state.subagentToolCallSpan) {
2194
2565
  this.traceShipper.endSpan(state.subagentToolCallSpan, { error: actualError });
2195
2566
  }
2567
+ const isEmbed = state.operationId === "ai.embed" || state.operationId === "ai.embedMany";
2568
+ if (!isEmbed) {
2569
+ this.finalizeGenerateEvent(state, state.accumulatedText || void 0, void 0);
2570
+ }
2196
2571
  this.cleanup(event.callId);
2197
2572
  };
2573
+ // ── onAbort ─────────────────────────────────────────────────────────────
2574
+ //
2575
+ // Dispatched by the v7 canary line (post-beta.116) when a `streamText` call
2576
+ // is cancelled via its `AbortSignal`. On abort the SDK fires neither `onEnd`
2577
+ // nor `onError`, so without this every open span would leak and the event
2578
+ // would hang forever in its `isPending` state. We close every open span with
2579
+ // an `ai.response.aborted` marker (no error status — an abort is not a model
2580
+ // failure) and flush the partial event.
2581
+ this.onAbort = (event) => {
2582
+ const callId = event == null ? void 0 : event.callId;
2583
+ if (!callId) return;
2584
+ const state = this.getState(callId);
2585
+ if (!state) return;
2586
+ const abortedAttr = attrString("ai.response.aborted", "true");
2587
+ if (state.stepSpan) {
2588
+ this.traceShipper.endSpan(state.stepSpan, { attributes: [abortedAttr] });
2589
+ state.stepSpan = void 0;
2590
+ state.stepParent = void 0;
2591
+ }
2592
+ for (const embedSpan of state.embedSpans.values()) {
2593
+ this.traceShipper.endSpan(embedSpan, { attributes: [abortedAttr] });
2594
+ }
2595
+ state.embedSpans.clear();
2596
+ for (const toolCallId of state.parentContextToolCallIds) {
2597
+ this.priorParentContexts.delete(toolCallId);
2598
+ }
2599
+ state.parentContextToolCallIds.clear();
2600
+ for (const toolSpan of state.toolSpans.values()) {
2601
+ this.traceShipper.endSpan(toolSpan, { attributes: [abortedAttr] });
2602
+ }
2603
+ state.toolSpans.clear();
2604
+ if (state.rootSpan) {
2605
+ this.traceShipper.endSpan(state.rootSpan, {
2606
+ attributes: [abortedAttr, attrInt("ai.toolCall.count", state.toolCallCount)]
2607
+ });
2608
+ }
2609
+ if (state.subagentToolCallSpan) {
2610
+ this.traceShipper.endSpan(state.subagentToolCallSpan, {
2611
+ attributes: [abortedAttr]
2612
+ });
2613
+ }
2614
+ this.finalizeGenerateEvent(state, state.accumulatedText || void 0, void 0);
2615
+ this.cleanup(callId);
2616
+ };
2198
2617
  // ── executeTool ─────────────────────────────────────────────────────────
2199
2618
  this.executeTool = async ({
2200
2619
  callId,
@@ -2352,11 +2771,12 @@ var RaindropTelemetryIntegration = class {
2352
2771
  const toolSpan = state.toolSpans.get(event.toolCall.toolCallId);
2353
2772
  if (!toolSpan) return;
2354
2773
  state.toolCallCount += 1;
2355
- if (event.success) {
2356
- const outputAttrs = state.recordOutputs ? [attrString("ai.toolCall.result", safeJsonWithUint8(event.output))] : [];
2774
+ const outcome = "toolOutput" in event ? event.toolOutput.type === "tool-result" ? { success: true, output: event.toolOutput.output } : { success: false, error: event.toolOutput.error } : event.success ? { success: true, output: event.output } : { success: false, error: event.error };
2775
+ if (outcome.success) {
2776
+ const outputAttrs = state.recordOutputs ? [attrString("ai.toolCall.result", safeJsonWithUint8(outcome.output))] : [];
2357
2777
  this.traceShipper.endSpan(toolSpan, { attributes: outputAttrs });
2358
2778
  } else {
2359
- this.traceShipper.endSpan(toolSpan, { error: event.error });
2779
+ this.traceShipper.endSpan(toolSpan, { error: outcome.error });
2360
2780
  }
2361
2781
  this.emitLive(state, "tool_result", event.toolCall.toolName);
2362
2782
  state.toolSpans.delete(event.toolCall.toolCallId);
@@ -2430,13 +2850,13 @@ var RaindropTelemetryIntegration = class {
2430
2850
  }
2431
2851
  }
2432
2852
  finishGenerate(event, state) {
2433
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
2853
+ var _a, _b, _c, _d, _e, _f;
2434
2854
  if (state.rootSpan) {
2435
2855
  const outputAttrs = [];
2436
2856
  if (state.recordOutputs) {
2437
2857
  outputAttrs.push(
2438
2858
  attrString("ai.response.finishReason", event.finishReason),
2439
- attrString("ai.response.text", (_a = event.text) != null ? _a : void 0),
2859
+ attrString("ai.response.text", capText2((_a = event.text) != null ? _a : void 0)),
2440
2860
  attrString(
2441
2861
  "ai.response.providerMetadata",
2442
2862
  event.providerMetadata ? safeJsonWithUint8(event.providerMetadata) : void 0
@@ -2446,7 +2866,7 @@ var RaindropTelemetryIntegration = class {
2446
2866
  outputAttrs.push(
2447
2867
  attrString(
2448
2868
  "ai.response.toolCalls",
2449
- JSON.stringify(
2869
+ safeJsonWithUint8(
2450
2870
  event.toolCalls.map((tc) => ({
2451
2871
  toolCallId: tc.toolCallId,
2452
2872
  toolName: tc.toolName,
@@ -2459,7 +2879,7 @@ var RaindropTelemetryIntegration = class {
2459
2879
  if (((_c = event.reasoning) == null ? void 0 : _c.length) > 0) {
2460
2880
  const reasoningText = event.reasoning.filter((part) => "text" in part).map((part) => part.text).join("\n");
2461
2881
  if (reasoningText) {
2462
- outputAttrs.push(attrString("ai.response.reasoning", reasoningText));
2882
+ outputAttrs.push(attrString("ai.response.reasoning", capText2(reasoningText)));
2463
2883
  }
2464
2884
  }
2465
2885
  }
@@ -2478,38 +2898,48 @@ var RaindropTelemetryIntegration = class {
2478
2898
  );
2479
2899
  this.traceShipper.endSpan(state.rootSpan, { attributes: outputAttrs });
2480
2900
  }
2901
+ this.finalizeGenerateEvent(
2902
+ state,
2903
+ (_e = event.text) != null ? _e : state.accumulatedText || void 0,
2904
+ (_f = event.response) == null ? void 0 : _f.modelId
2905
+ );
2906
+ }
2907
+ /**
2908
+ * Patch the Raindrop event for a completed, aborted, or errored text
2909
+ * generation so it leaves the `isPending` state. Shared by `onFinish`/`onEnd`,
2910
+ * `onAbort`, and `onError`.
2911
+ */
2912
+ finalizeGenerateEvent(state, output, model) {
2913
+ var _a, _b, _c, _d, _e, _f, _g, _h;
2481
2914
  const suppressSubagentEvent = state.subagentName !== void 0 && state.subagentToolCallSpan !== void 0;
2482
- if (this.sendEvents && !suppressSubagentEvent) {
2483
- const callMeta = this.extractRaindropMetadata(state.metadata);
2484
- const userId = (_f = callMeta.userId) != null ? _f : (_e = this.defaultContext) == null ? void 0 : _e.userId;
2485
- if (userId) {
2486
- const eventName = (_i = (_h = callMeta.eventName) != null ? _h : (_g = this.defaultContext) == null ? void 0 : _g.eventName) != null ? _i : state.operationId;
2487
- const output = (_j = event.text) != null ? _j : state.accumulatedText || void 0;
2488
- const input = state.inputText;
2489
- const model = (_k = event.response) == null ? void 0 : _k.modelId;
2490
- const properties = {
2491
- ...(_l = this.defaultContext) == null ? void 0 : _l.properties,
2492
- ...callMeta.properties
2493
- };
2494
- const convoId = (_n = callMeta.convoId) != null ? _n : (_m = this.defaultContext) == null ? void 0 : _m.convoId;
2495
- void this.eventShipper.patch(state.eventId, {
2496
- eventName,
2497
- userId,
2498
- convoId,
2499
- input,
2500
- output,
2501
- model,
2502
- properties: Object.keys(properties).length > 0 ? properties : void 0,
2503
- isPending: false
2504
- }).catch((err) => {
2505
- if (this.debug) {
2506
- console.warn(
2507
- `[raindrop-ai/ai-sdk] event patch failed: ${err instanceof Error ? err.message : err}`
2508
- );
2509
- }
2510
- });
2915
+ if (!this.sendEvents || suppressSubagentEvent) return;
2916
+ const callMeta = this.extractRaindropMetadata(state.metadata);
2917
+ const userId = (_b = callMeta.userId) != null ? _b : (_a = this.defaultContext) == null ? void 0 : _a.userId;
2918
+ if (!userId) return;
2919
+ const eventName = (_e = (_d = callMeta.eventName) != null ? _d : (_c = this.defaultContext) == null ? void 0 : _c.eventName) != null ? _e : state.operationId;
2920
+ const cappedOutput = capText2(output);
2921
+ const input = capText2(state.inputText);
2922
+ const properties = {
2923
+ ...(_f = this.defaultContext) == null ? void 0 : _f.properties,
2924
+ ...callMeta.properties
2925
+ };
2926
+ const convoId = (_h = callMeta.convoId) != null ? _h : (_g = this.defaultContext) == null ? void 0 : _g.convoId;
2927
+ void this.eventShipper.patch(state.eventId, {
2928
+ eventName,
2929
+ userId,
2930
+ convoId,
2931
+ input,
2932
+ output: cappedOutput,
2933
+ model,
2934
+ properties: Object.keys(properties).length > 0 ? properties : void 0,
2935
+ isPending: false
2936
+ }).catch((err) => {
2937
+ if (this.debug) {
2938
+ console.warn(
2939
+ `[raindrop-ai/ai-sdk] event patch failed: ${err instanceof Error ? err.message : err}`
2940
+ );
2511
2941
  }
2512
- }
2942
+ });
2513
2943
  }
2514
2944
  finishEmbed(event, state) {
2515
2945
  var _a;
@@ -2972,13 +3402,14 @@ function shouldKeepEventPending(params) {
2972
3402
  return params.finishReason === "tool-calls" || params.finishReason === "tool_calls";
2973
3403
  }
2974
3404
  function normalizePromptAttr(arg) {
3405
+ var _a, _b;
2975
3406
  if (!isRecord(arg)) return arg;
2976
3407
  const system = arg["system"];
2977
3408
  const prompt = arg["prompt"];
2978
3409
  const messages = arg["messages"];
2979
3410
  if (Array.isArray(messages)) {
2980
3411
  if (system) {
2981
- const sysContent = typeof system === "string" ? system : JSON.stringify(system);
3412
+ const sysContent = typeof system === "string" ? system : (_a = safeJsonWithUint8(system)) != null ? _a : String(system);
2982
3413
  return [{ role: "system", content: sysContent }, ...messages];
2983
3414
  }
2984
3415
  return messages;
@@ -2986,7 +3417,10 @@ function normalizePromptAttr(arg) {
2986
3417
  if (typeof prompt === "string") {
2987
3418
  const msgs = [];
2988
3419
  if (system) {
2989
- msgs.push({ role: "system", content: typeof system === "string" ? system : JSON.stringify(system) });
3420
+ msgs.push({
3421
+ role: "system",
3422
+ content: typeof system === "string" ? system : (_b = safeJsonWithUint8(system)) != null ? _b : String(system)
3423
+ });
2990
3424
  }
2991
3425
  msgs.push({ role: "user", content: prompt });
2992
3426
  return msgs;
@@ -3155,7 +3589,8 @@ function createFinalize(params) {
3155
3589
  };
3156
3590
  const built = await maybeBuildEvent(options.buildEvent, allMessages);
3157
3591
  const patch = mergeBuildEventPatch(defaultPatch, built);
3158
- const output = patch.output;
3592
+ const output = capText2(patch.output);
3593
+ const input = capText2(patch.input);
3159
3594
  const finalModel = (_c = patch.model) != null ? _c : model;
3160
3595
  if (setup.rootSpan) {
3161
3596
  const spanEndTimeUnixNano = nowUnixNanoString();
@@ -3199,7 +3634,7 @@ function createFinalize(params) {
3199
3634
  eventName: patch.eventName,
3200
3635
  userId: setup.ctx.userId,
3201
3636
  convoId: setup.ctx.convoId,
3202
- input: patch.input,
3637
+ input,
3203
3638
  output,
3204
3639
  model: finalModel,
3205
3640
  properties: patch.properties,
@@ -3714,7 +4149,8 @@ function wrapAgentGenerate(generate, instance, agentSettings, className, aiSDK,
3714
4149
  };
3715
4150
  const built = await maybeBuildEvent(deps.options.buildEvent, allMessages);
3716
4151
  const patch = mergeBuildEventPatch(defaultPatch, built);
3717
- const output = patch.output;
4152
+ const output = capText2(patch.output);
4153
+ const input = capText2(patch.input);
3718
4154
  const finalModel = (_c2 = patch.model) != null ? _c2 : model;
3719
4155
  if (rootSpan) {
3720
4156
  const spanEndTimeUnixNano = nowUnixNanoString();
@@ -3772,7 +4208,7 @@ function wrapAgentGenerate(generate, instance, agentSettings, className, aiSDK,
3772
4208
  eventName: patch.eventName,
3773
4209
  userId: ctx.userId,
3774
4210
  convoId: ctx.convoId,
3775
- input: patch.input,
4211
+ input,
3776
4212
  output,
3777
4213
  model: finalModel,
3778
4214
  properties: patch.properties,
@@ -3921,7 +4357,8 @@ function wrapAgentStream(stream, instance, agentSettings, className, aiSDK, deps
3921
4357
  };
3922
4358
  const built = await maybeBuildEvent(deps.options.buildEvent, allMessages);
3923
4359
  const patch = mergeBuildEventPatch(defaultPatch, built);
3924
- const output = patch.output;
4360
+ const output = capText2(patch.output);
4361
+ const input = capText2(patch.input);
3925
4362
  const finalModel = (_c2 = patch.model) != null ? _c2 : model;
3926
4363
  if (rootSpan) {
3927
4364
  const spanEndTimeUnixNano = nowUnixNanoString();
@@ -3979,7 +4416,7 @@ function wrapAgentStream(stream, instance, agentSettings, className, aiSDK, deps
3979
4416
  eventName: patch.eventName,
3980
4417
  userId: ctx.userId,
3981
4418
  convoId: ctx.convoId,
3982
- input: patch.input,
4419
+ input,
3983
4420
  output,
3984
4421
  model: finalModel,
3985
4422
  properties: patch.properties,
@@ -4319,7 +4756,7 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
4319
4756
  attributes: [
4320
4757
  ...((_a = ctx.telemetry) == null ? void 0 : _a.recordOutputs) === false ? [] : [
4321
4758
  attrString("ai.response.finishReason", finishReason),
4322
- attrString("ai.response.text", activeText.length ? activeText : void 0),
4759
+ attrString("ai.response.text", activeText.length ? capText2(activeText) : void 0),
4323
4760
  attrString(
4324
4761
  "ai.response.toolCalls",
4325
4762
  safeJsonWithUint8(toolCallsLocal.length ? toolCallsLocal : void 0)
@@ -4372,7 +4809,9 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
4372
4809
  } else if (typeof value["textDelta"] === "string") {
4373
4810
  textDelta = value["textDelta"];
4374
4811
  }
4375
- if (typeof textDelta === "string") activeText += textDelta;
4812
+ if (typeof textDelta === "string" && activeText.length <= effectiveMaxTextFieldChars()) {
4813
+ activeText += textDelta;
4814
+ }
4376
4815
  }
4377
4816
  if (type === "finish") finishReason = extractFinishReason(value);
4378
4817
  if (type === "tool-call") toolCallsLocal.push(value);
@@ -4645,8 +5084,8 @@ function eventMetadataFromChatRequest(options) {
4645
5084
  });
4646
5085
  }
4647
5086
  function stringify(v) {
4648
- if (typeof v === "string") return v;
4649
- return JSON.stringify(v);
5087
+ if (typeof v === "string") return capText2(v);
5088
+ return boundedStringify(v);
4650
5089
  }
4651
5090
  function userAttrsToOtlp(attrs) {
4652
5091
  if (!attrs) return [];
@@ -4664,6 +5103,7 @@ function createRaindropAISDK(opts) {
4664
5103
  const eventsRequested = ((_a = opts.events) == null ? void 0 : _a.enabled) !== false;
4665
5104
  const tracesRequested = ((_b = opts.traces) == null ? void 0 : _b.enabled) !== false;
4666
5105
  const envDebug = envDebugEnabled();
5106
+ setMaxTextFieldChars(opts.maxTextFieldChars);
4667
5107
  const localWorkshopInput = opts.localWorkshopUrl === false ? null : opts.localWorkshopUrl;
4668
5108
  const resolvedLocalDebuggerUrl = resolveLocalDebuggerBaseUrl(localWorkshopInput);
4669
5109
  const localDebuggerUrl = localWorkshopInput === null ? null : resolvedLocalDebuggerUrl != null ? resolvedLocalDebuggerUrl : void 0;
@@ -4842,5 +5282,12 @@ function createRaindropAISDK(opts) {
4842
5282
  }
4843
5283
  };
4844
5284
  }
5285
+ function raindrop(options = {}) {
5286
+ var _a;
5287
+ const { context, subagentWrapping, writeKey, ...rest } = options;
5288
+ const resolvedWriteKey = writeKey != null ? writeKey : typeof process !== "undefined" ? (_a = process.env) == null ? void 0 : _a.RAINDROP_WRITE_KEY : void 0;
5289
+ const client = createRaindropAISDK({ ...rest, writeKey: resolvedWriteKey });
5290
+ return client.createTelemetryIntegration({ context, subagentWrapping });
5291
+ }
4845
5292
 
4846
- 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 };
5293
+ export { DEFAULT_MAX_TEXT_FIELD_CHARS2 as DEFAULT_MAX_TEXT_FIELD_CHARS, DEFAULT_REDACT_ATTRIBUTE_KEYS, DEFAULT_SECRET_KEY_NAMES, REDACTED_PLACEHOLDER, RaindropTelemetryIntegration, TRUNCATION_MARKER2 as TRUNCATION_MARKER, _resetParentToolContextStorage, _resetRaindropCallMetadataStorage, _resetWarnedMissingUserId, boundedStringify, capText2 as capText, clearParentToolContext, createRaindropAISDK, currentSpan, defaultTransformSpan, enterParentToolContext, eventMetadata, eventMetadataFromChatRequest, getContextManager, getCurrentParentToolContext, getCurrentRaindropCallMetadata, raindrop, readRaindropCallMetadataFromArgs, redactJsonAttributeValue, redactSecretsInObject, runWithParentToolContext, runWithRaindropCallMetadata, withCurrent };