@raindrop-ai/pi-agent 0.0.3 → 0.0.5
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 +13 -4
- package/dist/{chunk-MHIMKMK7.js → chunk-2NGOEVWI.js} +488 -75
- package/dist/extension.cjs +501 -79
- package/dist/extension.d.cts +2 -2
- package/dist/extension.d.ts +2 -2
- package/dist/extension.js +16 -5
- package/dist/index.cjs +491 -78
- package/dist/index.d-CRPiWjXE.d.cts +369 -0
- package/dist/index.d-CRPiWjXE.d.ts +369 -0
- package/dist/index.d.cts +3 -3
- package/dist/index.d.ts +3 -3
- package/dist/index.js +6 -4
- package/package.json +7 -7
- package/dist/index.d-CtwaEReY.d.cts +0 -228
- package/dist/index.d-CtwaEReY.d.ts +0 -228
package/dist/extension.cjs
CHANGED
|
@@ -25,7 +25,7 @@ __export(extension_exports, {
|
|
|
25
25
|
});
|
|
26
26
|
module.exports = __toCommonJS(extension_exports);
|
|
27
27
|
|
|
28
|
-
// ../core/dist/chunk-
|
|
28
|
+
// ../core/dist/chunk-U5HUTMR5.js
|
|
29
29
|
function getCrypto() {
|
|
30
30
|
const c = globalThis.crypto;
|
|
31
31
|
return c;
|
|
@@ -72,6 +72,8 @@ function base64Encode(bytes) {
|
|
|
72
72
|
function generateId() {
|
|
73
73
|
return base64Encode(randomBytes(12)).replace(/[+/=]/g, "").slice(0, 16);
|
|
74
74
|
}
|
|
75
|
+
var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
|
|
76
|
+
var MAX_RETRY_DELAY_MS = 3e4;
|
|
75
77
|
function wait(ms) {
|
|
76
78
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
77
79
|
}
|
|
@@ -79,6 +81,46 @@ function formatEndpoint(endpoint) {
|
|
|
79
81
|
if (!endpoint) return void 0;
|
|
80
82
|
return endpoint.endsWith("/") ? endpoint : `${endpoint}/`;
|
|
81
83
|
}
|
|
84
|
+
function redactUrlForLog(url) {
|
|
85
|
+
try {
|
|
86
|
+
const parsed = new URL(url);
|
|
87
|
+
parsed.username = "";
|
|
88
|
+
parsed.password = "";
|
|
89
|
+
parsed.search = "";
|
|
90
|
+
parsed.hash = "";
|
|
91
|
+
return parsed.toString();
|
|
92
|
+
} catch (e) {
|
|
93
|
+
return "<unparseable-url>";
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
var RATE_LIMITED_LOG_INTERVAL_MS = 3e4;
|
|
97
|
+
var rateLimitedLogLast = /* @__PURE__ */ new Map();
|
|
98
|
+
function rateLimitedLog(key, log) {
|
|
99
|
+
const now = Date.now();
|
|
100
|
+
const last = rateLimitedLogLast.get(key);
|
|
101
|
+
if (last !== void 0 && now - last < RATE_LIMITED_LOG_INTERVAL_MS) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
rateLimitedLogLast.set(key, now);
|
|
105
|
+
log();
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
async function raceWithTimeout(promise, timeoutMs) {
|
|
109
|
+
let timer;
|
|
110
|
+
const settledInTime = await Promise.race([
|
|
111
|
+
promise.then(
|
|
112
|
+
() => true,
|
|
113
|
+
() => true
|
|
114
|
+
),
|
|
115
|
+
new Promise((resolve) => {
|
|
116
|
+
var _a;
|
|
117
|
+
timer = setTimeout(() => resolve(false), Math.max(0, timeoutMs));
|
|
118
|
+
(_a = timer.unref) == null ? void 0 : _a.call(timer);
|
|
119
|
+
})
|
|
120
|
+
]);
|
|
121
|
+
if (timer) clearTimeout(timer);
|
|
122
|
+
return settledInTime;
|
|
123
|
+
}
|
|
82
124
|
function parseRetryAfter(headers) {
|
|
83
125
|
var _a;
|
|
84
126
|
const value = (_a = headers.get("Retry-After")) != null ? _a : headers.get("retry-after");
|
|
@@ -95,12 +137,12 @@ function parseRetryAfter(headers) {
|
|
|
95
137
|
function getRetryDelayMs(attemptNumber, previousError) {
|
|
96
138
|
if (previousError && typeof previousError === "object" && previousError !== null && "retryAfterMs" in previousError) {
|
|
97
139
|
const v = previousError.retryAfterMs;
|
|
98
|
-
if (typeof v === "number") return Math.max(0, v);
|
|
140
|
+
if (typeof v === "number") return Math.min(Math.max(0, v), MAX_RETRY_DELAY_MS);
|
|
99
141
|
}
|
|
100
142
|
if (attemptNumber <= 1) return 0;
|
|
101
143
|
const base = 500;
|
|
102
144
|
const factor = Math.pow(2, attemptNumber - 2);
|
|
103
|
-
return base * factor;
|
|
145
|
+
return Math.min(base * factor, MAX_RETRY_DELAY_MS);
|
|
104
146
|
}
|
|
105
147
|
async function withRetry(operation, opName, opts) {
|
|
106
148
|
const prefix = opts.sdkName ? `[raindrop-ai/${opts.sdkName}]` : "[raindrop-ai/core]";
|
|
@@ -135,7 +177,9 @@ async function withRetry(operation, opName, opts) {
|
|
|
135
177
|
throw lastError instanceof Error ? lastError : new Error(String(lastError));
|
|
136
178
|
}
|
|
137
179
|
async function postJson(url, body, headers, opts) {
|
|
138
|
-
|
|
180
|
+
var _a;
|
|
181
|
+
const opName = `POST ${redactUrlForLog(url)}`;
|
|
182
|
+
const timeoutMs = (_a = opts.timeoutMs) != null ? _a : DEFAULT_REQUEST_TIMEOUT_MS;
|
|
139
183
|
await withRetry(
|
|
140
184
|
async () => {
|
|
141
185
|
const resp = await fetch(url, {
|
|
@@ -144,7 +188,8 @@ async function postJson(url, body, headers, opts) {
|
|
|
144
188
|
"Content-Type": "application/json",
|
|
145
189
|
...headers
|
|
146
190
|
},
|
|
147
|
-
body: JSON.stringify(body)
|
|
191
|
+
body: JSON.stringify(body),
|
|
192
|
+
signal: AbortSignal.timeout(timeoutMs)
|
|
148
193
|
});
|
|
149
194
|
if (!resp.ok) {
|
|
150
195
|
const text = await resp.text().catch(() => "");
|
|
@@ -161,6 +206,27 @@ async function postJson(url, body, headers, opts) {
|
|
|
161
206
|
opts
|
|
162
207
|
);
|
|
163
208
|
}
|
|
209
|
+
var DEFAULT_MAX_TEXT_FIELD_CHARS = 1e6;
|
|
210
|
+
var TRUNCATION_MARKER = "...[truncated by raindrop]";
|
|
211
|
+
var currentDefaultMaxTextFieldChars = DEFAULT_MAX_TEXT_FIELD_CHARS;
|
|
212
|
+
function resolveMaxTextFieldChars(value) {
|
|
213
|
+
if (typeof value === "number" && Number.isFinite(value) && value > 0) {
|
|
214
|
+
return Math.floor(value);
|
|
215
|
+
}
|
|
216
|
+
return currentDefaultMaxTextFieldChars;
|
|
217
|
+
}
|
|
218
|
+
function truncateToLimit(text, limit) {
|
|
219
|
+
if (limit > TRUNCATION_MARKER.length) {
|
|
220
|
+
return text.slice(0, limit - TRUNCATION_MARKER.length) + TRUNCATION_MARKER;
|
|
221
|
+
}
|
|
222
|
+
return text.slice(0, Math.max(0, limit));
|
|
223
|
+
}
|
|
224
|
+
function capText(value, limit) {
|
|
225
|
+
if (typeof value !== "string") return value;
|
|
226
|
+
const max = limit != null ? limit : currentDefaultMaxTextFieldChars;
|
|
227
|
+
if (value.length <= max) return value;
|
|
228
|
+
return truncateToLimit(value, max);
|
|
229
|
+
}
|
|
164
230
|
var SpanStatusCode = {
|
|
165
231
|
UNSET: 0,
|
|
166
232
|
OK: 1,
|
|
@@ -303,6 +369,8 @@ function mirrorPartialEventToLocalDebugger(event, options = {}) {
|
|
|
303
369
|
}).catch(() => {
|
|
304
370
|
});
|
|
305
371
|
}
|
|
372
|
+
var SHUTDOWN_DEADLINE_MS = 1e4;
|
|
373
|
+
var POST_SHUTDOWN_TIMEOUT_MS = 5e3;
|
|
306
374
|
function mergePatches(target, source) {
|
|
307
375
|
var _a, _b, _c, _d;
|
|
308
376
|
const out = { ...target, ...source };
|
|
@@ -320,6 +388,7 @@ var EventShipper = class {
|
|
|
320
388
|
this.sticky = /* @__PURE__ */ new Map();
|
|
321
389
|
this.timers = /* @__PURE__ */ new Map();
|
|
322
390
|
this.inFlight = /* @__PURE__ */ new Set();
|
|
391
|
+
this.hasShutdown = false;
|
|
323
392
|
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
324
393
|
this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
|
|
325
394
|
this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
|
|
@@ -329,6 +398,7 @@ var EventShipper = class {
|
|
|
329
398
|
this.sdkName = (_d = opts.sdkName) != null ? _d : "core";
|
|
330
399
|
this.prefix = `[raindrop-ai/${this.sdkName}]`;
|
|
331
400
|
this.defaultEventName = (_e = opts.defaultEventName) != null ? _e : "ai_generation";
|
|
401
|
+
this.maxTextFieldCharsOpt = opts.maxTextFieldChars;
|
|
332
402
|
this.localDebuggerUrl = (_f = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _f : void 0;
|
|
333
403
|
if (this.debug && this.localDebuggerUrl) {
|
|
334
404
|
console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
|
|
@@ -351,10 +421,52 @@ var EventShipper = class {
|
|
|
351
421
|
authHeaders() {
|
|
352
422
|
return this.writeKey ? { Authorization: `Bearer ${this.writeKey}` } : {};
|
|
353
423
|
}
|
|
424
|
+
/**
|
|
425
|
+
* Build the retry/timeout options for one POST, honoring the shutdown
|
|
426
|
+
* deadline. Returns `null` when the shutdown drain window is exhausted —
|
|
427
|
+
* the caller must drop the payload (with a rate-limited warning) instead
|
|
428
|
+
* of issuing a request that could outlive process exit.
|
|
429
|
+
*
|
|
430
|
+
* Checked fresh on EVERY send, so a shutdown that begins while the flush
|
|
431
|
+
* path is mid-drain takes effect immediately: no further retries, and the
|
|
432
|
+
* per-attempt timeout is clamped to the remaining window. After
|
|
433
|
+
* `shutdown()` returns (deadline cleared, `hasShutdown` still set),
|
|
434
|
+
* sends — late callers, or flush work the deadline abandoned mid-drain —
|
|
435
|
+
* run as a single short attempt rather than regaining the full retry
|
|
436
|
+
* schedule.
|
|
437
|
+
*/
|
|
438
|
+
requestOpts() {
|
|
439
|
+
if (this.shutdownDeadlineAt !== void 0) {
|
|
440
|
+
const remainingMs = this.shutdownDeadlineAt - Date.now();
|
|
441
|
+
if (remainingMs <= 0) return null;
|
|
442
|
+
return {
|
|
443
|
+
maxAttempts: 1,
|
|
444
|
+
debug: this.debug,
|
|
445
|
+
sdkName: this.sdkName,
|
|
446
|
+
timeoutMs: Math.min(DEFAULT_REQUEST_TIMEOUT_MS, remainingMs)
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
if (this.hasShutdown) {
|
|
450
|
+
return {
|
|
451
|
+
maxAttempts: 1,
|
|
452
|
+
debug: this.debug,
|
|
453
|
+
sdkName: this.sdkName,
|
|
454
|
+
timeoutMs: POST_SHUTDOWN_TIMEOUT_MS
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
return { maxAttempts: 3, debug: this.debug, sdkName: this.sdkName };
|
|
458
|
+
}
|
|
354
459
|
async patch(eventId, patch) {
|
|
355
460
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
356
461
|
if (!this.enabled) return;
|
|
357
462
|
if (!eventId || !eventId.trim()) return;
|
|
463
|
+
const maxChars = resolveMaxTextFieldChars(this.maxTextFieldCharsOpt);
|
|
464
|
+
if (typeof patch.input === "string" && patch.input.length > maxChars) {
|
|
465
|
+
patch = { ...patch, input: capText(patch.input, maxChars) };
|
|
466
|
+
}
|
|
467
|
+
if (typeof patch.output === "string" && patch.output.length > maxChars) {
|
|
468
|
+
patch = { ...patch, output: capText(patch.output, maxChars) };
|
|
469
|
+
}
|
|
358
470
|
if (this.debug) {
|
|
359
471
|
console.log(`${this.prefix} queue patch`, {
|
|
360
472
|
eventId,
|
|
@@ -401,9 +513,16 @@ var EventShipper = class {
|
|
|
401
513
|
})));
|
|
402
514
|
}
|
|
403
515
|
async shutdown() {
|
|
404
|
-
|
|
405
|
-
this.
|
|
406
|
-
|
|
516
|
+
this.hasShutdown = true;
|
|
517
|
+
this.shutdownDeadlineAt = Date.now() + SHUTDOWN_DEADLINE_MS;
|
|
518
|
+
try {
|
|
519
|
+
for (const t of this.timers.values()) clearTimeout(t);
|
|
520
|
+
this.timers.clear();
|
|
521
|
+
const settled = await raceWithTimeout(this.flush(), SHUTDOWN_DEADLINE_MS);
|
|
522
|
+
if (!settled) this.warnShutdownDrop("in-flight request(s) at shutdown");
|
|
523
|
+
} finally {
|
|
524
|
+
this.shutdownDeadlineAt = void 0;
|
|
525
|
+
}
|
|
407
526
|
}
|
|
408
527
|
async trackSignal(signal) {
|
|
409
528
|
var _a, _b;
|
|
@@ -425,15 +544,19 @@ var EventShipper = class {
|
|
|
425
544
|
];
|
|
426
545
|
if (!this.writeKey) return;
|
|
427
546
|
const url = `${this.baseUrl}signals/track`;
|
|
547
|
+
const opts = this.requestOpts();
|
|
548
|
+
if (!opts) {
|
|
549
|
+
this.warnShutdownDrop("signal");
|
|
550
|
+
return;
|
|
551
|
+
}
|
|
428
552
|
try {
|
|
429
|
-
await postJson(url, body, this.authHeaders(),
|
|
430
|
-
maxAttempts: 3,
|
|
431
|
-
debug: this.debug,
|
|
432
|
-
sdkName: this.sdkName
|
|
433
|
-
});
|
|
553
|
+
await postJson(url, body, this.authHeaders(), opts);
|
|
434
554
|
} catch (err) {
|
|
435
555
|
const msg = err instanceof Error ? err.message : String(err);
|
|
436
|
-
|
|
556
|
+
rateLimitedLog(
|
|
557
|
+
`${this.prefix}.send_signal_failed`,
|
|
558
|
+
() => console.warn(`${this.prefix} failed to send signal (dropping): ${msg}`)
|
|
559
|
+
);
|
|
437
560
|
}
|
|
438
561
|
}
|
|
439
562
|
async identify(users) {
|
|
@@ -457,17 +580,27 @@ var EventShipper = class {
|
|
|
457
580
|
if (!this.writeKey) return;
|
|
458
581
|
if (body.length === 0) return;
|
|
459
582
|
const url = `${this.baseUrl}users/identify`;
|
|
583
|
+
const opts = this.requestOpts();
|
|
584
|
+
if (!opts) {
|
|
585
|
+
this.warnShutdownDrop("identify");
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
460
588
|
try {
|
|
461
|
-
await postJson(url, body, this.authHeaders(),
|
|
462
|
-
maxAttempts: 3,
|
|
463
|
-
debug: this.debug,
|
|
464
|
-
sdkName: this.sdkName
|
|
465
|
-
});
|
|
589
|
+
await postJson(url, body, this.authHeaders(), opts);
|
|
466
590
|
} catch (err) {
|
|
467
591
|
const msg = err instanceof Error ? err.message : String(err);
|
|
468
|
-
|
|
592
|
+
rateLimitedLog(
|
|
593
|
+
`${this.prefix}.send_identify_failed`,
|
|
594
|
+
() => console.warn(`${this.prefix} failed to send identify (dropping): ${msg}`)
|
|
595
|
+
);
|
|
469
596
|
}
|
|
470
597
|
}
|
|
598
|
+
warnShutdownDrop(what) {
|
|
599
|
+
rateLimitedLog(
|
|
600
|
+
`${this.prefix}.shutdown_deadline`,
|
|
601
|
+
() => console.warn(`${this.prefix} shutdown flush deadline exceeded; dropping ${what}`)
|
|
602
|
+
);
|
|
603
|
+
}
|
|
471
604
|
async flushOne(eventId) {
|
|
472
605
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
|
|
473
606
|
if (!this.enabled) return;
|
|
@@ -543,11 +676,13 @@ var EventShipper = class {
|
|
|
543
676
|
if (!isPending) this.sticky.delete(eventId);
|
|
544
677
|
return;
|
|
545
678
|
}
|
|
546
|
-
const
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
679
|
+
const opts = this.requestOpts();
|
|
680
|
+
if (!opts) {
|
|
681
|
+
this.warnShutdownDrop(`track_partial ${eventId}`);
|
|
682
|
+
if (!isPending) this.sticky.delete(eventId);
|
|
683
|
+
return;
|
|
684
|
+
}
|
|
685
|
+
const p = postJson(url, payload, this.authHeaders(), opts);
|
|
551
686
|
this.inFlight.add(p);
|
|
552
687
|
try {
|
|
553
688
|
try {
|
|
@@ -557,7 +692,10 @@ var EventShipper = class {
|
|
|
557
692
|
}
|
|
558
693
|
} catch (err) {
|
|
559
694
|
const msg = err instanceof Error ? err.message : String(err);
|
|
560
|
-
|
|
695
|
+
rateLimitedLog(
|
|
696
|
+
`${this.prefix}.send_track_partial_failed`,
|
|
697
|
+
() => console.warn(`${this.prefix} failed to send track_partial (dropping): ${msg}`)
|
|
698
|
+
);
|
|
561
699
|
}
|
|
562
700
|
} finally {
|
|
563
701
|
this.inFlight.delete(p);
|
|
@@ -567,10 +705,113 @@ var EventShipper = class {
|
|
|
567
705
|
}
|
|
568
706
|
}
|
|
569
707
|
};
|
|
708
|
+
var DEFAULT_SECRET_KEY_NAMES = [
|
|
709
|
+
"apikey",
|
|
710
|
+
"apisecret",
|
|
711
|
+
"apitoken",
|
|
712
|
+
"secretaccesskey",
|
|
713
|
+
"sessiontoken",
|
|
714
|
+
"privatekey",
|
|
715
|
+
"privatekeyid",
|
|
716
|
+
"clientsecret",
|
|
717
|
+
"accesstoken",
|
|
718
|
+
"refreshtoken",
|
|
719
|
+
"oauthtoken",
|
|
720
|
+
"bearertoken",
|
|
721
|
+
"authorization",
|
|
722
|
+
"password",
|
|
723
|
+
"passphrase"
|
|
724
|
+
];
|
|
725
|
+
var REDACTED_PLACEHOLDER = "[REDACTED]";
|
|
726
|
+
function normalizeKeyName(name) {
|
|
727
|
+
return name.toLowerCase().replace(/[-_.]/g, "");
|
|
728
|
+
}
|
|
729
|
+
function redactSecretsInObject(value, options) {
|
|
730
|
+
var _a, _b;
|
|
731
|
+
const normalizedSecretSet = buildSecretSet((_a = options == null ? void 0 : options.secretKeyNames) != null ? _a : DEFAULT_SECRET_KEY_NAMES);
|
|
732
|
+
const placeholder = (_b = options == null ? void 0 : options.placeholder) != null ? _b : REDACTED_PLACEHOLDER;
|
|
733
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
734
|
+
const walk = (node) => {
|
|
735
|
+
if (node === null || typeof node !== "object") return node;
|
|
736
|
+
if (seen.has(node)) return "[CIRCULAR]";
|
|
737
|
+
seen.add(node);
|
|
738
|
+
if (Array.isArray(node)) {
|
|
739
|
+
return node.map((item) => walk(item));
|
|
740
|
+
}
|
|
741
|
+
const out = {};
|
|
742
|
+
for (const [k, v] of Object.entries(node)) {
|
|
743
|
+
if (normalizedSecretSet.has(normalizeKeyName(k))) {
|
|
744
|
+
out[k] = placeholder;
|
|
745
|
+
} else {
|
|
746
|
+
out[k] = walk(v);
|
|
747
|
+
}
|
|
748
|
+
}
|
|
749
|
+
return out;
|
|
750
|
+
};
|
|
751
|
+
return walk(value);
|
|
752
|
+
}
|
|
753
|
+
function buildSecretSet(names) {
|
|
754
|
+
const set = /* @__PURE__ */ new Set();
|
|
755
|
+
for (const name of names) set.add(normalizeKeyName(name));
|
|
756
|
+
return set;
|
|
757
|
+
}
|
|
758
|
+
var DEFAULT_REDACT_ATTRIBUTE_KEYS = [
|
|
759
|
+
"ai.request.providerOptions",
|
|
760
|
+
"ai.response.providerMetadata"
|
|
761
|
+
];
|
|
762
|
+
function defaultTransformSpan(span) {
|
|
763
|
+
const attrs = span.attributes;
|
|
764
|
+
if (!attrs || attrs.length === 0) return span;
|
|
765
|
+
let nextAttrs;
|
|
766
|
+
for (let i = 0; i < attrs.length; i++) {
|
|
767
|
+
const attr = attrs[i];
|
|
768
|
+
const redacted = redactJsonAttributeValue(attr.key, attr.value);
|
|
769
|
+
if (redacted === void 0) continue;
|
|
770
|
+
if (!nextAttrs) nextAttrs = attrs.slice();
|
|
771
|
+
nextAttrs[i] = { key: attr.key, value: redacted };
|
|
772
|
+
}
|
|
773
|
+
if (!nextAttrs) return span;
|
|
774
|
+
return { ...span, attributes: nextAttrs };
|
|
775
|
+
}
|
|
776
|
+
var REDACT_JSON_ATTRIBUTE_KEYS = new Set(DEFAULT_REDACT_ATTRIBUTE_KEYS);
|
|
777
|
+
function redactJsonAttributeValue(key, value) {
|
|
778
|
+
if (!REDACT_JSON_ATTRIBUTE_KEYS.has(key)) return void 0;
|
|
779
|
+
const json = value.stringValue;
|
|
780
|
+
if (typeof json !== "string" || json.length === 0) return void 0;
|
|
781
|
+
let parsed;
|
|
782
|
+
try {
|
|
783
|
+
parsed = JSON.parse(json);
|
|
784
|
+
} catch (e) {
|
|
785
|
+
return void 0;
|
|
786
|
+
}
|
|
787
|
+
const scrubbed = redactSecretsInObject(parsed);
|
|
788
|
+
let scrubbedJson;
|
|
789
|
+
try {
|
|
790
|
+
scrubbedJson = JSON.stringify(scrubbed);
|
|
791
|
+
} catch (e) {
|
|
792
|
+
return void 0;
|
|
793
|
+
}
|
|
794
|
+
if (scrubbedJson === json) return void 0;
|
|
795
|
+
return { stringValue: scrubbedJson };
|
|
796
|
+
}
|
|
797
|
+
function applyOtelSpanAttributeLimit(limit) {
|
|
798
|
+
var _a, _b;
|
|
799
|
+
try {
|
|
800
|
+
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;
|
|
801
|
+
if (!raw) return limit;
|
|
802
|
+
const parsed = Number.parseInt(raw, 10);
|
|
803
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
804
|
+
return Math.min(limit, parsed);
|
|
805
|
+
}
|
|
806
|
+
} catch (e) {
|
|
807
|
+
}
|
|
808
|
+
return limit;
|
|
809
|
+
}
|
|
570
810
|
var TraceShipper = class {
|
|
571
811
|
constructor(opts) {
|
|
572
812
|
this.queue = [];
|
|
573
813
|
this.inFlight = /* @__PURE__ */ new Set();
|
|
814
|
+
this.hasShutdown = false;
|
|
574
815
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
575
816
|
this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
|
|
576
817
|
this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
|
|
@@ -588,6 +829,75 @@ var TraceShipper = class {
|
|
|
588
829
|
if (this.debug && this.localDebuggerUrl) {
|
|
589
830
|
console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
|
|
590
831
|
}
|
|
832
|
+
this.transformSpanHook = opts.transformSpan;
|
|
833
|
+
this.disableDefaultRedaction = opts.disableDefaultRedaction === true;
|
|
834
|
+
this.maxTextFieldCharsOpt = opts.maxTextFieldChars;
|
|
835
|
+
}
|
|
836
|
+
/**
|
|
837
|
+
* Cap every string attribute value on the span. O(#attributes) length
|
|
838
|
+
* checks; only oversized values pay a slice. Runs AFTER the redaction
|
|
839
|
+
* pipeline so the default secret-scrub still sees parseable JSON in
|
|
840
|
+
* `ai.request.providerOptions` / `ai.response.providerMetadata` (capping
|
|
841
|
+
* first could cut a JSON blob mid-way, fail the parse, and ship secrets
|
|
842
|
+
* in the surviving prefix).
|
|
843
|
+
*
|
|
844
|
+
* A stricter `OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT` env var is honored
|
|
845
|
+
* for span content, matching the Python SDK and the OTel SDK convention.
|
|
846
|
+
*/
|
|
847
|
+
capSpanAttributes(span) {
|
|
848
|
+
var _a;
|
|
849
|
+
const maxChars = applyOtelSpanAttributeLimit(
|
|
850
|
+
resolveMaxTextFieldChars(this.maxTextFieldCharsOpt)
|
|
851
|
+
);
|
|
852
|
+
const attrs = span.attributes;
|
|
853
|
+
if (!attrs || attrs.length === 0) return span;
|
|
854
|
+
let nextAttrs;
|
|
855
|
+
for (let i = 0; i < attrs.length; i++) {
|
|
856
|
+
const attr = attrs[i];
|
|
857
|
+
const value = (_a = attr.value) == null ? void 0 : _a.stringValue;
|
|
858
|
+
if (typeof value !== "string" || value.length <= maxChars) continue;
|
|
859
|
+
if (!nextAttrs) nextAttrs = attrs.slice();
|
|
860
|
+
nextAttrs[i] = {
|
|
861
|
+
key: attr.key,
|
|
862
|
+
value: { ...attr.value, stringValue: capText(value, maxChars) }
|
|
863
|
+
};
|
|
864
|
+
}
|
|
865
|
+
if (!nextAttrs) return span;
|
|
866
|
+
return { ...span, attributes: nextAttrs };
|
|
867
|
+
}
|
|
868
|
+
/**
|
|
869
|
+
* Apply the user `transformSpan` hook (if any) followed by the default
|
|
870
|
+
* redactor (unless disabled). Returns either the (possibly new) span to
|
|
871
|
+
* ship, or `null` to drop the span entirely.
|
|
872
|
+
*
|
|
873
|
+
* Ordering: user hook runs first so callers can rewrite the span freely
|
|
874
|
+
* (rename attrs, add new ones, scrub things the default doesn't know
|
|
875
|
+
* about). The default redactor then runs on whatever the user produced,
|
|
876
|
+
* acting as the always-on floor for documented BYOK secrets. If the user
|
|
877
|
+
* sets `disableDefaultRedaction: true`, the floor is skipped.
|
|
878
|
+
*
|
|
879
|
+
* Fail-closed: if the user hook throws, the span is dropped — a buggy
|
|
880
|
+
* hook can never accidentally ship raw, un-redacted spans.
|
|
881
|
+
*/
|
|
882
|
+
redactSpan(span) {
|
|
883
|
+
let current = span;
|
|
884
|
+
if (this.transformSpanHook) {
|
|
885
|
+
try {
|
|
886
|
+
const result = this.transformSpanHook(current);
|
|
887
|
+
if (result === null) return null;
|
|
888
|
+
if (result !== void 0) current = result;
|
|
889
|
+
} catch (err) {
|
|
890
|
+
if (this.debug) {
|
|
891
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
892
|
+
console.warn(`${this.prefix} transformSpan hook threw: ${msg}`);
|
|
893
|
+
}
|
|
894
|
+
return null;
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
if (!this.disableDefaultRedaction) {
|
|
898
|
+
current = defaultTransformSpan(current);
|
|
899
|
+
}
|
|
900
|
+
return this.capSpanAttributes(current);
|
|
591
901
|
}
|
|
592
902
|
isDebugEnabled() {
|
|
593
903
|
return this.debug;
|
|
@@ -605,8 +915,8 @@ var TraceShipper = class {
|
|
|
605
915
|
];
|
|
606
916
|
if ((_b = args.attributes) == null ? void 0 : _b.length) attrs.push(...args.attributes);
|
|
607
917
|
const span = { ids, name: args.name, startTimeUnixNano: started, attributes: attrs };
|
|
608
|
-
|
|
609
|
-
|
|
918
|
+
this.mirrorToLocalDebugger(
|
|
919
|
+
buildOtlpSpan({
|
|
610
920
|
ids: span.ids,
|
|
611
921
|
name: span.name,
|
|
612
922
|
startTimeUnixNano: span.startTimeUnixNano,
|
|
@@ -614,16 +924,21 @@ var TraceShipper = class {
|
|
|
614
924
|
// placeholder — will be updated on endSpan
|
|
615
925
|
attributes: span.attributes,
|
|
616
926
|
status: { code: SpanStatusCode.UNSET }
|
|
617
|
-
})
|
|
618
|
-
|
|
619
|
-
mirrorTraceExportToLocalDebugger(body, {
|
|
620
|
-
baseUrl: this.localDebuggerUrl,
|
|
621
|
-
debug: false,
|
|
622
|
-
sdkName: this.sdkName
|
|
623
|
-
});
|
|
624
|
-
}
|
|
927
|
+
})
|
|
928
|
+
);
|
|
625
929
|
return span;
|
|
626
930
|
}
|
|
931
|
+
mirrorToLocalDebugger(span) {
|
|
932
|
+
if (!this.localDebuggerUrl) return;
|
|
933
|
+
const redacted = this.redactSpan(span);
|
|
934
|
+
if (redacted === null) return;
|
|
935
|
+
const body = buildExportTraceServiceRequest([redacted], this.serviceName, this.serviceVersion);
|
|
936
|
+
mirrorTraceExportToLocalDebugger(body, {
|
|
937
|
+
baseUrl: this.localDebuggerUrl,
|
|
938
|
+
debug: false,
|
|
939
|
+
sdkName: this.sdkName
|
|
940
|
+
});
|
|
941
|
+
}
|
|
627
942
|
endSpan(span, extra) {
|
|
628
943
|
var _a, _b;
|
|
629
944
|
if (span.endTimeUnixNano) return;
|
|
@@ -645,14 +960,7 @@ var TraceShipper = class {
|
|
|
645
960
|
status
|
|
646
961
|
});
|
|
647
962
|
this.enqueue(otlp);
|
|
648
|
-
|
|
649
|
-
const body = buildExportTraceServiceRequest([otlp], this.serviceName, this.serviceVersion);
|
|
650
|
-
mirrorTraceExportToLocalDebugger(body, {
|
|
651
|
-
baseUrl: this.localDebuggerUrl,
|
|
652
|
-
debug: false,
|
|
653
|
-
sdkName: this.sdkName
|
|
654
|
-
});
|
|
655
|
-
}
|
|
963
|
+
this.mirrorToLocalDebugger(otlp);
|
|
656
964
|
}
|
|
657
965
|
createSpan(args) {
|
|
658
966
|
var _a;
|
|
@@ -670,14 +978,7 @@ var TraceShipper = class {
|
|
|
670
978
|
status: args.status
|
|
671
979
|
});
|
|
672
980
|
this.enqueue(otlp);
|
|
673
|
-
|
|
674
|
-
const body = buildExportTraceServiceRequest([otlp], this.serviceName, this.serviceVersion);
|
|
675
|
-
mirrorTraceExportToLocalDebugger(body, {
|
|
676
|
-
baseUrl: this.localDebuggerUrl,
|
|
677
|
-
debug: false,
|
|
678
|
-
sdkName: this.sdkName
|
|
679
|
-
});
|
|
680
|
-
}
|
|
981
|
+
this.mirrorToLocalDebugger(otlp);
|
|
681
982
|
}
|
|
682
983
|
enqueue(span) {
|
|
683
984
|
if (!this.enabled) return;
|
|
@@ -689,10 +990,12 @@ var TraceShipper = class {
|
|
|
689
990
|
)}`
|
|
690
991
|
);
|
|
691
992
|
}
|
|
993
|
+
const redacted = this.redactSpan(span);
|
|
994
|
+
if (redacted === null) return;
|
|
692
995
|
if (this.queue.length >= this.maxQueueSize) {
|
|
693
996
|
this.queue.shift();
|
|
694
997
|
}
|
|
695
|
-
this.queue.push(
|
|
998
|
+
this.queue.push(redacted);
|
|
696
999
|
if (this.queue.length >= this.maxBatchSize) {
|
|
697
1000
|
void this.flush().catch(() => {
|
|
698
1001
|
});
|
|
@@ -715,6 +1018,16 @@ var TraceShipper = class {
|
|
|
715
1018
|
while (this.queue.length > 0) {
|
|
716
1019
|
const batch = this.queue.splice(0, this.maxBatchSize);
|
|
717
1020
|
if (!this.writeKey) continue;
|
|
1021
|
+
const opts = this.requestOpts();
|
|
1022
|
+
if (!opts) {
|
|
1023
|
+
rateLimitedLog(
|
|
1024
|
+
`${this.prefix}.shutdown_deadline`,
|
|
1025
|
+
() => console.warn(
|
|
1026
|
+
`${this.prefix} shutdown flush deadline exceeded; dropping ${batch.length} spans`
|
|
1027
|
+
)
|
|
1028
|
+
);
|
|
1029
|
+
continue;
|
|
1030
|
+
}
|
|
718
1031
|
const body = buildExportTraceServiceRequest(batch, this.serviceName, this.serviceVersion);
|
|
719
1032
|
const url = `${this.baseUrl}traces`;
|
|
720
1033
|
if (this.debug) {
|
|
@@ -723,11 +1036,7 @@ var TraceShipper = class {
|
|
|
723
1036
|
endpoint: url
|
|
724
1037
|
});
|
|
725
1038
|
}
|
|
726
|
-
const p = postJson(url, body, this.authHeaders(),
|
|
727
|
-
maxAttempts: 3,
|
|
728
|
-
debug: this.debug,
|
|
729
|
-
sdkName: this.sdkName
|
|
730
|
-
});
|
|
1039
|
+
const p = postJson(url, body, this.authHeaders(), opts);
|
|
731
1040
|
this.inFlight.add(p);
|
|
732
1041
|
try {
|
|
733
1042
|
try {
|
|
@@ -735,21 +1044,61 @@ var TraceShipper = class {
|
|
|
735
1044
|
if (this.debug) console.log(`${this.prefix} sent ${batch.length} spans`);
|
|
736
1045
|
} catch (err) {
|
|
737
1046
|
const msg = err instanceof Error ? err.message : String(err);
|
|
738
|
-
|
|
1047
|
+
rateLimitedLog(
|
|
1048
|
+
`${this.prefix}.send_spans_failed`,
|
|
1049
|
+
() => console.warn(`${this.prefix} failed to send ${batch.length} spans: ${msg}`)
|
|
1050
|
+
);
|
|
739
1051
|
}
|
|
740
1052
|
} finally {
|
|
741
1053
|
this.inFlight.delete(p);
|
|
742
1054
|
}
|
|
743
1055
|
}
|
|
744
1056
|
}
|
|
1057
|
+
/** See EventShipper.requestOpts — same shutdown-budget semantics. */
|
|
1058
|
+
requestOpts() {
|
|
1059
|
+
if (this.shutdownDeadlineAt !== void 0) {
|
|
1060
|
+
const remainingMs = this.shutdownDeadlineAt - Date.now();
|
|
1061
|
+
if (remainingMs <= 0) return null;
|
|
1062
|
+
return {
|
|
1063
|
+
maxAttempts: 1,
|
|
1064
|
+
debug: this.debug,
|
|
1065
|
+
sdkName: this.sdkName,
|
|
1066
|
+
timeoutMs: Math.min(DEFAULT_REQUEST_TIMEOUT_MS, remainingMs)
|
|
1067
|
+
};
|
|
1068
|
+
}
|
|
1069
|
+
if (this.hasShutdown) {
|
|
1070
|
+
return {
|
|
1071
|
+
maxAttempts: 1,
|
|
1072
|
+
debug: this.debug,
|
|
1073
|
+
sdkName: this.sdkName,
|
|
1074
|
+
timeoutMs: POST_SHUTDOWN_TIMEOUT_MS
|
|
1075
|
+
};
|
|
1076
|
+
}
|
|
1077
|
+
return { maxAttempts: 3, debug: this.debug, sdkName: this.sdkName };
|
|
1078
|
+
}
|
|
745
1079
|
async shutdown() {
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
1080
|
+
this.hasShutdown = true;
|
|
1081
|
+
this.shutdownDeadlineAt = Date.now() + SHUTDOWN_DEADLINE_MS;
|
|
1082
|
+
try {
|
|
1083
|
+
if (this.timer) {
|
|
1084
|
+
clearTimeout(this.timer);
|
|
1085
|
+
this.timer = void 0;
|
|
1086
|
+
}
|
|
1087
|
+
const drain = async () => {
|
|
1088
|
+
await this.flush();
|
|
1089
|
+
await Promise.all([...this.inFlight].map((p) => p.catch(() => {
|
|
1090
|
+
})));
|
|
1091
|
+
};
|
|
1092
|
+
const settled = await raceWithTimeout(drain(), SHUTDOWN_DEADLINE_MS);
|
|
1093
|
+
if (!settled) {
|
|
1094
|
+
rateLimitedLog(
|
|
1095
|
+
`${this.prefix}.shutdown_deadline`,
|
|
1096
|
+
() => console.warn(`${this.prefix} shutdown flush deadline exceeded; abandoning in-flight spans`)
|
|
1097
|
+
);
|
|
1098
|
+
}
|
|
1099
|
+
} finally {
|
|
1100
|
+
this.shutdownDeadlineAt = void 0;
|
|
749
1101
|
}
|
|
750
|
-
await this.flush();
|
|
751
|
-
await Promise.all([...this.inFlight].map((p) => p.catch(() => {
|
|
752
|
-
})));
|
|
753
1102
|
}
|
|
754
1103
|
};
|
|
755
1104
|
|
|
@@ -814,7 +1163,7 @@ function resolveLocalWorkshopUrl(fileValue) {
|
|
|
814
1163
|
// package.json
|
|
815
1164
|
var package_default = {
|
|
816
1165
|
name: "@raindrop-ai/pi-agent",
|
|
817
|
-
version: "0.0.
|
|
1166
|
+
version: "0.0.5",
|
|
818
1167
|
description: "Raindrop observability for Pi Agent \u2014 automatic tracing via subscriber or pi-coding-agent extension",
|
|
819
1168
|
type: "module",
|
|
820
1169
|
license: "MIT",
|
|
@@ -864,18 +1213,18 @@ var package_default = {
|
|
|
864
1213
|
"test:watch": "vitest"
|
|
865
1214
|
},
|
|
866
1215
|
peerDependencies: {
|
|
867
|
-
"@
|
|
868
|
-
"@
|
|
1216
|
+
"@earendil-works/pi-agent-core": ">=0.74.0",
|
|
1217
|
+
"@earendil-works/pi-coding-agent": ">=0.74.0"
|
|
869
1218
|
},
|
|
870
1219
|
peerDependenciesMeta: {
|
|
871
|
-
"@
|
|
1220
|
+
"@earendil-works/pi-coding-agent": {
|
|
872
1221
|
optional: true
|
|
873
1222
|
}
|
|
874
1223
|
},
|
|
875
1224
|
devDependencies: {
|
|
876
1225
|
"@raindrop-ai/core": "workspace:*",
|
|
877
|
-
"@
|
|
878
|
-
"@
|
|
1226
|
+
"@earendil-works/pi-agent-core": "^0.78.0",
|
|
1227
|
+
"@earendil-works/pi-coding-agent": "^0.78.0",
|
|
879
1228
|
"@types/node": "^20.11.17",
|
|
880
1229
|
msw: "^2.12.7",
|
|
881
1230
|
tsup: "^8.5.1",
|
|
@@ -969,19 +1318,82 @@ function formatToolSpanName(toolName, args) {
|
|
|
969
1318
|
}
|
|
970
1319
|
return toolName;
|
|
971
1320
|
}
|
|
972
|
-
|
|
1321
|
+
var TRUNCATION_MARKER2 = "...[truncated by raindrop]";
|
|
1322
|
+
var MAX_TEXT_FIELD_CHARS = 1e6;
|
|
1323
|
+
var MAX_ATTR_LENGTH = 32768;
|
|
1324
|
+
var MAX_BOUNDED_DEPTH = 12;
|
|
1325
|
+
function capText2(value, limit = MAX_TEXT_FIELD_CHARS) {
|
|
1326
|
+
if (value.length <= limit) return value;
|
|
1327
|
+
if (limit > TRUNCATION_MARKER2.length) {
|
|
1328
|
+
return value.slice(0, limit - TRUNCATION_MARKER2.length) + TRUNCATION_MARKER2;
|
|
1329
|
+
}
|
|
1330
|
+
return value.slice(0, limit);
|
|
1331
|
+
}
|
|
1332
|
+
function boundedClone2(value, budget, depth) {
|
|
1333
|
+
if (budget.remaining <= 0) return TRUNCATION_MARKER2;
|
|
1334
|
+
if (typeof value === "string") {
|
|
1335
|
+
if (value.length > budget.remaining) {
|
|
1336
|
+
const taken = value.slice(0, Math.max(0, budget.remaining)) + TRUNCATION_MARKER2;
|
|
1337
|
+
budget.remaining = 0;
|
|
1338
|
+
return taken;
|
|
1339
|
+
}
|
|
1340
|
+
budget.remaining -= Math.max(value.length, 1);
|
|
1341
|
+
return value;
|
|
1342
|
+
}
|
|
1343
|
+
if (value === null || typeof value === "number" || typeof value === "boolean") {
|
|
1344
|
+
budget.remaining -= 8;
|
|
1345
|
+
return value;
|
|
1346
|
+
}
|
|
1347
|
+
if (typeof value !== "object") {
|
|
1348
|
+
budget.remaining -= 8;
|
|
1349
|
+
return value;
|
|
1350
|
+
}
|
|
1351
|
+
if (depth >= MAX_BOUNDED_DEPTH) {
|
|
1352
|
+
budget.remaining -= 16;
|
|
1353
|
+
return `<max depth: ${TRUNCATION_MARKER2}>`;
|
|
1354
|
+
}
|
|
1355
|
+
const withToJson = value;
|
|
1356
|
+
if (typeof withToJson.toJSON === "function") {
|
|
1357
|
+
try {
|
|
1358
|
+
return boundedClone2(withToJson.toJSON(), budget, depth + 1);
|
|
1359
|
+
} catch (e) {
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
if (Array.isArray(value)) {
|
|
1363
|
+
const out2 = [];
|
|
1364
|
+
for (const item of value) {
|
|
1365
|
+
if (budget.remaining <= 0) {
|
|
1366
|
+
out2.push(TRUNCATION_MARKER2);
|
|
1367
|
+
break;
|
|
1368
|
+
}
|
|
1369
|
+
out2.push(boundedClone2(item, budget, depth + 1));
|
|
1370
|
+
}
|
|
1371
|
+
return out2;
|
|
1372
|
+
}
|
|
1373
|
+
const out = {};
|
|
1374
|
+
for (const key of Object.keys(value)) {
|
|
1375
|
+
if (budget.remaining <= 0) {
|
|
1376
|
+
out["..."] = TRUNCATION_MARKER2;
|
|
1377
|
+
break;
|
|
1378
|
+
}
|
|
1379
|
+
budget.remaining -= Math.max(key.length, 1);
|
|
1380
|
+
out[key] = boundedClone2(value[key], budget, depth + 1);
|
|
1381
|
+
}
|
|
1382
|
+
return out;
|
|
1383
|
+
}
|
|
1384
|
+
function safeStringify(value, limit = MAX_ATTR_LENGTH) {
|
|
973
1385
|
if (value === void 0 || value === null) return void 0;
|
|
974
1386
|
try {
|
|
975
|
-
|
|
1387
|
+
const pruned = boundedClone2(value, { remaining: limit + TRUNCATION_MARKER2.length + 256 }, 0);
|
|
1388
|
+
return JSON.stringify(pruned);
|
|
976
1389
|
} catch (e) {
|
|
977
1390
|
try {
|
|
978
|
-
return String(value);
|
|
1391
|
+
return capText2(String(value), limit);
|
|
979
1392
|
} catch (e2) {
|
|
980
1393
|
return "[unserializable]";
|
|
981
1394
|
}
|
|
982
1395
|
}
|
|
983
1396
|
}
|
|
984
|
-
var MAX_ATTR_LENGTH = 32768;
|
|
985
1397
|
function truncate(value) {
|
|
986
1398
|
if (value === void 0) return void 0;
|
|
987
1399
|
if (value.length <= MAX_ATTR_LENGTH) return value;
|
|
@@ -1020,6 +1432,15 @@ function safeParsArgs(argsStr) {
|
|
|
1020
1432
|
}
|
|
1021
1433
|
}
|
|
1022
1434
|
var MAX_SYSTEM_PROMPT_LENGTH = 32768;
|
|
1435
|
+
var ERROR_LOG_INTERVAL_MS = 3e4;
|
|
1436
|
+
var lastErrorLogAt = /* @__PURE__ */ new Map();
|
|
1437
|
+
function rateLimitedErrorLog(key, message) {
|
|
1438
|
+
const now = Date.now();
|
|
1439
|
+
const last = lastErrorLogAt.get(key);
|
|
1440
|
+
if (last !== void 0 && now - last < ERROR_LOG_INTERVAL_MS) return;
|
|
1441
|
+
lastErrorLogAt.set(key, now);
|
|
1442
|
+
console.log(message);
|
|
1443
|
+
}
|
|
1023
1444
|
function createSessionState(sessionId) {
|
|
1024
1445
|
return {
|
|
1025
1446
|
sessionId,
|
|
@@ -1084,7 +1505,8 @@ function getState(stateRef, ctx) {
|
|
|
1084
1505
|
function registerTracing(pi, config, eventShipper, traceShipper) {
|
|
1085
1506
|
const stateRef = {};
|
|
1086
1507
|
function logError(hook, err) {
|
|
1087
|
-
|
|
1508
|
+
rateLimitedErrorLog(
|
|
1509
|
+
hook,
|
|
1088
1510
|
`[raindrop-ai/pi-agent] [error] Error in ${hook}: ${err instanceof Error ? err.message : String(err)}`
|
|
1089
1511
|
);
|
|
1090
1512
|
}
|
|
@@ -1137,7 +1559,7 @@ function registerTracing(pi, config, eventShipper, traceShipper) {
|
|
|
1137
1559
|
}
|
|
1138
1560
|
state.toolSpanStarts.clear();
|
|
1139
1561
|
state.toolCallToLlmParent.clear();
|
|
1140
|
-
state.currentInput = event.prompt;
|
|
1562
|
+
state.currentInput = capText2(event.prompt);
|
|
1141
1563
|
state.turnNumber = 0;
|
|
1142
1564
|
state.currentSystemPrompt = config.captureSystemPrompt ? truncateSystemPrompt(event.systemPrompt) : void 0;
|
|
1143
1565
|
state.currentEventRequestId = generateId();
|
|
@@ -1158,7 +1580,7 @@ function registerTracing(pi, config, eventShipper, traceShipper) {
|
|
|
1158
1580
|
userId: getUserId(state, config.eventMetadata),
|
|
1159
1581
|
convoId: state.sessionId,
|
|
1160
1582
|
eventName: getEventName(config),
|
|
1161
|
-
input:
|
|
1583
|
+
input: state.currentInput,
|
|
1162
1584
|
...attachments.length > 0 ? { attachments } : {},
|
|
1163
1585
|
properties: getBaseProperties(config, ctx)
|
|
1164
1586
|
});
|
|
@@ -1209,7 +1631,7 @@ function registerTracing(pi, config, eventShipper, traceShipper) {
|
|
|
1209
1631
|
const modelId = (_c = message.model) != null ? _c : "";
|
|
1210
1632
|
const modelName = provider && modelId ? `${provider}/${modelId}` : modelId || "llm";
|
|
1211
1633
|
const errorForSpan = getAssistantError(message);
|
|
1212
|
-
const outputText = getAssistantText(message);
|
|
1634
|
+
const outputText = capText2(getAssistantText(message));
|
|
1213
1635
|
const inputTokens = (_d = message.usage) == null ? void 0 : _d.input;
|
|
1214
1636
|
const outputTokens = (_e = message.usage) == null ? void 0 : _e.output;
|
|
1215
1637
|
const cacheReadTokens = (_f = message.usage) == null ? void 0 : _f.cacheRead;
|