@raindrop-ai/pi-agent 0.0.2 → 0.0.4
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/LICENSE +21 -0
- package/README.md +5 -5
- package/dist/{chunk-LZIGXU2D.js → chunk-EWIO36KH.js} +353 -150
- package/dist/extension.cjs +418 -197
- package/dist/extension.d.cts +12 -2
- package/dist/extension.d.ts +12 -2
- package/dist/extension.js +27 -7
- package/dist/index.cjs +269 -63
- package/dist/{index.d-npTVS9Mf.d.cts → index.d-Cxs_NTx0.d.cts} +82 -1
- package/dist/{index.d-npTVS9Mf.d.ts → index.d-Cxs_NTx0.d.ts} +82 -1
- package/dist/index.d.cts +12 -4
- package/dist/index.d.ts +12 -4
- package/dist/index.js +11 -6
- package/package.json +16 -16
package/dist/extension.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ExtensionAPI } from '@
|
|
2
|
-
import { E as EventShipper$1, T as TraceShipper$1, O as OtlpSpan } from './index.d-
|
|
1
|
+
import { ExtensionAPI } from '@earendil-works/pi-coding-agent';
|
|
2
|
+
import { E as EventShipper$1, T as TraceShipper$1, O as OtlpSpan } from './index.d-Cxs_NTx0.cjs';
|
|
3
3
|
|
|
4
4
|
interface EventMetadata {
|
|
5
5
|
userId?: string;
|
|
@@ -13,6 +13,13 @@ interface RaindropExtensionConfig {
|
|
|
13
13
|
debug: boolean;
|
|
14
14
|
captureSystemPrompt: boolean;
|
|
15
15
|
eventMetadata?: EventMetadata;
|
|
16
|
+
/**
|
|
17
|
+
* Explicit Workshop / local debugger URL forwarded to both shippers as their
|
|
18
|
+
* `localDebuggerUrl`. `null` opts out (overrides `RAINDROP_LOCAL_DEBUGGER` /
|
|
19
|
+
* `RAINDROP_WORKSHOP` env vars and auto-detect). `undefined` falls through to
|
|
20
|
+
* the env / auto-detect resolution in `@raindrop-ai/core`.
|
|
21
|
+
*/
|
|
22
|
+
localWorkshopUrl?: string | null;
|
|
16
23
|
}
|
|
17
24
|
|
|
18
25
|
declare class EventShipper extends EventShipper$1 {
|
|
@@ -49,6 +56,9 @@ declare function registerTracing(pi: ExtensionAPI, config: RaindropExtensionConf
|
|
|
49
56
|
* RAINDROP_API_URL — custom endpoint (default: https://api.raindrop.ai/v1)
|
|
50
57
|
* RAINDROP_DEBUG — enable debug logging
|
|
51
58
|
* RAINDROP_CAPTURE_SYSTEM_PROMPT — capture system prompts in traces
|
|
59
|
+
* RAINDROP_LOCAL_WORKSHOP_URL — mirror to a local Raindrop Workshop daemon
|
|
60
|
+
* in addition to the cloud endpoint. Pass `null`, `""`, or `"false"` to
|
|
61
|
+
* opt out of all auto-detection.
|
|
52
62
|
*
|
|
53
63
|
* Config file locations:
|
|
54
64
|
* ~/.pi/agent/raindrop.json (global)
|
package/dist/extension.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ExtensionAPI } from '@
|
|
2
|
-
import { E as EventShipper$1, T as TraceShipper$1, O as OtlpSpan } from './index.d-
|
|
1
|
+
import { ExtensionAPI } from '@earendil-works/pi-coding-agent';
|
|
2
|
+
import { E as EventShipper$1, T as TraceShipper$1, O as OtlpSpan } from './index.d-Cxs_NTx0.js';
|
|
3
3
|
|
|
4
4
|
interface EventMetadata {
|
|
5
5
|
userId?: string;
|
|
@@ -13,6 +13,13 @@ interface RaindropExtensionConfig {
|
|
|
13
13
|
debug: boolean;
|
|
14
14
|
captureSystemPrompt: boolean;
|
|
15
15
|
eventMetadata?: EventMetadata;
|
|
16
|
+
/**
|
|
17
|
+
* Explicit Workshop / local debugger URL forwarded to both shippers as their
|
|
18
|
+
* `localDebuggerUrl`. `null` opts out (overrides `RAINDROP_LOCAL_DEBUGGER` /
|
|
19
|
+
* `RAINDROP_WORKSHOP` env vars and auto-detect). `undefined` falls through to
|
|
20
|
+
* the env / auto-detect resolution in `@raindrop-ai/core`.
|
|
21
|
+
*/
|
|
22
|
+
localWorkshopUrl?: string | null;
|
|
16
23
|
}
|
|
17
24
|
|
|
18
25
|
declare class EventShipper extends EventShipper$1 {
|
|
@@ -49,6 +56,9 @@ declare function registerTracing(pi: ExtensionAPI, config: RaindropExtensionConf
|
|
|
49
56
|
* RAINDROP_API_URL — custom endpoint (default: https://api.raindrop.ai/v1)
|
|
50
57
|
* RAINDROP_DEBUG — enable debug logging
|
|
51
58
|
* RAINDROP_CAPTURE_SYSTEM_PROMPT — capture system prompts in traces
|
|
59
|
+
* RAINDROP_LOCAL_WORKSHOP_URL — mirror to a local Raindrop Workshop daemon
|
|
60
|
+
* in addition to the cloud endpoint. Pass `null`, `""`, or `"false"` to
|
|
61
|
+
* opt out of all auto-detection.
|
|
52
62
|
*
|
|
53
63
|
* Config file locations:
|
|
54
64
|
* ~/.pi/agent/raindrop.json (global)
|
package/dist/extension.js
CHANGED
|
@@ -10,9 +10,10 @@ import {
|
|
|
10
10
|
getUsername,
|
|
11
11
|
libraryVersion,
|
|
12
12
|
nowUnixNanoString,
|
|
13
|
+
resolveLocalDebuggerBaseUrl,
|
|
13
14
|
safeStringify,
|
|
14
15
|
truncate
|
|
15
|
-
} from "./chunk-
|
|
16
|
+
} from "./chunk-EWIO36KH.js";
|
|
16
17
|
|
|
17
18
|
// src/internal/config.ts
|
|
18
19
|
import { existsSync, readFileSync } from "fs";
|
|
@@ -53,9 +54,20 @@ function loadConfig(projectDirectory) {
|
|
|
53
54
|
eventName: (_e = merged.event_name) != null ? _e : "pi_session",
|
|
54
55
|
debug: process.env["RAINDROP_DEBUG"] === "true" ? true : (_f = merged.debug) != null ? _f : false,
|
|
55
56
|
captureSystemPrompt: process.env["RAINDROP_CAPTURE_SYSTEM_PROMPT"] !== void 0 ? process.env["RAINDROP_CAPTURE_SYSTEM_PROMPT"] === "true" : (_g = merged.capture_system_prompt) != null ? _g : false,
|
|
56
|
-
eventMetadata
|
|
57
|
+
eventMetadata,
|
|
58
|
+
localWorkshopUrl: resolveLocalWorkshopUrl(merged.local_workshop_url)
|
|
57
59
|
};
|
|
58
60
|
}
|
|
61
|
+
function resolveLocalWorkshopUrl(fileValue) {
|
|
62
|
+
const envValue = process.env["RAINDROP_LOCAL_WORKSHOP_URL"];
|
|
63
|
+
if (envValue !== void 0) {
|
|
64
|
+
if (envValue === "" || envValue.toLowerCase() === "null" || envValue.toLowerCase() === "false") {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
return envValue;
|
|
68
|
+
}
|
|
69
|
+
return fileValue;
|
|
70
|
+
}
|
|
59
71
|
|
|
60
72
|
// src/internal/extension-tracing.ts
|
|
61
73
|
function safeParsArgs(argsStr) {
|
|
@@ -424,25 +436,33 @@ function extension(pi) {
|
|
|
424
436
|
console.log(`[raindrop-ai/pi-agent] [${level}] ${message}`);
|
|
425
437
|
}
|
|
426
438
|
appLog("info", `Loading ${PLUGIN_NAME} v${libraryVersion}`);
|
|
427
|
-
|
|
439
|
+
const resolvedLocalUrl = resolveLocalDebuggerBaseUrl(config.localWorkshopUrl);
|
|
440
|
+
const hasLocalDestination = resolvedLocalUrl !== null;
|
|
441
|
+
if (!config.writeKey && !hasLocalDestination) {
|
|
428
442
|
appLog(
|
|
429
443
|
"warn",
|
|
430
|
-
"RAINDROP_WRITE_KEY not set \u2014 Raindrop tracing disabled. Set
|
|
444
|
+
"RAINDROP_WRITE_KEY not set and no local Workshop daemon detected \u2014 Raindrop tracing disabled. Set RAINDROP_WRITE_KEY for cloud, or RAINDROP_LOCAL_WORKSHOP_URL / RAINDROP_LOCAL_DEBUGGER for local-only mode."
|
|
431
445
|
);
|
|
432
446
|
return;
|
|
433
447
|
}
|
|
434
448
|
if (config.debug) {
|
|
435
|
-
|
|
449
|
+
const destinations = [
|
|
450
|
+
config.writeKey ? `cloud (${config.endpoint})` : null,
|
|
451
|
+
resolvedLocalUrl ? `local Workshop (${resolvedLocalUrl})` : null
|
|
452
|
+
].filter(Boolean);
|
|
453
|
+
appLog("info", `Raindrop tracing enabled \u2014 destinations: ${destinations.join(", ")}`);
|
|
436
454
|
}
|
|
437
455
|
const eventShipper = new EventShipper({
|
|
438
456
|
writeKey: config.writeKey,
|
|
439
457
|
endpoint: config.endpoint,
|
|
440
|
-
debug: config.debug
|
|
458
|
+
debug: config.debug,
|
|
459
|
+
localDebuggerUrl: config.localWorkshopUrl
|
|
441
460
|
});
|
|
442
461
|
const traceShipper = new TraceShipper({
|
|
443
462
|
writeKey: config.writeKey,
|
|
444
463
|
endpoint: config.endpoint,
|
|
445
|
-
debug: config.debug
|
|
464
|
+
debug: config.debug,
|
|
465
|
+
localDebuggerUrl: config.localWorkshopUrl
|
|
446
466
|
});
|
|
447
467
|
registerTracing(pi, config, eventShipper, traceShipper);
|
|
448
468
|
}
|
package/dist/index.cjs
CHANGED
|
@@ -24,7 +24,7 @@ __export(index_exports, {
|
|
|
24
24
|
});
|
|
25
25
|
module.exports = __toCommonJS(index_exports);
|
|
26
26
|
|
|
27
|
-
// ../core/dist/chunk-
|
|
27
|
+
// ../core/dist/chunk-VUNUOE2X.js
|
|
28
28
|
function getCrypto() {
|
|
29
29
|
const c = globalThis.crypto;
|
|
30
30
|
return c;
|
|
@@ -225,6 +225,91 @@ function buildExportTraceServiceRequest(spans, serviceName = "raindrop.core", se
|
|
|
225
225
|
]
|
|
226
226
|
};
|
|
227
227
|
}
|
|
228
|
+
var LOCAL_DEBUGGER_ENV_VAR = "RAINDROP_LOCAL_DEBUGGER";
|
|
229
|
+
var WORKSHOP_ENV_VAR = "RAINDROP_WORKSHOP";
|
|
230
|
+
var DEFAULT_LOCAL_WORKSHOP_URL = "http://localhost:5899/v1/";
|
|
231
|
+
function readEnvVar(name) {
|
|
232
|
+
var _a;
|
|
233
|
+
try {
|
|
234
|
+
const env = (_a = globalThis == null ? void 0 : globalThis.process) == null ? void 0 : _a.env;
|
|
235
|
+
if (env && typeof env[name] === "string" && env[name].length > 0) {
|
|
236
|
+
return env[name];
|
|
237
|
+
}
|
|
238
|
+
} catch (e) {
|
|
239
|
+
}
|
|
240
|
+
return void 0;
|
|
241
|
+
}
|
|
242
|
+
function readWorkshopEnv() {
|
|
243
|
+
const raw = readEnvVar(WORKSHOP_ENV_VAR);
|
|
244
|
+
if (raw === void 0) return void 0;
|
|
245
|
+
const trimmed = raw.trim();
|
|
246
|
+
if (trimmed.length === 0) return void 0;
|
|
247
|
+
if (/^https?:\/\//i.test(trimmed)) return { url: trimmed };
|
|
248
|
+
if (/^(1|true|yes|on)$/i.test(trimmed)) return "enable";
|
|
249
|
+
if (/^(0|false|no|off)$/i.test(trimmed)) return "disable";
|
|
250
|
+
return void 0;
|
|
251
|
+
}
|
|
252
|
+
function isLocalDevHost(hostname2) {
|
|
253
|
+
if (!hostname2) return false;
|
|
254
|
+
if (hostname2 === "localhost" || hostname2 === "127.0.0.1" || hostname2 === "0.0.0.0" || hostname2 === "::1") {
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
if (hostname2.endsWith(".localhost")) return true;
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
function readRuntimeHostname() {
|
|
261
|
+
try {
|
|
262
|
+
const loc = globalThis == null ? void 0 : globalThis.location;
|
|
263
|
+
if (loc && typeof loc.hostname === "string" && loc.hostname.length > 0) {
|
|
264
|
+
return loc.hostname;
|
|
265
|
+
}
|
|
266
|
+
} catch (e) {
|
|
267
|
+
}
|
|
268
|
+
return void 0;
|
|
269
|
+
}
|
|
270
|
+
function shouldAutoEnableLocalWorkshop() {
|
|
271
|
+
if (isLocalDevHost(readRuntimeHostname())) return true;
|
|
272
|
+
if (readEnvVar("NODE_ENV") === "development") return true;
|
|
273
|
+
return false;
|
|
274
|
+
}
|
|
275
|
+
function resolveLocalDebuggerBaseUrl(baseUrl) {
|
|
276
|
+
var _a, _b, _c;
|
|
277
|
+
if (baseUrl === null) return null;
|
|
278
|
+
if (typeof baseUrl === "string" && baseUrl.length > 0) {
|
|
279
|
+
return (_a = formatEndpoint(baseUrl)) != null ? _a : null;
|
|
280
|
+
}
|
|
281
|
+
const explicitUrlEnv = readEnvVar(LOCAL_DEBUGGER_ENV_VAR);
|
|
282
|
+
if (explicitUrlEnv) return (_b = formatEndpoint(explicitUrlEnv)) != null ? _b : null;
|
|
283
|
+
const workshopEnv = readWorkshopEnv();
|
|
284
|
+
if (workshopEnv === "disable") return null;
|
|
285
|
+
if (workshopEnv === "enable") return DEFAULT_LOCAL_WORKSHOP_URL;
|
|
286
|
+
if (workshopEnv && "url" in workshopEnv) return (_c = formatEndpoint(workshopEnv.url)) != null ? _c : null;
|
|
287
|
+
if (shouldAutoEnableLocalWorkshop()) return DEFAULT_LOCAL_WORKSHOP_URL;
|
|
288
|
+
return null;
|
|
289
|
+
}
|
|
290
|
+
function mirrorTraceExportToLocalDebugger(body, options = {}) {
|
|
291
|
+
var _a;
|
|
292
|
+
const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
|
|
293
|
+
if (!baseUrl) return;
|
|
294
|
+
void postJson(`${baseUrl}traces`, body, {}, {
|
|
295
|
+
maxAttempts: 1,
|
|
296
|
+
debug: (_a = options.debug) != null ? _a : false,
|
|
297
|
+
sdkName: options.sdkName
|
|
298
|
+
}).catch(() => {
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
function mirrorPartialEventToLocalDebugger(event, options = {}) {
|
|
302
|
+
var _a;
|
|
303
|
+
const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
|
|
304
|
+
if (!baseUrl) return;
|
|
305
|
+
const headers = options.writeKey ? { Authorization: `Bearer ${options.writeKey}` } : {};
|
|
306
|
+
void postJson(`${baseUrl}events/track_partial`, event, headers, {
|
|
307
|
+
maxAttempts: 1,
|
|
308
|
+
debug: (_a = options.debug) != null ? _a : false,
|
|
309
|
+
sdkName: options.sdkName
|
|
310
|
+
}).catch(() => {
|
|
311
|
+
});
|
|
312
|
+
}
|
|
228
313
|
function mergePatches(target, source) {
|
|
229
314
|
var _a, _b, _c, _d;
|
|
230
315
|
const out = { ...target, ...source };
|
|
@@ -242,7 +327,7 @@ var EventShipper = class {
|
|
|
242
327
|
this.sticky = /* @__PURE__ */ new Map();
|
|
243
328
|
this.timers = /* @__PURE__ */ new Map();
|
|
244
329
|
this.inFlight = /* @__PURE__ */ new Set();
|
|
245
|
-
var _a, _b, _c, _d, _e, _f, _g;
|
|
330
|
+
var _a, _b, _c, _d, _e, _f, _g, _h;
|
|
246
331
|
this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
|
|
247
332
|
this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
|
|
248
333
|
this.enabled = opts.enabled !== false;
|
|
@@ -251,11 +336,15 @@ var EventShipper = class {
|
|
|
251
336
|
this.sdkName = (_d = opts.sdkName) != null ? _d : "core";
|
|
252
337
|
this.prefix = `[raindrop-ai/${this.sdkName}]`;
|
|
253
338
|
this.defaultEventName = (_e = opts.defaultEventName) != null ? _e : "ai_generation";
|
|
339
|
+
this.localDebuggerUrl = (_f = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _f : void 0;
|
|
340
|
+
if (this.debug && this.localDebuggerUrl) {
|
|
341
|
+
console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
|
|
342
|
+
}
|
|
254
343
|
const isNode = typeof process !== "undefined" && typeof process.version === "string";
|
|
255
344
|
this.context = {
|
|
256
345
|
library: {
|
|
257
|
-
name: (
|
|
258
|
-
version: (
|
|
346
|
+
name: (_g = opts.libraryName) != null ? _g : "@raindrop-ai/core",
|
|
347
|
+
version: (_h = opts.libraryVersion) != null ? _h : "0.0.0"
|
|
259
348
|
},
|
|
260
349
|
metadata: {
|
|
261
350
|
jsRuntime: isNode ? "node" : "web",
|
|
@@ -341,6 +430,7 @@ var EventShipper = class {
|
|
|
341
430
|
}
|
|
342
431
|
}
|
|
343
432
|
];
|
|
433
|
+
if (!this.writeKey) return;
|
|
344
434
|
const url = `${this.baseUrl}signals/track`;
|
|
345
435
|
try {
|
|
346
436
|
await postJson(url, body, this.authHeaders(), {
|
|
@@ -371,6 +461,7 @@ var EventShipper = class {
|
|
|
371
461
|
traits: (_a = user.traits) != null ? _a : {}
|
|
372
462
|
};
|
|
373
463
|
});
|
|
464
|
+
if (!this.writeKey) return;
|
|
374
465
|
if (body.length === 0) return;
|
|
375
466
|
const url = `${this.baseUrl}users/identify`;
|
|
376
467
|
try {
|
|
@@ -447,6 +538,18 @@ var EventShipper = class {
|
|
|
447
538
|
endpoint: url
|
|
448
539
|
});
|
|
449
540
|
}
|
|
541
|
+
if (this.localDebuggerUrl) {
|
|
542
|
+
mirrorPartialEventToLocalDebugger(payload, {
|
|
543
|
+
baseUrl: this.localDebuggerUrl,
|
|
544
|
+
writeKey: this.writeKey,
|
|
545
|
+
debug: this.debug,
|
|
546
|
+
sdkName: this.sdkName
|
|
547
|
+
});
|
|
548
|
+
}
|
|
549
|
+
if (!this.writeKey) {
|
|
550
|
+
if (!isPending) this.sticky.delete(eventId);
|
|
551
|
+
return;
|
|
552
|
+
}
|
|
450
553
|
const p = postJson(url, payload, this.authHeaders(), {
|
|
451
554
|
maxAttempts: 3,
|
|
452
555
|
debug: this.debug,
|
|
@@ -471,28 +574,100 @@ var EventShipper = class {
|
|
|
471
574
|
}
|
|
472
575
|
}
|
|
473
576
|
};
|
|
474
|
-
var
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
577
|
+
var DEFAULT_SECRET_KEY_NAMES = [
|
|
578
|
+
"apikey",
|
|
579
|
+
"apisecret",
|
|
580
|
+
"apitoken",
|
|
581
|
+
"secretaccesskey",
|
|
582
|
+
"sessiontoken",
|
|
583
|
+
"privatekey",
|
|
584
|
+
"privatekeyid",
|
|
585
|
+
"clientsecret",
|
|
586
|
+
"accesstoken",
|
|
587
|
+
"refreshtoken",
|
|
588
|
+
"oauthtoken",
|
|
589
|
+
"bearertoken",
|
|
590
|
+
"authorization",
|
|
591
|
+
"password",
|
|
592
|
+
"passphrase"
|
|
593
|
+
];
|
|
594
|
+
var REDACTED_PLACEHOLDER = "[REDACTED]";
|
|
595
|
+
function normalizeKeyName(name) {
|
|
596
|
+
return name.toLowerCase().replace(/[-_.]/g, "");
|
|
479
597
|
}
|
|
480
|
-
function
|
|
481
|
-
var _a;
|
|
482
|
-
const
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
598
|
+
function redactSecretsInObject(value, options) {
|
|
599
|
+
var _a, _b;
|
|
600
|
+
const normalizedSecretSet = buildSecretSet((_a = options == null ? void 0 : options.secretKeyNames) != null ? _a : DEFAULT_SECRET_KEY_NAMES);
|
|
601
|
+
const placeholder = (_b = options == null ? void 0 : options.placeholder) != null ? _b : REDACTED_PLACEHOLDER;
|
|
602
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
603
|
+
const walk = (node) => {
|
|
604
|
+
if (node === null || typeof node !== "object") return node;
|
|
605
|
+
if (seen.has(node)) return "[CIRCULAR]";
|
|
606
|
+
seen.add(node);
|
|
607
|
+
if (Array.isArray(node)) {
|
|
608
|
+
return node.map((item) => walk(item));
|
|
609
|
+
}
|
|
610
|
+
const out = {};
|
|
611
|
+
for (const [k, v] of Object.entries(node)) {
|
|
612
|
+
if (normalizedSecretSet.has(normalizeKeyName(k))) {
|
|
613
|
+
out[k] = placeholder;
|
|
614
|
+
} else {
|
|
615
|
+
out[k] = walk(v);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
return out;
|
|
619
|
+
};
|
|
620
|
+
return walk(value);
|
|
621
|
+
}
|
|
622
|
+
function buildSecretSet(names) {
|
|
623
|
+
const set = /* @__PURE__ */ new Set();
|
|
624
|
+
for (const name of names) set.add(normalizeKeyName(name));
|
|
625
|
+
return set;
|
|
626
|
+
}
|
|
627
|
+
var DEFAULT_REDACT_ATTRIBUTE_KEYS = [
|
|
628
|
+
"ai.request.providerOptions",
|
|
629
|
+
"ai.response.providerMetadata"
|
|
630
|
+
];
|
|
631
|
+
function defaultTransformSpan(span) {
|
|
632
|
+
const attrs = span.attributes;
|
|
633
|
+
if (!attrs || attrs.length === 0) return span;
|
|
634
|
+
let nextAttrs;
|
|
635
|
+
for (let i = 0; i < attrs.length; i++) {
|
|
636
|
+
const attr = attrs[i];
|
|
637
|
+
const redacted = redactJsonAttributeValue(attr.key, attr.value);
|
|
638
|
+
if (redacted === void 0) continue;
|
|
639
|
+
if (!nextAttrs) nextAttrs = attrs.slice();
|
|
640
|
+
nextAttrs[i] = { key: attr.key, value: redacted };
|
|
641
|
+
}
|
|
642
|
+
if (!nextAttrs) return span;
|
|
643
|
+
return { ...span, attributes: nextAttrs };
|
|
644
|
+
}
|
|
645
|
+
var REDACT_JSON_ATTRIBUTE_KEYS = new Set(DEFAULT_REDACT_ATTRIBUTE_KEYS);
|
|
646
|
+
function redactJsonAttributeValue(key, value) {
|
|
647
|
+
if (!REDACT_JSON_ATTRIBUTE_KEYS.has(key)) return void 0;
|
|
648
|
+
const json = value.stringValue;
|
|
649
|
+
if (typeof json !== "string" || json.length === 0) return void 0;
|
|
650
|
+
let parsed;
|
|
651
|
+
try {
|
|
652
|
+
parsed = JSON.parse(json);
|
|
653
|
+
} catch (e) {
|
|
654
|
+
return void 0;
|
|
655
|
+
}
|
|
656
|
+
const scrubbed = redactSecretsInObject(parsed);
|
|
657
|
+
let scrubbedJson;
|
|
658
|
+
try {
|
|
659
|
+
scrubbedJson = JSON.stringify(scrubbed);
|
|
660
|
+
} catch (e) {
|
|
661
|
+
return void 0;
|
|
662
|
+
}
|
|
663
|
+
if (scrubbedJson === json) return void 0;
|
|
664
|
+
return { stringValue: scrubbedJson };
|
|
490
665
|
}
|
|
491
666
|
var TraceShipper = class {
|
|
492
667
|
constructor(opts) {
|
|
493
668
|
this.queue = [];
|
|
494
669
|
this.inFlight = /* @__PURE__ */ new Set();
|
|
495
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _i
|
|
670
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
496
671
|
this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
|
|
497
672
|
this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
|
|
498
673
|
this.enabled = opts.enabled !== false;
|
|
@@ -505,13 +680,46 @@ var TraceShipper = class {
|
|
|
505
680
|
this.prefix = `[raindrop-ai/${this.sdkName}]`;
|
|
506
681
|
this.serviceName = (_g = opts.serviceName) != null ? _g : "raindrop.core";
|
|
507
682
|
this.serviceVersion = (_h = opts.serviceVersion) != null ? _h : "0.0.0";
|
|
508
|
-
|
|
509
|
-
if (
|
|
510
|
-
this.
|
|
511
|
-
|
|
512
|
-
|
|
683
|
+
this.localDebuggerUrl = (_i = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _i : void 0;
|
|
684
|
+
if (this.debug && this.localDebuggerUrl) {
|
|
685
|
+
console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
|
|
686
|
+
}
|
|
687
|
+
this.transformSpanHook = opts.transformSpan;
|
|
688
|
+
this.disableDefaultRedaction = opts.disableDefaultRedaction === true;
|
|
689
|
+
}
|
|
690
|
+
/**
|
|
691
|
+
* Apply the user `transformSpan` hook (if any) followed by the default
|
|
692
|
+
* redactor (unless disabled). Returns either the (possibly new) span to
|
|
693
|
+
* ship, or `null` to drop the span entirely.
|
|
694
|
+
*
|
|
695
|
+
* Ordering: user hook runs first so callers can rewrite the span freely
|
|
696
|
+
* (rename attrs, add new ones, scrub things the default doesn't know
|
|
697
|
+
* about). The default redactor then runs on whatever the user produced,
|
|
698
|
+
* acting as the always-on floor for documented BYOK secrets. If the user
|
|
699
|
+
* sets `disableDefaultRedaction: true`, the floor is skipped.
|
|
700
|
+
*
|
|
701
|
+
* Fail-closed: if the user hook throws, the span is dropped — a buggy
|
|
702
|
+
* hook can never accidentally ship raw, un-redacted spans.
|
|
703
|
+
*/
|
|
704
|
+
redactSpan(span) {
|
|
705
|
+
let current = span;
|
|
706
|
+
if (this.transformSpanHook) {
|
|
707
|
+
try {
|
|
708
|
+
const result = this.transformSpanHook(current);
|
|
709
|
+
if (result === null) return null;
|
|
710
|
+
if (result !== void 0) current = result;
|
|
711
|
+
} catch (err) {
|
|
712
|
+
if (this.debug) {
|
|
713
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
714
|
+
console.warn(`${this.prefix} transformSpan hook threw: ${msg}`);
|
|
715
|
+
}
|
|
716
|
+
return null;
|
|
513
717
|
}
|
|
514
718
|
}
|
|
719
|
+
if (!this.disableDefaultRedaction) {
|
|
720
|
+
current = defaultTransformSpan(current);
|
|
721
|
+
}
|
|
722
|
+
return current;
|
|
515
723
|
}
|
|
516
724
|
isDebugEnabled() {
|
|
517
725
|
return this.debug;
|
|
@@ -529,8 +737,8 @@ var TraceShipper = class {
|
|
|
529
737
|
];
|
|
530
738
|
if ((_b = args.attributes) == null ? void 0 : _b.length) attrs.push(...args.attributes);
|
|
531
739
|
const span = { ids, name: args.name, startTimeUnixNano: started, attributes: attrs };
|
|
532
|
-
|
|
533
|
-
|
|
740
|
+
this.mirrorToLocalDebugger(
|
|
741
|
+
buildOtlpSpan({
|
|
534
742
|
ids: span.ids,
|
|
535
743
|
name: span.name,
|
|
536
744
|
startTimeUnixNano: span.startTimeUnixNano,
|
|
@@ -538,16 +746,21 @@ var TraceShipper = class {
|
|
|
538
746
|
// placeholder — will be updated on endSpan
|
|
539
747
|
attributes: span.attributes,
|
|
540
748
|
status: { code: SpanStatusCode.UNSET }
|
|
541
|
-
})
|
|
542
|
-
|
|
543
|
-
mirrorTraceExportToLocalDebugger(body, {
|
|
544
|
-
baseUrl: this.localDebuggerUrl,
|
|
545
|
-
debug: false,
|
|
546
|
-
sdkName: this.sdkName
|
|
547
|
-
});
|
|
548
|
-
}
|
|
749
|
+
})
|
|
750
|
+
);
|
|
549
751
|
return span;
|
|
550
752
|
}
|
|
753
|
+
mirrorToLocalDebugger(span) {
|
|
754
|
+
if (!this.localDebuggerUrl) return;
|
|
755
|
+
const redacted = this.redactSpan(span);
|
|
756
|
+
if (redacted === null) return;
|
|
757
|
+
const body = buildExportTraceServiceRequest([redacted], this.serviceName, this.serviceVersion);
|
|
758
|
+
mirrorTraceExportToLocalDebugger(body, {
|
|
759
|
+
baseUrl: this.localDebuggerUrl,
|
|
760
|
+
debug: false,
|
|
761
|
+
sdkName: this.sdkName
|
|
762
|
+
});
|
|
763
|
+
}
|
|
551
764
|
endSpan(span, extra) {
|
|
552
765
|
var _a, _b;
|
|
553
766
|
if (span.endTimeUnixNano) return;
|
|
@@ -569,14 +782,7 @@ var TraceShipper = class {
|
|
|
569
782
|
status
|
|
570
783
|
});
|
|
571
784
|
this.enqueue(otlp);
|
|
572
|
-
|
|
573
|
-
const body = buildExportTraceServiceRequest([otlp], this.serviceName, this.serviceVersion);
|
|
574
|
-
mirrorTraceExportToLocalDebugger(body, {
|
|
575
|
-
baseUrl: this.localDebuggerUrl,
|
|
576
|
-
debug: false,
|
|
577
|
-
sdkName: this.sdkName
|
|
578
|
-
});
|
|
579
|
-
}
|
|
785
|
+
this.mirrorToLocalDebugger(otlp);
|
|
580
786
|
}
|
|
581
787
|
createSpan(args) {
|
|
582
788
|
var _a;
|
|
@@ -594,14 +800,7 @@ var TraceShipper = class {
|
|
|
594
800
|
status: args.status
|
|
595
801
|
});
|
|
596
802
|
this.enqueue(otlp);
|
|
597
|
-
|
|
598
|
-
const body = buildExportTraceServiceRequest([otlp], this.serviceName, this.serviceVersion);
|
|
599
|
-
mirrorTraceExportToLocalDebugger(body, {
|
|
600
|
-
baseUrl: this.localDebuggerUrl,
|
|
601
|
-
debug: false,
|
|
602
|
-
sdkName: this.sdkName
|
|
603
|
-
});
|
|
604
|
-
}
|
|
803
|
+
this.mirrorToLocalDebugger(otlp);
|
|
605
804
|
}
|
|
606
805
|
enqueue(span) {
|
|
607
806
|
if (!this.enabled) return;
|
|
@@ -613,10 +812,12 @@ var TraceShipper = class {
|
|
|
613
812
|
)}`
|
|
614
813
|
);
|
|
615
814
|
}
|
|
815
|
+
const redacted = this.redactSpan(span);
|
|
816
|
+
if (redacted === null) return;
|
|
616
817
|
if (this.queue.length >= this.maxQueueSize) {
|
|
617
818
|
this.queue.shift();
|
|
618
819
|
}
|
|
619
|
-
this.queue.push(
|
|
820
|
+
this.queue.push(redacted);
|
|
620
821
|
if (this.queue.length >= this.maxBatchSize) {
|
|
621
822
|
void this.flush().catch(() => {
|
|
622
823
|
});
|
|
@@ -638,6 +839,7 @@ var TraceShipper = class {
|
|
|
638
839
|
}
|
|
639
840
|
while (this.queue.length > 0) {
|
|
640
841
|
const batch = this.queue.splice(0, this.maxBatchSize);
|
|
842
|
+
if (!this.writeKey) continue;
|
|
641
843
|
const body = buildExportTraceServiceRequest(batch, this.serviceName, this.serviceVersion);
|
|
642
844
|
const url = `${this.baseUrl}traces`;
|
|
643
845
|
if (this.debug) {
|
|
@@ -683,7 +885,7 @@ globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = import_async_hooks.AsyncLocalStorage;
|
|
|
683
885
|
// package.json
|
|
684
886
|
var package_default = {
|
|
685
887
|
name: "@raindrop-ai/pi-agent",
|
|
686
|
-
version: "0.0.
|
|
888
|
+
version: "0.0.4",
|
|
687
889
|
description: "Raindrop observability for Pi Agent \u2014 automatic tracing via subscriber or pi-coding-agent extension",
|
|
688
890
|
type: "module",
|
|
689
891
|
license: "MIT",
|
|
@@ -733,18 +935,18 @@ var package_default = {
|
|
|
733
935
|
"test:watch": "vitest"
|
|
734
936
|
},
|
|
735
937
|
peerDependencies: {
|
|
736
|
-
"@
|
|
737
|
-
"@
|
|
938
|
+
"@earendil-works/pi-agent-core": ">=0.74.0",
|
|
939
|
+
"@earendil-works/pi-coding-agent": ">=0.74.0"
|
|
738
940
|
},
|
|
739
941
|
peerDependenciesMeta: {
|
|
740
|
-
"@
|
|
942
|
+
"@earendil-works/pi-coding-agent": {
|
|
741
943
|
optional: true
|
|
742
944
|
}
|
|
743
945
|
},
|
|
744
946
|
devDependencies: {
|
|
745
947
|
"@raindrop-ai/core": "workspace:*",
|
|
746
|
-
"@
|
|
747
|
-
"@
|
|
948
|
+
"@earendil-works/pi-agent-core": "^0.78.0",
|
|
949
|
+
"@earendil-works/pi-coding-agent": "^0.78.0",
|
|
748
950
|
"@types/node": "^20.11.17",
|
|
749
951
|
msw: "^2.12.7",
|
|
750
952
|
tsup: "^8.5.1",
|
|
@@ -1282,23 +1484,26 @@ function envDebugEnabled() {
|
|
|
1282
1484
|
function createRaindropPiAgent(opts) {
|
|
1283
1485
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
|
|
1284
1486
|
const hasWriteKey = typeof opts.writeKey === "string" && opts.writeKey.trim().length > 0;
|
|
1487
|
+
const resolvedLocalUrl = resolveLocalDebuggerBaseUrl(opts.localWorkshopUrl);
|
|
1488
|
+
const hasLocalDestination = resolvedLocalUrl !== null;
|
|
1285
1489
|
const eventsEnabled = ((_a = opts.events) == null ? void 0 : _a.enabled) !== false;
|
|
1286
1490
|
const tracesEnabled = ((_b = opts.traces) == null ? void 0 : _b.enabled) !== false;
|
|
1287
|
-
if (!hasWriteKey && !opts.endpoint) {
|
|
1491
|
+
if (!hasWriteKey && !opts.endpoint && !hasLocalDestination) {
|
|
1288
1492
|
console.warn(
|
|
1289
1493
|
"[raindrop-ai/pi-agent] writeKey not provided; telemetry shipping is disabled"
|
|
1290
1494
|
);
|
|
1291
1495
|
}
|
|
1292
1496
|
const envDebug = envDebugEnabled();
|
|
1293
1497
|
const debug = ((_c = opts.events) == null ? void 0 : _c.debug) === true || ((_d = opts.traces) == null ? void 0 : _d.debug) === true || envDebug;
|
|
1294
|
-
const eventShipper = eventsEnabled && (hasWriteKey || opts.endpoint) ? new EventShipper2({
|
|
1498
|
+
const eventShipper = eventsEnabled && (hasWriteKey || opts.endpoint || hasLocalDestination) ? new EventShipper2({
|
|
1295
1499
|
writeKey: opts.writeKey,
|
|
1296
1500
|
endpoint: opts.endpoint,
|
|
1297
1501
|
enabled: true,
|
|
1298
1502
|
debug: ((_e = opts.events) == null ? void 0 : _e.debug) === true || envDebug,
|
|
1299
|
-
partialFlushMs: (_f = opts.events) == null ? void 0 : _f.partialFlushMs
|
|
1503
|
+
partialFlushMs: (_f = opts.events) == null ? void 0 : _f.partialFlushMs,
|
|
1504
|
+
localDebuggerUrl: opts.localWorkshopUrl
|
|
1300
1505
|
}) : null;
|
|
1301
|
-
const traceShipper = tracesEnabled && (hasWriteKey || opts.endpoint) ? new TraceShipper2({
|
|
1506
|
+
const traceShipper = tracesEnabled && (hasWriteKey || opts.endpoint || hasLocalDestination) ? new TraceShipper2({
|
|
1302
1507
|
writeKey: opts.writeKey,
|
|
1303
1508
|
endpoint: opts.endpoint,
|
|
1304
1509
|
enabled: true,
|
|
@@ -1306,7 +1511,8 @@ function createRaindropPiAgent(opts) {
|
|
|
1306
1511
|
debugSpans: ((_h = opts.traces) == null ? void 0 : _h.debugSpans) === true || envDebug,
|
|
1307
1512
|
flushIntervalMs: (_i = opts.traces) == null ? void 0 : _i.flushIntervalMs,
|
|
1308
1513
|
maxBatchSize: (_j = opts.traces) == null ? void 0 : _j.maxBatchSize,
|
|
1309
|
-
maxQueueSize: (_k = opts.traces) == null ? void 0 : _k.maxQueueSize
|
|
1514
|
+
maxQueueSize: (_k = opts.traces) == null ? void 0 : _k.maxQueueSize,
|
|
1515
|
+
localDebuggerUrl: opts.localWorkshopUrl
|
|
1310
1516
|
}) : null;
|
|
1311
1517
|
const defaultOptions = {
|
|
1312
1518
|
userId: opts.userId,
|