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