raindrop-ai 0.1.1-otelv2 → 0.1.2
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 +21 -0
- package/dist/{chunk-DP5ED5DR.mjs → chunk-UICWZEYM.mjs} +251 -48
- package/dist/index.d.mts +34 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.js +358 -72
- package/dist/index.mjs +130 -25
- package/dist/tracing/index.js +229 -48
- package/dist/tracing/index.mjs +1 -1
- package/package.json +5 -7
package/README.md
CHANGED
|
@@ -18,6 +18,27 @@ const raindrop = new Raindrop({
|
|
|
18
18
|
});
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
+
## Payload size limits
|
|
22
|
+
|
|
23
|
+
Text fields (ai input/output, tool span I/O, span content) are capped at
|
|
24
|
+
**1,000,000 characters per field by default** and truncated with a
|
|
25
|
+
`...[truncated by raindrop]` marker. The cap is enforced before (or during)
|
|
26
|
+
serialization, so oversized payloads cost the cap — not the payload — on your
|
|
27
|
+
event loop, and large events land truncated instead of being silently dropped
|
|
28
|
+
at the 1 MB ingest limit. Tune it via:
|
|
29
|
+
|
|
30
|
+
```ts
|
|
31
|
+
const raindrop = new Raindrop({
|
|
32
|
+
writeKey: "...",
|
|
33
|
+
maxTextFieldChars: 250_000,
|
|
34
|
+
});
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
A stricter `OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT` env var is still honored
|
|
38
|
+
for span content. All outbound HTTP carries finite timeouts, and
|
|
39
|
+
`raindrop.close()` runs under a 10s deadline so a dead network can never
|
|
40
|
+
wedge your process exit.
|
|
41
|
+
|
|
21
42
|
## Notes
|
|
22
43
|
|
|
23
44
|
- This package preserves the current dist structure and public exports.
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
// ../core/dist/chunk-
|
|
1
|
+
// ../core/dist/chunk-U5HUTMR5.js
|
|
2
|
+
var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
|
|
3
|
+
var MAX_RETRY_DELAY_MS = 3e4;
|
|
2
4
|
function wait(ms) {
|
|
3
5
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
4
6
|
}
|
|
@@ -6,6 +8,46 @@ function formatEndpoint(endpoint) {
|
|
|
6
8
|
if (!endpoint) return void 0;
|
|
7
9
|
return endpoint.endsWith("/") ? endpoint : `${endpoint}/`;
|
|
8
10
|
}
|
|
11
|
+
function redactUrlForLog(url) {
|
|
12
|
+
try {
|
|
13
|
+
const parsed = new URL(url);
|
|
14
|
+
parsed.username = "";
|
|
15
|
+
parsed.password = "";
|
|
16
|
+
parsed.search = "";
|
|
17
|
+
parsed.hash = "";
|
|
18
|
+
return parsed.toString();
|
|
19
|
+
} catch (e) {
|
|
20
|
+
return "<unparseable-url>";
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
var RATE_LIMITED_LOG_INTERVAL_MS = 3e4;
|
|
24
|
+
var rateLimitedLogLast = /* @__PURE__ */ new Map();
|
|
25
|
+
function rateLimitedLog(key, log) {
|
|
26
|
+
const now = Date.now();
|
|
27
|
+
const last = rateLimitedLogLast.get(key);
|
|
28
|
+
if (last !== void 0 && now - last < RATE_LIMITED_LOG_INTERVAL_MS) {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
rateLimitedLogLast.set(key, now);
|
|
32
|
+
log();
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
async function raceWithTimeout(promise, timeoutMs) {
|
|
36
|
+
let timer;
|
|
37
|
+
const settledInTime = await Promise.race([
|
|
38
|
+
promise.then(
|
|
39
|
+
() => true,
|
|
40
|
+
() => true
|
|
41
|
+
),
|
|
42
|
+
new Promise((resolve) => {
|
|
43
|
+
var _a;
|
|
44
|
+
timer = setTimeout(() => resolve(false), Math.max(0, timeoutMs));
|
|
45
|
+
(_a = timer.unref) == null ? void 0 : _a.call(timer);
|
|
46
|
+
})
|
|
47
|
+
]);
|
|
48
|
+
if (timer) clearTimeout(timer);
|
|
49
|
+
return settledInTime;
|
|
50
|
+
}
|
|
9
51
|
function parseRetryAfter(headers) {
|
|
10
52
|
var _a;
|
|
11
53
|
const value = (_a = headers.get("Retry-After")) != null ? _a : headers.get("retry-after");
|
|
@@ -22,12 +64,12 @@ function parseRetryAfter(headers) {
|
|
|
22
64
|
function getRetryDelayMs(attemptNumber, previousError) {
|
|
23
65
|
if (previousError && typeof previousError === "object" && previousError !== null && "retryAfterMs" in previousError) {
|
|
24
66
|
const v = previousError.retryAfterMs;
|
|
25
|
-
if (typeof v === "number") return Math.max(0, v);
|
|
67
|
+
if (typeof v === "number") return Math.min(Math.max(0, v), MAX_RETRY_DELAY_MS);
|
|
26
68
|
}
|
|
27
69
|
if (attemptNumber <= 1) return 0;
|
|
28
70
|
const base = 500;
|
|
29
71
|
const factor = Math.pow(2, attemptNumber - 2);
|
|
30
|
-
return base * factor;
|
|
72
|
+
return Math.min(base * factor, MAX_RETRY_DELAY_MS);
|
|
31
73
|
}
|
|
32
74
|
async function withRetry(operation, opName, opts) {
|
|
33
75
|
const prefix = opts.sdkName ? `[raindrop-ai/${opts.sdkName}]` : "[raindrop-ai/core]";
|
|
@@ -62,7 +104,9 @@ async function withRetry(operation, opName, opts) {
|
|
|
62
104
|
throw lastError instanceof Error ? lastError : new Error(String(lastError));
|
|
63
105
|
}
|
|
64
106
|
async function postJson(url, body, headers, opts) {
|
|
65
|
-
|
|
107
|
+
var _a;
|
|
108
|
+
const opName = `POST ${redactUrlForLog(url)}`;
|
|
109
|
+
const timeoutMs = (_a = opts.timeoutMs) != null ? _a : DEFAULT_REQUEST_TIMEOUT_MS;
|
|
66
110
|
await withRetry(
|
|
67
111
|
async () => {
|
|
68
112
|
const resp = await fetch(url, {
|
|
@@ -71,7 +115,8 @@ async function postJson(url, body, headers, opts) {
|
|
|
71
115
|
"Content-Type": "application/json",
|
|
72
116
|
...headers
|
|
73
117
|
},
|
|
74
|
-
body: JSON.stringify(body)
|
|
118
|
+
body: JSON.stringify(body),
|
|
119
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
75
120
|
});
|
|
76
121
|
if (!resp.ok) {
|
|
77
122
|
const text = await resp.text().catch(() => "");
|
|
@@ -88,6 +133,108 @@ async function postJson(url, body, headers, opts) {
|
|
|
88
133
|
opts
|
|
89
134
|
);
|
|
90
135
|
}
|
|
136
|
+
var DEFAULT_MAX_TEXT_FIELD_CHARS = 1e6;
|
|
137
|
+
var TRUNCATION_MARKER = "...[truncated by raindrop]";
|
|
138
|
+
var BOUNDED_CLONE_MAX_DEPTH = 12;
|
|
139
|
+
var BOUNDED_CLONE_SLACK = 256;
|
|
140
|
+
var currentDefaultMaxTextFieldChars = DEFAULT_MAX_TEXT_FIELD_CHARS;
|
|
141
|
+
function setDefaultMaxTextFieldChars(value) {
|
|
142
|
+
if (typeof value === "number" && Number.isFinite(value) && value > 0) {
|
|
143
|
+
currentDefaultMaxTextFieldChars = Math.floor(value);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
function resolveMaxTextFieldChars(value) {
|
|
147
|
+
if (typeof value === "number" && Number.isFinite(value) && value > 0) {
|
|
148
|
+
return Math.floor(value);
|
|
149
|
+
}
|
|
150
|
+
return currentDefaultMaxTextFieldChars;
|
|
151
|
+
}
|
|
152
|
+
function truncateToLimit(text, limit) {
|
|
153
|
+
if (limit > TRUNCATION_MARKER.length) {
|
|
154
|
+
return text.slice(0, limit - TRUNCATION_MARKER.length) + TRUNCATION_MARKER;
|
|
155
|
+
}
|
|
156
|
+
return text.slice(0, Math.max(0, limit));
|
|
157
|
+
}
|
|
158
|
+
function capText(value, limit) {
|
|
159
|
+
if (typeof value !== "string") return value;
|
|
160
|
+
const max = limit != null ? limit : currentDefaultMaxTextFieldChars;
|
|
161
|
+
if (value.length <= max) return value;
|
|
162
|
+
return truncateToLimit(value, max);
|
|
163
|
+
}
|
|
164
|
+
function boundedClone(obj, charBudget) {
|
|
165
|
+
let budget = charBudget;
|
|
166
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
167
|
+
const walk = (node, depth) => {
|
|
168
|
+
if (budget <= 0) return TRUNCATION_MARKER;
|
|
169
|
+
if (typeof node === "string") {
|
|
170
|
+
if (node.length > budget) {
|
|
171
|
+
const taken = node.slice(0, Math.max(0, budget)) + TRUNCATION_MARKER;
|
|
172
|
+
budget = 0;
|
|
173
|
+
return taken;
|
|
174
|
+
}
|
|
175
|
+
budget -= Math.max(node.length, 1);
|
|
176
|
+
return node;
|
|
177
|
+
}
|
|
178
|
+
if (node === null || typeof node === "number" || typeof node === "boolean") {
|
|
179
|
+
budget -= 8;
|
|
180
|
+
return node;
|
|
181
|
+
}
|
|
182
|
+
if (typeof node !== "object") {
|
|
183
|
+
budget -= 8;
|
|
184
|
+
return node;
|
|
185
|
+
}
|
|
186
|
+
if (seen.has(node)) return "[CIRCULAR]";
|
|
187
|
+
if (depth >= BOUNDED_CLONE_MAX_DEPTH) {
|
|
188
|
+
budget -= 16;
|
|
189
|
+
return `<max depth>`;
|
|
190
|
+
}
|
|
191
|
+
seen.add(node);
|
|
192
|
+
if (Array.isArray(node)) {
|
|
193
|
+
const out2 = [];
|
|
194
|
+
for (const v of node) {
|
|
195
|
+
if (budget <= 0) {
|
|
196
|
+
out2.push(TRUNCATION_MARKER);
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
out2.push(walk(v, depth + 1));
|
|
200
|
+
}
|
|
201
|
+
return out2;
|
|
202
|
+
}
|
|
203
|
+
if (typeof node.toJSON === "function") {
|
|
204
|
+
budget -= 16;
|
|
205
|
+
return node;
|
|
206
|
+
}
|
|
207
|
+
const out = {};
|
|
208
|
+
for (const k in node) {
|
|
209
|
+
if (!Object.prototype.hasOwnProperty.call(node, k)) continue;
|
|
210
|
+
if (budget <= 0) {
|
|
211
|
+
out["..."] = TRUNCATION_MARKER;
|
|
212
|
+
break;
|
|
213
|
+
}
|
|
214
|
+
const key = walk(k, depth + 1);
|
|
215
|
+
out[key] = walk(node[k], depth + 1);
|
|
216
|
+
}
|
|
217
|
+
return out;
|
|
218
|
+
};
|
|
219
|
+
return walk(obj, 0);
|
|
220
|
+
}
|
|
221
|
+
function stringifyBounded(value, limit) {
|
|
222
|
+
const max = limit != null ? limit : currentDefaultMaxTextFieldChars;
|
|
223
|
+
if (typeof value === "string") {
|
|
224
|
+
return capText(value, max);
|
|
225
|
+
}
|
|
226
|
+
const pruned = boundedClone(value, max + TRUNCATION_MARKER.length + BOUNDED_CLONE_SLACK);
|
|
227
|
+
let json;
|
|
228
|
+
try {
|
|
229
|
+
json = JSON.stringify(pruned);
|
|
230
|
+
} catch (e) {
|
|
231
|
+
json = void 0;
|
|
232
|
+
}
|
|
233
|
+
if (json === void 0) {
|
|
234
|
+
return capText(String(value), max);
|
|
235
|
+
}
|
|
236
|
+
return json.length <= max ? json : truncateToLimit(json, max);
|
|
237
|
+
}
|
|
91
238
|
var LOCAL_DEBUGGER_ENV_VAR = "RAINDROP_LOCAL_DEBUGGER";
|
|
92
239
|
var WORKSHOP_ENV_VAR = "RAINDROP_WORKSHOP";
|
|
93
240
|
var DEFAULT_LOCAL_WORKSHOP_URL = "http://localhost:5899/v1/";
|
|
@@ -196,6 +343,13 @@ function sendLocalDebuggerLiveEvent(event, options = {}) {
|
|
|
196
343
|
).catch(() => {
|
|
197
344
|
});
|
|
198
345
|
}
|
|
346
|
+
var SHUTDOWN_DEADLINE_MS = 1e4;
|
|
347
|
+
var POST_SHUTDOWN_TIMEOUT_MS = 5e3;
|
|
348
|
+
var DEFAULT_REDACT_ATTRIBUTE_KEYS = [
|
|
349
|
+
"ai.request.providerOptions",
|
|
350
|
+
"ai.response.providerMetadata"
|
|
351
|
+
];
|
|
352
|
+
var REDACT_JSON_ATTRIBUTE_KEYS = new Set(DEFAULT_REDACT_ATTRIBUTE_KEYS);
|
|
199
353
|
|
|
200
354
|
// ../core/dist/index.node.js
|
|
201
355
|
import { AsyncLocalStorage } from "async_hooks";
|
|
@@ -204,7 +358,7 @@ globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = AsyncLocalStorage;
|
|
|
204
358
|
// package.json
|
|
205
359
|
var package_default = {
|
|
206
360
|
name: "raindrop-ai",
|
|
207
|
-
version: "0.1.
|
|
361
|
+
version: "0.1.2",
|
|
208
362
|
main: "dist/index.js",
|
|
209
363
|
module: "dist/index.mjs",
|
|
210
364
|
types: "dist/index.d.ts",
|
|
@@ -362,12 +516,12 @@ function parseRetryAfter2(headers) {
|
|
|
362
516
|
function getRetryDelayMs2(attemptNumber, previousError) {
|
|
363
517
|
if (previousError && typeof previousError === "object" && previousError !== null && "retryAfterMs" in previousError) {
|
|
364
518
|
const v = previousError.retryAfterMs;
|
|
365
|
-
if (typeof v === "number") return Math.max(0, v);
|
|
519
|
+
if (typeof v === "number") return Math.min(Math.max(0, v), MAX_RETRY_DELAY_MS);
|
|
366
520
|
}
|
|
367
521
|
if (attemptNumber <= 1) return 0;
|
|
368
522
|
const base = 500;
|
|
369
523
|
const factor = Math.pow(2, attemptNumber - 2);
|
|
370
|
-
return base * factor;
|
|
524
|
+
return Math.min(base * factor, MAX_RETRY_DELAY_MS);
|
|
371
525
|
}
|
|
372
526
|
async function withRetry2(operation, opName, opts) {
|
|
373
527
|
let lastError = void 0;
|
|
@@ -399,7 +553,9 @@ async function withRetry2(operation, opName, opts) {
|
|
|
399
553
|
throw lastError instanceof Error ? lastError : new Error(String(lastError));
|
|
400
554
|
}
|
|
401
555
|
async function postJson2(url, body, headers, opts) {
|
|
402
|
-
|
|
556
|
+
var _a;
|
|
557
|
+
const opName = `POST ${redactUrlForLog(url)}`;
|
|
558
|
+
const timeoutMs = (_a = opts.timeoutMs) != null ? _a : DEFAULT_REQUEST_TIMEOUT_MS;
|
|
403
559
|
await withRetry2(
|
|
404
560
|
async () => {
|
|
405
561
|
const resp = await fetch(url, {
|
|
@@ -408,7 +564,8 @@ async function postJson2(url, body, headers, opts) {
|
|
|
408
564
|
"Content-Type": "application/json",
|
|
409
565
|
...headers
|
|
410
566
|
},
|
|
411
|
-
body: JSON.stringify(body)
|
|
567
|
+
body: JSON.stringify(body),
|
|
568
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
412
569
|
});
|
|
413
570
|
if (!resp.ok) {
|
|
414
571
|
const text = await resp.text().catch(() => "");
|
|
@@ -556,16 +713,19 @@ function getActiveTraceContext() {
|
|
|
556
713
|
|
|
557
714
|
// src/tracing/direct/shipper.ts
|
|
558
715
|
function serializeAssociationValue(value) {
|
|
559
|
-
|
|
560
|
-
return value;
|
|
561
|
-
}
|
|
562
|
-
const jsonValue = JSON.stringify(value);
|
|
563
|
-
return jsonValue === void 0 ? String(value) : jsonValue;
|
|
716
|
+
return stringifyBounded(value);
|
|
564
717
|
}
|
|
565
718
|
var DirectTraceShipper = class {
|
|
566
719
|
constructor(opts) {
|
|
567
720
|
this.queue = [];
|
|
568
721
|
this.inFlight = /* @__PURE__ */ new Set();
|
|
722
|
+
/**
|
|
723
|
+
* Set once `shutdown()` begins and never cleared. Sends issued after the
|
|
724
|
+
* drain window (stragglers, or flush work the deadline abandoned
|
|
725
|
+
* mid-drain) run as a single short attempt instead of regaining the full
|
|
726
|
+
* retry schedule.
|
|
727
|
+
*/
|
|
728
|
+
this.hasShutdown = false;
|
|
569
729
|
var _a, _b, _c, _d, _e, _f;
|
|
570
730
|
this.writeKey = opts.writeKey;
|
|
571
731
|
this.baseUrl = (_a = formatEndpoint2(opts.endpoint)) != null ? _a : "https://api.raindrop.ai/v1/";
|
|
@@ -690,14 +850,19 @@ var DirectTraceShipper = class {
|
|
|
690
850
|
if (this.debug) console.log(`[raindrop] direct: dropped ${batch.length} cloud spans (local-only)`);
|
|
691
851
|
continue;
|
|
692
852
|
}
|
|
853
|
+
const opts = this.requestOpts();
|
|
854
|
+
if (!opts) {
|
|
855
|
+
rateLimitedLog(
|
|
856
|
+
"js-sdk.direct.shutdown_deadline",
|
|
857
|
+
() => console.warn(
|
|
858
|
+
`[raindrop] direct: shutdown flush deadline exceeded; dropping ${batch.length} spans`
|
|
859
|
+
)
|
|
860
|
+
);
|
|
861
|
+
continue;
|
|
862
|
+
}
|
|
693
863
|
const body = buildExportTraceServiceRequest2(batch);
|
|
694
864
|
const url = `${this.baseUrl}traces`;
|
|
695
|
-
const p = postJson2(
|
|
696
|
-
url,
|
|
697
|
-
body,
|
|
698
|
-
{ Authorization: `Bearer ${this.writeKey}` },
|
|
699
|
-
{ maxAttempts: 3, debug: this.debug }
|
|
700
|
-
);
|
|
865
|
+
const p = postJson2(url, body, { Authorization: `Bearer ${this.writeKey}` }, opts);
|
|
701
866
|
this.inFlight.add(p);
|
|
702
867
|
try {
|
|
703
868
|
try {
|
|
@@ -714,14 +879,48 @@ var DirectTraceShipper = class {
|
|
|
714
879
|
}
|
|
715
880
|
}
|
|
716
881
|
}
|
|
882
|
+
/**
|
|
883
|
+
* Retry/timeout options for one batch POST, honoring the shutdown budget:
|
|
884
|
+
* outside shutdown, the normal 3-attempt schedule; during shutdown, a
|
|
885
|
+
* single attempt clamped to the remaining window; `null` once the window
|
|
886
|
+
* is exhausted (caller drops the batch). After shutdown() returns,
|
|
887
|
+
* stragglers run as a single short attempt.
|
|
888
|
+
*/
|
|
889
|
+
requestOpts() {
|
|
890
|
+
if (this.shutdownDeadlineAt !== void 0) {
|
|
891
|
+
const remainingMs = this.shutdownDeadlineAt - Date.now();
|
|
892
|
+
if (remainingMs <= 0) return null;
|
|
893
|
+
return {
|
|
894
|
+
maxAttempts: 1,
|
|
895
|
+
debug: this.debug,
|
|
896
|
+
timeoutMs: Math.min(DEFAULT_REQUEST_TIMEOUT_MS, remainingMs)
|
|
897
|
+
};
|
|
898
|
+
}
|
|
899
|
+
if (this.hasShutdown) {
|
|
900
|
+
return { maxAttempts: 1, debug: this.debug, timeoutMs: POST_SHUTDOWN_TIMEOUT_MS };
|
|
901
|
+
}
|
|
902
|
+
return { maxAttempts: 3, debug: this.debug };
|
|
903
|
+
}
|
|
717
904
|
async shutdown() {
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
905
|
+
this.hasShutdown = true;
|
|
906
|
+
this.shutdownDeadlineAt = Date.now() + SHUTDOWN_DEADLINE_MS;
|
|
907
|
+
try {
|
|
908
|
+
if (this.timer) {
|
|
909
|
+
clearTimeout(this.timer);
|
|
910
|
+
this.timer = void 0;
|
|
911
|
+
}
|
|
912
|
+
const drain = async () => {
|
|
913
|
+
await this.flush();
|
|
914
|
+
await Promise.all([...this.inFlight].map((p) => p.catch(() => {
|
|
915
|
+
})));
|
|
916
|
+
};
|
|
917
|
+
const settled = await raceWithTimeout(drain(), SHUTDOWN_DEADLINE_MS);
|
|
918
|
+
if (!settled && this.debug) {
|
|
919
|
+
console.warn("[raindrop] direct: shutdown deadline exceeded; abandoning in-flight spans");
|
|
920
|
+
}
|
|
921
|
+
} finally {
|
|
922
|
+
this.shutdownDeadlineAt = void 0;
|
|
721
923
|
}
|
|
722
|
-
await this.flush();
|
|
723
|
-
await Promise.all([...this.inFlight].map((p) => p.catch(() => {
|
|
724
|
-
})));
|
|
725
924
|
}
|
|
726
925
|
};
|
|
727
926
|
|
|
@@ -743,7 +942,7 @@ function getPropertiesFromContext(context5) {
|
|
|
743
942
|
...context5.properties || {}
|
|
744
943
|
};
|
|
745
944
|
if (context5.attachments && context5.attachments.length > 0) {
|
|
746
|
-
properties.attachments =
|
|
945
|
+
properties.attachments = stringifyBounded(context5.attachments);
|
|
747
946
|
}
|
|
748
947
|
return properties;
|
|
749
948
|
}
|
|
@@ -761,11 +960,7 @@ function serializeAssociationProperties(properties) {
|
|
|
761
960
|
);
|
|
762
961
|
}
|
|
763
962
|
function serializeSpanValue(value) {
|
|
764
|
-
|
|
765
|
-
return value;
|
|
766
|
-
}
|
|
767
|
-
const jsonValue = JSON.stringify(value);
|
|
768
|
-
return jsonValue === void 0 ? String(value) : jsonValue;
|
|
963
|
+
return stringifyBounded(value);
|
|
769
964
|
}
|
|
770
965
|
function getLocalDebuggerMetadata(context5) {
|
|
771
966
|
return {
|
|
@@ -1044,7 +1239,7 @@ var LiveInteraction = class {
|
|
|
1044
1239
|
error = err instanceof Error ? err.message : String(err);
|
|
1045
1240
|
const endTimeMs2 = Date.now();
|
|
1046
1241
|
const durationMs2 = endTimeMs2 - startTimeMs;
|
|
1047
|
-
const inputStr2 = params.inputParameters ?
|
|
1242
|
+
const inputStr2 = params.inputParameters ? stringifyBounded(params.inputParameters) : void 0;
|
|
1048
1243
|
this.directShipper.sendToolSpan({
|
|
1049
1244
|
name: toolName,
|
|
1050
1245
|
spanId: spanIdB64,
|
|
@@ -1073,8 +1268,8 @@ var LiveInteraction = class {
|
|
|
1073
1268
|
}
|
|
1074
1269
|
const endTimeMs = Date.now();
|
|
1075
1270
|
const durationMs = endTimeMs - startTimeMs;
|
|
1076
|
-
const inputStr = params.inputParameters ?
|
|
1077
|
-
const outputStr = result !== void 0 ?
|
|
1271
|
+
const inputStr = params.inputParameters ? stringifyBounded(params.inputParameters) : void 0;
|
|
1272
|
+
const outputStr = result !== void 0 ? stringifyBounded(result) : void 0;
|
|
1078
1273
|
this.directShipper.sendToolSpan({
|
|
1079
1274
|
name: toolName,
|
|
1080
1275
|
spanId: spanIdB64,
|
|
@@ -1311,8 +1506,8 @@ var LiveInteraction = class {
|
|
|
1311
1506
|
const traceIdB64 = this.ensureTraceId(activeContext.traceIdB64);
|
|
1312
1507
|
const { parentSpanIdB64 } = activeContext;
|
|
1313
1508
|
const spanIdB64 = base64Encode2(randomBytes2(8));
|
|
1314
|
-
const inputStr = input !== void 0 ?
|
|
1315
|
-
const outputStr = output !== void 0 ?
|
|
1509
|
+
const inputStr = input !== void 0 ? stringifyBounded(input) : void 0;
|
|
1510
|
+
const outputStr = output !== void 0 ? stringifyBounded(output) : void 0;
|
|
1316
1511
|
this.directShipper.sendToolSpan({
|
|
1317
1512
|
name,
|
|
1318
1513
|
spanId: spanIdB64,
|
|
@@ -1359,12 +1554,10 @@ var LiveInteraction = class {
|
|
|
1359
1554
|
span.setAttribute("traceloop.span.kind", "tool");
|
|
1360
1555
|
setAssociationProperties(span, properties);
|
|
1361
1556
|
if (input !== void 0) {
|
|
1362
|
-
|
|
1363
|
-
span.setAttribute("traceloop.entity.input", inputStr);
|
|
1557
|
+
span.setAttribute("traceloop.entity.input", stringifyBounded(input));
|
|
1364
1558
|
}
|
|
1365
1559
|
if (output !== void 0) {
|
|
1366
|
-
|
|
1367
|
-
span.setAttribute("traceloop.entity.output", outputStr);
|
|
1560
|
+
span.setAttribute("traceloop.entity.output", stringifyBounded(output));
|
|
1368
1561
|
}
|
|
1369
1562
|
if (durationMs !== void 0) {
|
|
1370
1563
|
span.setAttribute("traceloop.entity.duration_ms", durationMs);
|
|
@@ -1452,8 +1645,8 @@ var LiveTracer = class {
|
|
|
1452
1645
|
if (this.directShipper) {
|
|
1453
1646
|
const { traceIdB64, parentSpanIdB64 } = getActiveTraceContext();
|
|
1454
1647
|
const spanIdB64 = base64Encode2(randomBytes2(8));
|
|
1455
|
-
const inputStr = input !== void 0 ?
|
|
1456
|
-
const outputStr = output !== void 0 ?
|
|
1648
|
+
const inputStr = input !== void 0 ? stringifyBounded(input) : void 0;
|
|
1649
|
+
const outputStr = output !== void 0 ? stringifyBounded(output) : void 0;
|
|
1457
1650
|
this.directShipper.sendToolSpan({
|
|
1458
1651
|
name,
|
|
1459
1652
|
spanId: spanIdB64,
|
|
@@ -1497,12 +1690,10 @@ var LiveTracer = class {
|
|
|
1497
1690
|
});
|
|
1498
1691
|
span.setAttribute("traceloop.span.kind", "tool");
|
|
1499
1692
|
if (input !== void 0) {
|
|
1500
|
-
|
|
1501
|
-
span.setAttribute("traceloop.entity.input", inputStr);
|
|
1693
|
+
span.setAttribute("traceloop.entity.input", stringifyBounded(input));
|
|
1502
1694
|
}
|
|
1503
1695
|
if (output !== void 0) {
|
|
1504
|
-
|
|
1505
|
-
span.setAttribute("traceloop.entity.output", outputStr);
|
|
1696
|
+
span.setAttribute("traceloop.entity.output", stringifyBounded(output));
|
|
1506
1697
|
}
|
|
1507
1698
|
if (durationMs !== void 0) {
|
|
1508
1699
|
span.setAttribute("traceloop.entity.duration_ms", durationMs);
|
|
@@ -1934,6 +2125,7 @@ function getCurrentTraceId() {
|
|
|
1934
2125
|
return (_a = trace4.getSpan(context4.active())) == null ? void 0 : _a.spanContext().traceId;
|
|
1935
2126
|
}
|
|
1936
2127
|
var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
2128
|
+
process.env.TRACELOOP_TELEMETRY = "false";
|
|
1937
2129
|
const {
|
|
1938
2130
|
logLevel,
|
|
1939
2131
|
useExternalOtel,
|
|
@@ -2213,8 +2405,19 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
|
2213
2405
|
};
|
|
2214
2406
|
|
|
2215
2407
|
export {
|
|
2408
|
+
DEFAULT_REQUEST_TIMEOUT_MS,
|
|
2409
|
+
MAX_RETRY_DELAY_MS,
|
|
2410
|
+
redactUrlForLog,
|
|
2411
|
+
rateLimitedLog,
|
|
2412
|
+
raceWithTimeout,
|
|
2413
|
+
setDefaultMaxTextFieldChars,
|
|
2414
|
+
resolveMaxTextFieldChars,
|
|
2415
|
+
capText,
|
|
2416
|
+
stringifyBounded,
|
|
2216
2417
|
resolveLocalDebuggerBaseUrl,
|
|
2217
2418
|
mirrorPartialEventToLocalDebugger,
|
|
2419
|
+
SHUTDOWN_DEADLINE_MS,
|
|
2420
|
+
POST_SHUTDOWN_TIMEOUT_MS,
|
|
2218
2421
|
package_default,
|
|
2219
2422
|
tracing
|
|
2220
2423
|
};
|
package/dist/index.d.mts
CHANGED
|
@@ -735,6 +735,16 @@ interface AnalyticsConfig {
|
|
|
735
735
|
debugLogs?: boolean;
|
|
736
736
|
endpoint?: string;
|
|
737
737
|
redactPii?: boolean;
|
|
738
|
+
/**
|
|
739
|
+
* Per-field character cap applied to ai input/output and serialized
|
|
740
|
+
* tool/span content BEFORE buffering or serialization, so oversized
|
|
741
|
+
* payloads cost the cap — not the payload — on the calling code path
|
|
742
|
+
* (`JSON.stringify` of a multi-MB payload blocks the event loop).
|
|
743
|
+
* Truncated fields end with `...[truncated by raindrop]` and never exceed
|
|
744
|
+
* the cap, marker included. Defaults to 1,000,000 (matching the Python SDK's
|
|
745
|
+
* `max_text_field_chars`).
|
|
746
|
+
*/
|
|
747
|
+
maxTextFieldChars?: number;
|
|
738
748
|
/**
|
|
739
749
|
* Force-enable (or opt out of) Workshop / local-debugger mirroring.
|
|
740
750
|
*
|
|
@@ -855,6 +865,20 @@ declare class Raindrop {
|
|
|
855
865
|
private partialEventBuffer;
|
|
856
866
|
private partialEventTimeouts;
|
|
857
867
|
private inFlightRequests;
|
|
868
|
+
private maxTextFieldChars;
|
|
869
|
+
/**
|
|
870
|
+
* Epoch ms deadline while `close()` is draining; undefined otherwise.
|
|
871
|
+
* Checked before every POST issued during the final flush so a dead or
|
|
872
|
+
* slow network can never wedge process exit.
|
|
873
|
+
*/
|
|
874
|
+
private shutdownDeadlineAt;
|
|
875
|
+
/**
|
|
876
|
+
* Set once `close()` begins and never cleared. Sends issued after the
|
|
877
|
+
* drain window (stragglers, or flush work the deadline abandoned
|
|
878
|
+
* mid-drain) run as a single short attempt instead of regaining the full
|
|
879
|
+
* retry schedule.
|
|
880
|
+
*/
|
|
881
|
+
private hasShutdown;
|
|
858
882
|
debugLogs: boolean;
|
|
859
883
|
constructor(config: AnalyticsConfig);
|
|
860
884
|
private get localOnly();
|
|
@@ -964,6 +988,15 @@ declare class Raindrop {
|
|
|
964
988
|
private saveToBuffer;
|
|
965
989
|
private flush;
|
|
966
990
|
private mirrorBatchToLocalDebugger;
|
|
991
|
+
/**
|
|
992
|
+
* Attempts/timeout budget for one POST, honoring the close() deadline.
|
|
993
|
+
* Returns `null` when the shutdown budget is exhausted — the caller must
|
|
994
|
+
* drop the payload instead of issuing a request that could outlive
|
|
995
|
+
* process exit. Checked fresh on every send so a deadline that expires
|
|
996
|
+
* mid-drain takes effect immediately.
|
|
997
|
+
*/
|
|
998
|
+
private requestBudget;
|
|
999
|
+
private warnShutdownDrop;
|
|
967
1000
|
private sendBatchToApi;
|
|
968
1001
|
private getContext;
|
|
969
1002
|
private formatZodError;
|
|
@@ -1000,6 +1033,7 @@ declare class Raindrop {
|
|
|
1000
1033
|
*/
|
|
1001
1034
|
forceFlush(): Promise<void>;
|
|
1002
1035
|
close(): Promise<void>;
|
|
1036
|
+
private closeWithinDeadline;
|
|
1003
1037
|
}
|
|
1004
1038
|
|
|
1005
1039
|
export { type AiTrackEvent, type Attachment, type AttachmentType, type BeginInteractionOptions, type FinishInteractionOptions, type IdentifyEvent, type Interaction, type LocalDebuggerLiveEventInput, MAX_INGEST_SIZE_BYTES, type PartialAiTrackEvent, Raindrop, type RaindropProperties, type RaindropPropertyLeaf, type RaindropPropertyValue, type RaindropSpanProcessor, type SelfDiagnoseOptions, type SelfDiagnosticsExecuteContext, type SelfDiagnosticsExecuteResult, type SelfDiagnosticsSignalDefinition, type SelfDiagnosticsSignalDefinitions, type SelfDiagnosticsTool, type SelfDiagnosticsToolInputSchema, type SelfDiagnosticsToolOptions, type SignalEvent, type SpanParams, type ToolParams, type ToolSpan, type TraceContext, type Tracer, type TrackToolParams, type WorkflowParams, Raindrop as default };
|
package/dist/index.d.ts
CHANGED
|
@@ -735,6 +735,16 @@ interface AnalyticsConfig {
|
|
|
735
735
|
debugLogs?: boolean;
|
|
736
736
|
endpoint?: string;
|
|
737
737
|
redactPii?: boolean;
|
|
738
|
+
/**
|
|
739
|
+
* Per-field character cap applied to ai input/output and serialized
|
|
740
|
+
* tool/span content BEFORE buffering or serialization, so oversized
|
|
741
|
+
* payloads cost the cap — not the payload — on the calling code path
|
|
742
|
+
* (`JSON.stringify` of a multi-MB payload blocks the event loop).
|
|
743
|
+
* Truncated fields end with `...[truncated by raindrop]` and never exceed
|
|
744
|
+
* the cap, marker included. Defaults to 1,000,000 (matching the Python SDK's
|
|
745
|
+
* `max_text_field_chars`).
|
|
746
|
+
*/
|
|
747
|
+
maxTextFieldChars?: number;
|
|
738
748
|
/**
|
|
739
749
|
* Force-enable (or opt out of) Workshop / local-debugger mirroring.
|
|
740
750
|
*
|
|
@@ -855,6 +865,20 @@ declare class Raindrop {
|
|
|
855
865
|
private partialEventBuffer;
|
|
856
866
|
private partialEventTimeouts;
|
|
857
867
|
private inFlightRequests;
|
|
868
|
+
private maxTextFieldChars;
|
|
869
|
+
/**
|
|
870
|
+
* Epoch ms deadline while `close()` is draining; undefined otherwise.
|
|
871
|
+
* Checked before every POST issued during the final flush so a dead or
|
|
872
|
+
* slow network can never wedge process exit.
|
|
873
|
+
*/
|
|
874
|
+
private shutdownDeadlineAt;
|
|
875
|
+
/**
|
|
876
|
+
* Set once `close()` begins and never cleared. Sends issued after the
|
|
877
|
+
* drain window (stragglers, or flush work the deadline abandoned
|
|
878
|
+
* mid-drain) run as a single short attempt instead of regaining the full
|
|
879
|
+
* retry schedule.
|
|
880
|
+
*/
|
|
881
|
+
private hasShutdown;
|
|
858
882
|
debugLogs: boolean;
|
|
859
883
|
constructor(config: AnalyticsConfig);
|
|
860
884
|
private get localOnly();
|
|
@@ -964,6 +988,15 @@ declare class Raindrop {
|
|
|
964
988
|
private saveToBuffer;
|
|
965
989
|
private flush;
|
|
966
990
|
private mirrorBatchToLocalDebugger;
|
|
991
|
+
/**
|
|
992
|
+
* Attempts/timeout budget for one POST, honoring the close() deadline.
|
|
993
|
+
* Returns `null` when the shutdown budget is exhausted — the caller must
|
|
994
|
+
* drop the payload instead of issuing a request that could outlive
|
|
995
|
+
* process exit. Checked fresh on every send so a deadline that expires
|
|
996
|
+
* mid-drain takes effect immediately.
|
|
997
|
+
*/
|
|
998
|
+
private requestBudget;
|
|
999
|
+
private warnShutdownDrop;
|
|
967
1000
|
private sendBatchToApi;
|
|
968
1001
|
private getContext;
|
|
969
1002
|
private formatZodError;
|
|
@@ -1000,6 +1033,7 @@ declare class Raindrop {
|
|
|
1000
1033
|
*/
|
|
1001
1034
|
forceFlush(): Promise<void>;
|
|
1002
1035
|
close(): Promise<void>;
|
|
1036
|
+
private closeWithinDeadline;
|
|
1003
1037
|
}
|
|
1004
1038
|
|
|
1005
1039
|
export { type AiTrackEvent, type Attachment, type AttachmentType, type BeginInteractionOptions, type FinishInteractionOptions, type IdentifyEvent, type Interaction, type LocalDebuggerLiveEventInput, MAX_INGEST_SIZE_BYTES, type PartialAiTrackEvent, Raindrop, type RaindropProperties, type RaindropPropertyLeaf, type RaindropPropertyValue, type RaindropSpanProcessor, type SelfDiagnoseOptions, type SelfDiagnosticsExecuteContext, type SelfDiagnosticsExecuteResult, type SelfDiagnosticsSignalDefinition, type SelfDiagnosticsSignalDefinitions, type SelfDiagnosticsTool, type SelfDiagnosticsToolInputSchema, type SelfDiagnosticsToolOptions, type SignalEvent, type SpanParams, type ToolParams, type ToolSpan, type TraceContext, type Tracer, type TrackToolParams, type WorkflowParams, Raindrop as default };
|