@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.
- package/README.md +66 -3
- package/dist/{chunk-YDMJ6ABM.mjs → chunk-OLOFN54C.mjs} +556 -109
- package/dist/{index-CwK0GdEe.d.mts → index-HYjRP6nV.d.mts} +197 -4
- package/dist/{index-CwK0GdEe.d.ts → index-HYjRP6nV.d.ts} +197 -4
- package/dist/index.browser.d.mts +197 -4
- package/dist/index.browser.d.ts +197 -4
- package/dist/index.browser.js +560 -108
- package/dist/index.browser.mjs +556 -109
- package/dist/index.node.d.mts +1 -1
- package/dist/index.node.d.ts +1 -1
- package/dist/index.node.js +560 -108
- package/dist/index.node.mjs +1 -1
- package/dist/index.workers.d.mts +1 -1
- package/dist/index.workers.d.ts +1 -1
- package/dist/index.workers.js +560 -108
- package/dist/index.workers.mjs +1 -1
- package/package.json +3 -3
package/dist/index.browser.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// ../core/dist/chunk-
|
|
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
|
-
|
|
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
|
-
|
|
431
|
-
this.
|
|
432
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
891
|
-
|
|
892
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
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) =>
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
2356
|
-
|
|
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:
|
|
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
|
|
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
|
-
|
|
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
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
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 :
|
|
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({
|
|
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
|
|
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
|
|
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
|
|
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"
|
|
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
|
|
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 };
|