@raindrop-ai/pi-agent 0.0.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/dist/index.cjs ADDED
@@ -0,0 +1,1405 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ createRaindropPiAgent: () => createRaindropPiAgent
24
+ });
25
+ module.exports = __toCommonJS(index_exports);
26
+
27
+ // ../core/dist/chunk-4UCYIEH4.js
28
+ function getCrypto() {
29
+ const c = globalThis.crypto;
30
+ return c;
31
+ }
32
+ function randomBytes(length) {
33
+ const cryptoObj = getCrypto();
34
+ const out = new Uint8Array(length);
35
+ if (cryptoObj && typeof cryptoObj.getRandomValues === "function") {
36
+ cryptoObj.getRandomValues(out);
37
+ return out;
38
+ }
39
+ for (let i = 0; i < out.length; i++) out[i] = Math.floor(Math.random() * 256);
40
+ return out;
41
+ }
42
+ function randomUUID() {
43
+ const cryptoObj = getCrypto();
44
+ if (cryptoObj && typeof cryptoObj.randomUUID === "function") {
45
+ return cryptoObj.randomUUID();
46
+ }
47
+ const b = randomBytes(16);
48
+ b[6] = b[6] & 15 | 64;
49
+ b[8] = b[8] & 63 | 128;
50
+ const hex = [...b].map((x) => x.toString(16).padStart(2, "0")).join("");
51
+ return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
52
+ }
53
+ function base64Encode(bytes) {
54
+ const maybeBuffer = globalThis.Buffer;
55
+ if (maybeBuffer) {
56
+ return maybeBuffer.from(bytes).toString("base64");
57
+ }
58
+ let binary = "";
59
+ for (let i2 = 0; i2 < bytes.length; i2++) {
60
+ binary += String.fromCharCode(bytes[i2]);
61
+ }
62
+ const btoaFn = globalThis.btoa;
63
+ if (typeof btoaFn === "function") return btoaFn(binary);
64
+ const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
65
+ let out = "";
66
+ let i = 0;
67
+ while (i < binary.length) {
68
+ const c1 = binary.charCodeAt(i++) & 255;
69
+ const c2 = i < binary.length ? binary.charCodeAt(i++) & 255 : NaN;
70
+ const c3 = i < binary.length ? binary.charCodeAt(i++) & 255 : NaN;
71
+ const e1 = c1 >> 2;
72
+ const e2 = (c1 & 3) << 4 | (Number.isNaN(c2) ? 0 : c2 >> 4);
73
+ const e3 = Number.isNaN(c2) ? 64 : (c2 & 15) << 2 | (Number.isNaN(c3) ? 0 : c3 >> 6);
74
+ const e4 = Number.isNaN(c3) ? 64 : c3 & 63;
75
+ out += alphabet.charAt(e1);
76
+ out += alphabet.charAt(e2);
77
+ out += e3 === 64 ? "=" : alphabet.charAt(e3);
78
+ out += e4 === 64 ? "=" : alphabet.charAt(e4);
79
+ }
80
+ return out;
81
+ }
82
+ function wait(ms) {
83
+ return new Promise((resolve) => setTimeout(resolve, ms));
84
+ }
85
+ function formatEndpoint(endpoint) {
86
+ if (!endpoint) return void 0;
87
+ return endpoint.endsWith("/") ? endpoint : `${endpoint}/`;
88
+ }
89
+ function parseRetryAfter(headers) {
90
+ var _a;
91
+ const value = (_a = headers.get("Retry-After")) != null ? _a : headers.get("retry-after");
92
+ if (!value) return void 0;
93
+ const asNumber = Number(value);
94
+ if (value.trim() !== "" && !Number.isNaN(asNumber)) return asNumber * 1e3;
95
+ const asDate = new Date(value).getTime();
96
+ if (!Number.isNaN(asDate)) {
97
+ const delta = asDate - Date.now();
98
+ return delta > 0 ? delta : 0;
99
+ }
100
+ return void 0;
101
+ }
102
+ function getRetryDelayMs(attemptNumber, previousError) {
103
+ if (previousError && typeof previousError === "object" && previousError !== null && "retryAfterMs" in previousError) {
104
+ const v = previousError.retryAfterMs;
105
+ if (typeof v === "number") return Math.max(0, v);
106
+ }
107
+ if (attemptNumber <= 1) return 0;
108
+ const base = 500;
109
+ const factor = Math.pow(2, attemptNumber - 2);
110
+ return base * factor;
111
+ }
112
+ async function withRetry(operation, opName, opts) {
113
+ const prefix = opts.sdkName ? `[raindrop-ai/${opts.sdkName}]` : "[raindrop-ai/core]";
114
+ let lastError = void 0;
115
+ for (let attemptNumber = 1; attemptNumber <= opts.maxAttempts; attemptNumber++) {
116
+ if (attemptNumber > 1) {
117
+ const delay = getRetryDelayMs(attemptNumber, lastError);
118
+ if (opts.debug) {
119
+ console.warn(
120
+ `${prefix} ${opName} retry ${attemptNumber}/${opts.maxAttempts} in ${delay}ms`
121
+ );
122
+ }
123
+ if (delay > 0) await wait(delay);
124
+ } else if (opts.debug) {
125
+ console.log(`${prefix} ${opName} attempt ${attemptNumber}/${opts.maxAttempts}`);
126
+ }
127
+ try {
128
+ return await operation();
129
+ } catch (err) {
130
+ lastError = err;
131
+ if (opts.debug) {
132
+ const msg = err instanceof Error ? err.message : String(err);
133
+ console.warn(
134
+ `${prefix} ${opName} attempt ${attemptNumber} failed: ${msg}${attemptNumber === opts.maxAttempts ? " (no more retries)" : ""}`
135
+ );
136
+ }
137
+ if (lastError && typeof lastError === "object" && "retryable" in lastError && !lastError.retryable)
138
+ break;
139
+ if (attemptNumber === opts.maxAttempts) break;
140
+ }
141
+ }
142
+ throw lastError instanceof Error ? lastError : new Error(String(lastError));
143
+ }
144
+ async function postJson(url, body, headers, opts) {
145
+ const opName = `POST ${url}`;
146
+ await withRetry(
147
+ async () => {
148
+ const resp = await fetch(url, {
149
+ method: "POST",
150
+ headers: {
151
+ "Content-Type": "application/json",
152
+ ...headers
153
+ },
154
+ body: JSON.stringify(body)
155
+ });
156
+ if (!resp.ok) {
157
+ const text = await resp.text().catch(() => "");
158
+ const err = new Error(
159
+ `HTTP ${resp.status} ${resp.statusText}${text ? `: ${text}` : ""}`
160
+ );
161
+ const retryAfterMs = parseRetryAfter(resp.headers);
162
+ if (typeof retryAfterMs === "number") err.retryAfterMs = retryAfterMs;
163
+ err.retryable = resp.status === 429 || resp.status >= 500;
164
+ throw err;
165
+ }
166
+ },
167
+ opName,
168
+ opts
169
+ );
170
+ }
171
+ var SpanStatusCode = {
172
+ UNSET: 0,
173
+ OK: 1,
174
+ ERROR: 2
175
+ };
176
+ function createSpanIds(parent) {
177
+ const traceId = parent ? parent.traceIdB64 : base64Encode(randomBytes(16));
178
+ const spanId = base64Encode(randomBytes(8));
179
+ return {
180
+ traceIdB64: traceId,
181
+ spanIdB64: spanId,
182
+ parentSpanIdB64: parent ? parent.spanIdB64 : void 0
183
+ };
184
+ }
185
+ function nowUnixNanoString() {
186
+ return Date.now().toString() + "000000";
187
+ }
188
+ function attrString(key, value) {
189
+ if (value === void 0) return void 0;
190
+ return { key, value: { stringValue: value } };
191
+ }
192
+ function attrInt(key, value) {
193
+ if (value === void 0) return void 0;
194
+ if (!Number.isFinite(value)) return void 0;
195
+ return { key, value: { intValue: String(Math.trunc(value)) } };
196
+ }
197
+ function buildOtlpSpan(args) {
198
+ const attrs = args.attributes.filter((x) => x !== void 0);
199
+ const span = {
200
+ traceId: args.ids.traceIdB64,
201
+ spanId: args.ids.spanIdB64,
202
+ name: args.name,
203
+ startTimeUnixNano: args.startTimeUnixNano,
204
+ endTimeUnixNano: args.endTimeUnixNano
205
+ };
206
+ if (args.ids.parentSpanIdB64) span.parentSpanId = args.ids.parentSpanIdB64;
207
+ if (attrs.length) span.attributes = attrs;
208
+ if (args.status) span.status = args.status;
209
+ return span;
210
+ }
211
+ function buildExportTraceServiceRequest(spans, serviceName = "raindrop.core", serviceVersion = "0.0.0") {
212
+ return {
213
+ resourceSpans: [
214
+ {
215
+ resource: {
216
+ attributes: [{ key: "service.name", value: { stringValue: serviceName } }]
217
+ },
218
+ scopeSpans: [
219
+ {
220
+ scope: { name: serviceName, version: serviceVersion },
221
+ spans
222
+ }
223
+ ]
224
+ }
225
+ ]
226
+ };
227
+ }
228
+ function mergePatches(target, source) {
229
+ var _a, _b, _c, _d;
230
+ const out = { ...target, ...source };
231
+ if (target.properties || source.properties) {
232
+ out.properties = { ...(_a = target.properties) != null ? _a : {}, ...(_b = source.properties) != null ? _b : {} };
233
+ }
234
+ if (target.attachments || source.attachments) {
235
+ out.attachments = [...(_c = target.attachments) != null ? _c : [], ...(_d = source.attachments) != null ? _d : []];
236
+ }
237
+ return out;
238
+ }
239
+ var EventShipper = class {
240
+ constructor(opts) {
241
+ this.buffers = /* @__PURE__ */ new Map();
242
+ this.sticky = /* @__PURE__ */ new Map();
243
+ this.timers = /* @__PURE__ */ new Map();
244
+ this.inFlight = /* @__PURE__ */ new Set();
245
+ var _a, _b, _c, _d, _e, _f, _g;
246
+ this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
247
+ this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
248
+ this.enabled = opts.enabled !== false;
249
+ this.debug = opts.debug;
250
+ this.partialFlushMs = (_c = opts.partialFlushMs) != null ? _c : 1e3;
251
+ this.sdkName = (_d = opts.sdkName) != null ? _d : "core";
252
+ this.prefix = `[raindrop-ai/${this.sdkName}]`;
253
+ this.defaultEventName = (_e = opts.defaultEventName) != null ? _e : "ai_generation";
254
+ const isNode = typeof process !== "undefined" && typeof process.version === "string";
255
+ this.context = {
256
+ library: {
257
+ name: (_f = opts.libraryName) != null ? _f : "@raindrop-ai/core",
258
+ version: (_g = opts.libraryVersion) != null ? _g : "0.0.0"
259
+ },
260
+ metadata: {
261
+ jsRuntime: isNode ? "node" : "web",
262
+ ...isNode ? { nodeVersion: process.version } : {}
263
+ }
264
+ };
265
+ }
266
+ isDebugEnabled() {
267
+ return this.debug;
268
+ }
269
+ authHeaders() {
270
+ return this.writeKey ? { Authorization: `Bearer ${this.writeKey}` } : {};
271
+ }
272
+ async patch(eventId, patch) {
273
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
274
+ if (!this.enabled) return;
275
+ if (!eventId || !eventId.trim()) return;
276
+ if (this.debug) {
277
+ console.log(`${this.prefix} queue patch`, {
278
+ eventId,
279
+ userId: patch.userId,
280
+ convoId: patch.convoId,
281
+ eventName: patch.eventName,
282
+ hasInput: typeof patch.input === "string" && patch.input.length > 0,
283
+ hasOutput: typeof patch.output === "string" && patch.output.length > 0,
284
+ attachments: (_b = (_a = patch.attachments) == null ? void 0 : _a.length) != null ? _b : 0,
285
+ isPending: patch.isPending
286
+ });
287
+ }
288
+ const sticky = (_c = this.sticky.get(eventId)) != null ? _c : {};
289
+ const existing = (_d = this.buffers.get(eventId)) != null ? _d : {};
290
+ const merged = mergePatches(existing, patch);
291
+ merged.isPending = (_g = (_f = (_e = patch.isPending) != null ? _e : existing.isPending) != null ? _f : sticky.isPending) != null ? _g : true;
292
+ this.buffers.set(eventId, merged);
293
+ this.sticky.set(eventId, {
294
+ userId: (_h = merged.userId) != null ? _h : sticky.userId,
295
+ convoId: (_i = merged.convoId) != null ? _i : sticky.convoId,
296
+ eventName: (_j = merged.eventName) != null ? _j : sticky.eventName,
297
+ isPending: (_k = merged.isPending) != null ? _k : sticky.isPending
298
+ });
299
+ const t = this.timers.get(eventId);
300
+ if (t) clearTimeout(t);
301
+ if (merged.isPending === false) {
302
+ await this.flushOne(eventId);
303
+ return;
304
+ }
305
+ const timeout = setTimeout(() => {
306
+ void this.flushOne(eventId).catch(() => {
307
+ });
308
+ }, this.partialFlushMs);
309
+ this.timers.set(eventId, timeout);
310
+ }
311
+ async finish(eventId, patch) {
312
+ await this.patch(eventId, { ...patch, isPending: false });
313
+ }
314
+ async flush() {
315
+ if (!this.enabled) return;
316
+ const ids = [...this.buffers.keys()];
317
+ await Promise.all(ids.map((id) => this.flushOne(id)));
318
+ await Promise.all([...this.inFlight].map((p) => p.catch(() => {
319
+ })));
320
+ }
321
+ async shutdown() {
322
+ for (const t of this.timers.values()) clearTimeout(t);
323
+ this.timers.clear();
324
+ await this.flush();
325
+ }
326
+ async trackSignal(signal) {
327
+ var _a, _b;
328
+ if (!this.enabled) return;
329
+ const body = [
330
+ {
331
+ event_id: signal.eventId,
332
+ signal_name: signal.name,
333
+ signal_type: (_a = signal.type) != null ? _a : "default",
334
+ timestamp: signal.timestamp,
335
+ sentiment: signal.sentiment,
336
+ attachment_id: signal.attachmentId,
337
+ properties: {
338
+ ...(_b = signal.properties) != null ? _b : {},
339
+ ...signal.comment ? { comment: signal.comment } : {},
340
+ ...signal.after ? { after: signal.after } : {}
341
+ }
342
+ }
343
+ ];
344
+ const url = `${this.baseUrl}signals/track`;
345
+ try {
346
+ await postJson(url, body, this.authHeaders(), {
347
+ maxAttempts: 3,
348
+ debug: this.debug,
349
+ sdkName: this.sdkName
350
+ });
351
+ } catch (err) {
352
+ const msg = err instanceof Error ? err.message : String(err);
353
+ console.warn(`${this.prefix} failed to send signal (dropping): ${msg}`);
354
+ }
355
+ }
356
+ async identify(users) {
357
+ if (!this.enabled) return;
358
+ const list = Array.isArray(users) ? users : [users];
359
+ const body = list.filter((user) => {
360
+ if (!(user == null ? void 0 : user.userId) || !user.userId.trim()) {
361
+ if (this.debug) {
362
+ console.warn(`${this.prefix} skipping identify: missing userId`);
363
+ }
364
+ return false;
365
+ }
366
+ return true;
367
+ }).map((user) => {
368
+ var _a;
369
+ return {
370
+ user_id: user.userId,
371
+ traits: (_a = user.traits) != null ? _a : {}
372
+ };
373
+ });
374
+ if (body.length === 0) return;
375
+ const url = `${this.baseUrl}users/identify`;
376
+ try {
377
+ await postJson(url, body, this.authHeaders(), {
378
+ maxAttempts: 3,
379
+ debug: this.debug,
380
+ sdkName: this.sdkName
381
+ });
382
+ } catch (err) {
383
+ const msg = err instanceof Error ? err.message : String(err);
384
+ console.warn(`${this.prefix} failed to send identify (dropping): ${msg}`);
385
+ }
386
+ }
387
+ async flushOne(eventId) {
388
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
389
+ if (!this.enabled) return;
390
+ const timer = this.timers.get(eventId);
391
+ if (timer) {
392
+ clearTimeout(timer);
393
+ this.timers.delete(eventId);
394
+ }
395
+ const accumulated = this.buffers.get(eventId);
396
+ this.buffers.delete(eventId);
397
+ if (!accumulated) return;
398
+ const sticky = (_a = this.sticky.get(eventId)) != null ? _a : {};
399
+ const eventName = (_c = (_b = accumulated.eventName) != null ? _b : sticky.eventName) != null ? _c : this.defaultEventName;
400
+ const userId = (_d = accumulated.userId) != null ? _d : sticky.userId;
401
+ if (!userId) {
402
+ if (this.debug) {
403
+ console.warn(`${this.prefix} skipping track_partial for ${eventId}: missing userId`);
404
+ }
405
+ this.sticky.delete(eventId);
406
+ return;
407
+ }
408
+ const { wizardSession, ...restProperties } = (_e = accumulated.properties) != null ? _e : {};
409
+ const convoId = (_f = accumulated.convoId) != null ? _f : sticky.convoId;
410
+ const isPending = (_h = (_g = accumulated.isPending) != null ? _g : sticky.isPending) != null ? _h : true;
411
+ const payload = {
412
+ event_id: eventId,
413
+ user_id: userId,
414
+ event: eventName,
415
+ timestamp: (_i = accumulated.timestamp) != null ? _i : (/* @__PURE__ */ new Date()).toISOString(),
416
+ ai_data: {
417
+ input: accumulated.input,
418
+ output: accumulated.output,
419
+ model: accumulated.model,
420
+ convo_id: convoId
421
+ },
422
+ properties: {
423
+ ...restProperties,
424
+ ...wizardSession ? { "raindrop.wizardSession": wizardSession } : {},
425
+ $context: this.context
426
+ },
427
+ attachments: accumulated.attachments,
428
+ is_pending: isPending
429
+ };
430
+ const url = `${this.baseUrl}events/track_partial`;
431
+ if (this.debug) {
432
+ console.log(`${this.prefix} sending track_partial`, {
433
+ eventId,
434
+ eventName,
435
+ userId,
436
+ convoId,
437
+ isPending,
438
+ inputPreview: typeof accumulated.input === "string" ? accumulated.input.slice(0, 120) : void 0,
439
+ outputPreview: typeof accumulated.output === "string" ? accumulated.output.slice(0, 120) : void 0,
440
+ attachments: (_k = (_j = accumulated.attachments) == null ? void 0 : _j.length) != null ? _k : 0,
441
+ attachmentKinds: (_m = (_l = accumulated.attachments) == null ? void 0 : _l.map((a) => ({
442
+ type: a.type,
443
+ role: a.role,
444
+ name: a.name,
445
+ valuePreview: a.value.slice(0, 60)
446
+ }))) != null ? _m : [],
447
+ endpoint: url
448
+ });
449
+ }
450
+ const p = postJson(url, payload, this.authHeaders(), {
451
+ maxAttempts: 3,
452
+ debug: this.debug,
453
+ sdkName: this.sdkName
454
+ });
455
+ this.inFlight.add(p);
456
+ try {
457
+ try {
458
+ await p;
459
+ if (this.debug) {
460
+ console.log(`${this.prefix} sent track_partial ${eventId} (${eventName})`);
461
+ }
462
+ } catch (err) {
463
+ const msg = err instanceof Error ? err.message : String(err);
464
+ console.warn(`${this.prefix} failed to send track_partial (dropping): ${msg}`);
465
+ }
466
+ } finally {
467
+ this.inFlight.delete(p);
468
+ }
469
+ if (!isPending) {
470
+ this.sticky.delete(eventId);
471
+ }
472
+ }
473
+ };
474
+ var LOCAL_DEBUGGER_ENV_VAR = "RAINDROP_LOCAL_DEBUGGER";
475
+ function resolveLocalDebuggerBaseUrl(baseUrl) {
476
+ var _a, _b, _c;
477
+ const resolved = (_b = baseUrl != null ? baseUrl : typeof process !== "undefined" ? (_a = process.env) == null ? void 0 : _a[LOCAL_DEBUGGER_ENV_VAR] : void 0) != null ? _b : null;
478
+ return resolved ? (_c = formatEndpoint(resolved)) != null ? _c : null : null;
479
+ }
480
+ function mirrorTraceExportToLocalDebugger(body, options = {}) {
481
+ var _a;
482
+ const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
483
+ if (!baseUrl) return;
484
+ void postJson(`${baseUrl}traces`, body, {}, {
485
+ maxAttempts: 1,
486
+ debug: (_a = options.debug) != null ? _a : false,
487
+ sdkName: options.sdkName
488
+ }).catch(() => {
489
+ });
490
+ }
491
+ var TraceShipper = class {
492
+ constructor(opts) {
493
+ this.queue = [];
494
+ this.inFlight = /* @__PURE__ */ new Set();
495
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
496
+ this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
497
+ this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
498
+ this.enabled = opts.enabled !== false;
499
+ this.debug = opts.debug;
500
+ this.debugSpans = opts.debugSpans === true;
501
+ this.flushIntervalMs = (_c = opts.flushIntervalMs) != null ? _c : 1e3;
502
+ this.maxBatchSize = (_d = opts.maxBatchSize) != null ? _d : 50;
503
+ this.maxQueueSize = (_e = opts.maxQueueSize) != null ? _e : 5e3;
504
+ this.sdkName = (_f = opts.sdkName) != null ? _f : "core";
505
+ this.prefix = `[raindrop-ai/${this.sdkName}]`;
506
+ this.serviceName = (_g = opts.serviceName) != null ? _g : "raindrop.core";
507
+ this.serviceVersion = (_h = opts.serviceVersion) != null ? _h : "0.0.0";
508
+ const localDebugger = typeof process !== "undefined" ? (_i = process.env) == null ? void 0 : _i.RAINDROP_LOCAL_DEBUGGER : void 0;
509
+ if (localDebugger) {
510
+ this.localDebuggerUrl = (_j = resolveLocalDebuggerBaseUrl(localDebugger)) != null ? _j : void 0;
511
+ if (this.debug) {
512
+ console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
513
+ }
514
+ }
515
+ }
516
+ isDebugEnabled() {
517
+ return this.debug;
518
+ }
519
+ authHeaders() {
520
+ return this.writeKey ? { Authorization: `Bearer ${this.writeKey}` } : {};
521
+ }
522
+ startSpan(args) {
523
+ var _a, _b;
524
+ const ids = createSpanIds(args.parent);
525
+ const started = (_a = args.startTimeUnixNano) != null ? _a : nowUnixNanoString();
526
+ const attrs = [
527
+ attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId),
528
+ attrString("ai.operationId", args.operationId)
529
+ ];
530
+ if ((_b = args.attributes) == null ? void 0 : _b.length) attrs.push(...args.attributes);
531
+ const span = { ids, name: args.name, startTimeUnixNano: started, attributes: attrs };
532
+ if (this.localDebuggerUrl) {
533
+ const openSpan = buildOtlpSpan({
534
+ ids: span.ids,
535
+ name: span.name,
536
+ startTimeUnixNano: span.startTimeUnixNano,
537
+ endTimeUnixNano: span.startTimeUnixNano,
538
+ // placeholder — will be updated on endSpan
539
+ attributes: span.attributes,
540
+ status: { code: SpanStatusCode.UNSET }
541
+ });
542
+ const body = buildExportTraceServiceRequest([openSpan], this.serviceName, this.serviceVersion);
543
+ mirrorTraceExportToLocalDebugger(body, {
544
+ baseUrl: this.localDebuggerUrl,
545
+ debug: false,
546
+ sdkName: this.sdkName
547
+ });
548
+ }
549
+ return span;
550
+ }
551
+ endSpan(span, extra) {
552
+ var _a, _b;
553
+ if (span.endTimeUnixNano) return;
554
+ span.endTimeUnixNano = (_a = extra == null ? void 0 : extra.endTimeUnixNano) != null ? _a : nowUnixNanoString();
555
+ if ((_b = extra == null ? void 0 : extra.attributes) == null ? void 0 : _b.length) {
556
+ span.attributes.push(...extra.attributes);
557
+ }
558
+ let status = extra == null ? void 0 : extra.status;
559
+ if (!status && (extra == null ? void 0 : extra.error) !== void 0) {
560
+ const message = extra.error instanceof Error ? extra.error.message : String(extra.error);
561
+ status = { code: SpanStatusCode.ERROR, message };
562
+ }
563
+ const otlp = buildOtlpSpan({
564
+ ids: span.ids,
565
+ name: span.name,
566
+ startTimeUnixNano: span.startTimeUnixNano,
567
+ endTimeUnixNano: span.endTimeUnixNano,
568
+ attributes: span.attributes,
569
+ status
570
+ });
571
+ this.enqueue(otlp);
572
+ if (this.localDebuggerUrl) {
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
+ }
580
+ }
581
+ createSpan(args) {
582
+ var _a;
583
+ const ids = createSpanIds(args.parent);
584
+ const attrs = [
585
+ attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId)
586
+ ];
587
+ if ((_a = args.attributes) == null ? void 0 : _a.length) attrs.push(...args.attributes);
588
+ const otlp = buildOtlpSpan({
589
+ ids,
590
+ name: args.name,
591
+ startTimeUnixNano: args.startTimeUnixNano,
592
+ endTimeUnixNano: args.endTimeUnixNano,
593
+ attributes: attrs,
594
+ status: args.status
595
+ });
596
+ this.enqueue(otlp);
597
+ if (this.localDebuggerUrl) {
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
+ }
605
+ }
606
+ enqueue(span) {
607
+ if (!this.enabled) return;
608
+ if (this.debugSpans) {
609
+ const short = (s) => s ? s.slice(-8) : "none";
610
+ console.log(
611
+ `${this.prefix}[span] name=${span.name} trace=${short(span.traceId)} span=${short(span.spanId)} parent=${short(
612
+ span.parentSpanId
613
+ )}`
614
+ );
615
+ }
616
+ if (this.queue.length >= this.maxQueueSize) {
617
+ this.queue.shift();
618
+ }
619
+ this.queue.push(span);
620
+ if (this.queue.length >= this.maxBatchSize) {
621
+ void this.flush().catch(() => {
622
+ });
623
+ return;
624
+ }
625
+ if (!this.timer) {
626
+ this.timer = setTimeout(() => {
627
+ this.timer = void 0;
628
+ void this.flush().catch(() => {
629
+ });
630
+ }, this.flushIntervalMs);
631
+ }
632
+ }
633
+ async flush() {
634
+ if (!this.enabled) return;
635
+ if (this.timer) {
636
+ clearTimeout(this.timer);
637
+ this.timer = void 0;
638
+ }
639
+ while (this.queue.length > 0) {
640
+ const batch = this.queue.splice(0, this.maxBatchSize);
641
+ const body = buildExportTraceServiceRequest(batch, this.serviceName, this.serviceVersion);
642
+ const url = `${this.baseUrl}traces`;
643
+ if (this.debug) {
644
+ console.log(`${this.prefix} sending traces batch`, {
645
+ spans: batch.length,
646
+ endpoint: url
647
+ });
648
+ }
649
+ const p = postJson(url, body, this.authHeaders(), {
650
+ maxAttempts: 3,
651
+ debug: this.debug,
652
+ sdkName: this.sdkName
653
+ });
654
+ this.inFlight.add(p);
655
+ try {
656
+ try {
657
+ await p;
658
+ if (this.debug) console.log(`${this.prefix} sent ${batch.length} spans`);
659
+ } catch (err) {
660
+ const msg = err instanceof Error ? err.message : String(err);
661
+ console.warn(`${this.prefix} failed to send ${batch.length} spans: ${msg}`);
662
+ }
663
+ } finally {
664
+ this.inFlight.delete(p);
665
+ }
666
+ }
667
+ }
668
+ async shutdown() {
669
+ if (this.timer) {
670
+ clearTimeout(this.timer);
671
+ this.timer = void 0;
672
+ }
673
+ await this.flush();
674
+ await Promise.all([...this.inFlight].map((p) => p.catch(() => {
675
+ })));
676
+ }
677
+ };
678
+
679
+ // ../core/dist/index.node.js
680
+ var import_async_hooks = require("async_hooks");
681
+ globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = import_async_hooks.AsyncLocalStorage;
682
+
683
+ // package.json
684
+ var package_default = {
685
+ name: "@raindrop-ai/pi-agent",
686
+ version: "0.0.2",
687
+ description: "Raindrop observability for Pi Agent \u2014 automatic tracing via subscriber or pi-coding-agent extension",
688
+ type: "module",
689
+ license: "MIT",
690
+ repository: {
691
+ type: "git",
692
+ url: "git+https://github.com/raindrop-ai/raindrop-js.git",
693
+ directory: "packages/pi-agent"
694
+ },
695
+ homepage: "https://github.com/raindrop-ai/raindrop-js/tree/main/packages/pi-agent#readme",
696
+ bugs: {
697
+ url: "https://github.com/raindrop-ai/raindrop-js/issues"
698
+ },
699
+ keywords: [
700
+ "pi-package",
701
+ "raindrop",
702
+ "pi-agent",
703
+ "observability",
704
+ "tracing"
705
+ ],
706
+ exports: {
707
+ ".": {
708
+ types: "./dist/index.d.ts",
709
+ import: "./dist/index.js",
710
+ require: "./dist/index.cjs"
711
+ },
712
+ "./extension": {
713
+ types: "./dist/extension.d.ts",
714
+ import: "./dist/extension.js",
715
+ require: "./dist/extension.cjs"
716
+ }
717
+ },
718
+ pi: {
719
+ extensions: [
720
+ "./dist/extension.js"
721
+ ]
722
+ },
723
+ sideEffects: false,
724
+ files: [
725
+ "dist/**",
726
+ "README.md"
727
+ ],
728
+ scripts: {
729
+ build: "tsup",
730
+ dev: "tsup --watch",
731
+ clean: "rm -rf dist",
732
+ test: "vitest run",
733
+ "test:watch": "vitest"
734
+ },
735
+ peerDependencies: {
736
+ "@mariozechner/pi-agent-core": ">=0.60.0",
737
+ "@mariozechner/pi-coding-agent": ">=0.65.2"
738
+ },
739
+ peerDependenciesMeta: {
740
+ "@mariozechner/pi-coding-agent": {
741
+ optional: true
742
+ }
743
+ },
744
+ devDependencies: {
745
+ "@raindrop-ai/core": "workspace:*",
746
+ "@mariozechner/pi-agent-core": "^0.66.0",
747
+ "@mariozechner/pi-coding-agent": "^0.66.0",
748
+ "@types/node": "^20.11.17",
749
+ msw: "^2.12.7",
750
+ tsup: "^8.5.1",
751
+ typescript: "^5.7.3",
752
+ vitest: "^2.1.9"
753
+ },
754
+ tsup: {
755
+ entry: [
756
+ "src/index.ts",
757
+ "src/extension.ts"
758
+ ],
759
+ format: [
760
+ "cjs",
761
+ "esm"
762
+ ],
763
+ dts: {
764
+ resolve: true
765
+ },
766
+ clean: true,
767
+ noExternal: [
768
+ "@raindrop-ai/core"
769
+ ]
770
+ },
771
+ publishConfig: {
772
+ access: "public"
773
+ }
774
+ };
775
+
776
+ // src/version.ts
777
+ var libraryName = package_default.name;
778
+ var libraryVersion = package_default.version;
779
+
780
+ // src/internal/shipper.ts
781
+ var EventShipper2 = class extends EventShipper {
782
+ constructor(opts) {
783
+ var _a, _b, _c, _d;
784
+ super({
785
+ ...opts,
786
+ sdkName: (_a = opts.sdkName) != null ? _a : "pi-agent",
787
+ libraryName: (_b = opts.libraryName) != null ? _b : libraryName,
788
+ libraryVersion: (_c = opts.libraryVersion) != null ? _c : libraryVersion,
789
+ defaultEventName: (_d = opts.defaultEventName) != null ? _d : "pi_agent_prompt"
790
+ });
791
+ }
792
+ };
793
+ var TraceShipper2 = class extends TraceShipper {
794
+ constructor(opts) {
795
+ var _a, _b, _c;
796
+ super({
797
+ ...opts,
798
+ sdkName: (_a = opts.sdkName) != null ? _a : "pi-agent",
799
+ serviceName: (_b = opts.serviceName) != null ? _b : "raindrop.pi-agent",
800
+ serviceVersion: (_c = opts.serviceVersion) != null ? _c : libraryVersion
801
+ });
802
+ }
803
+ enqueue(span) {
804
+ var _a;
805
+ const attrs = (_a = span.attributes) != null ? _a : [];
806
+ attrs.unshift(
807
+ { key: "span.id", value: { stringValue: span.spanId } },
808
+ ...span.parentSpanId ? [{ key: "span.parent.id", value: { stringValue: span.parentSpanId } }] : []
809
+ );
810
+ span.attributes = attrs;
811
+ super.enqueue(span);
812
+ }
813
+ };
814
+
815
+ // src/internal/helpers.ts
816
+ var import_node_os = require("os");
817
+ function extractUserText(message) {
818
+ if (!("role" in message) || message.role !== "user") return void 0;
819
+ const content = message.content;
820
+ if (typeof content === "string") return content;
821
+ if (!Array.isArray(content)) return void 0;
822
+ const textParts = [];
823
+ for (const block of content) {
824
+ if (block.type === "text" && typeof block.text === "string") {
825
+ textParts.push(block.text);
826
+ }
827
+ }
828
+ return textParts.length > 0 ? textParts.join("\n") : void 0;
829
+ }
830
+ function extractModelName(message) {
831
+ if (!("role" in message) || message.role !== "assistant") return void 0;
832
+ const provider = "provider" in message ? message.provider : void 0;
833
+ const model = typeof message.model === "string" ? message.model : void 0;
834
+ if (provider && model) return `${provider}/${model}`;
835
+ return model;
836
+ }
837
+ function extractTokenUsage(message) {
838
+ if (!("role" in message) || message.role !== "assistant") return void 0;
839
+ const usage = message.usage;
840
+ if (!usage || typeof usage.input !== "number" || typeof usage.output !== "number") {
841
+ return void 0;
842
+ }
843
+ return {
844
+ input: usage.input,
845
+ output: usage.output,
846
+ ...typeof usage.cacheRead === "number" && usage.cacheRead > 0 ? { cacheRead: usage.cacheRead } : {}
847
+ };
848
+ }
849
+ function extractAssistantText(message) {
850
+ if (!("role" in message) || message.role !== "assistant") return void 0;
851
+ if (!Array.isArray(message.content)) return void 0;
852
+ const textParts = [];
853
+ for (const block of message.content) {
854
+ if (block.type === "text" && typeof block.text === "string") {
855
+ textParts.push(block.text);
856
+ }
857
+ }
858
+ return textParts.length > 0 ? textParts.join("\n") : void 0;
859
+ }
860
+ function extractToolCallIds(message) {
861
+ if (!("role" in message) || message.role !== "assistant") return [];
862
+ if (!Array.isArray(message.content)) return [];
863
+ const ids = [];
864
+ for (const block of message.content) {
865
+ if (block.type === "toolCall" && typeof block.id === "string") {
866
+ ids.push(block.id);
867
+ }
868
+ }
869
+ return ids;
870
+ }
871
+ function formatToolSpanName(toolName, args) {
872
+ if (!args || typeof args !== "object") return toolName;
873
+ try {
874
+ const obj = args;
875
+ const firstValue = Object.values(obj)[0];
876
+ if (typeof firstValue === "string" && firstValue.length > 0) {
877
+ const preview = firstValue.length > 40 ? firstValue.slice(0, 37) + "..." : firstValue;
878
+ return `${toolName}: ${preview}`;
879
+ }
880
+ } catch (e) {
881
+ }
882
+ return toolName;
883
+ }
884
+ function safeStringify(value) {
885
+ if (value === void 0 || value === null) return void 0;
886
+ try {
887
+ return JSON.stringify(value);
888
+ } catch (e) {
889
+ try {
890
+ return String(value);
891
+ } catch (e2) {
892
+ return "[unserializable]";
893
+ }
894
+ }
895
+ }
896
+ var MAX_ATTR_LENGTH = 32768;
897
+ function truncate(value) {
898
+ if (value === void 0) return void 0;
899
+ if (value.length <= MAX_ATTR_LENGTH) return value;
900
+ const suffix = "\n...[truncated]";
901
+ return value.slice(0, MAX_ATTR_LENGTH - suffix.length) + suffix;
902
+ }
903
+ var _hostname;
904
+ function getHostname() {
905
+ var _a;
906
+ if (_hostname) return _hostname;
907
+ try {
908
+ _hostname = (0, import_node_os.hostname)();
909
+ } catch (e) {
910
+ _hostname = (_a = process.env.HOSTNAME) != null ? _a : "unknown";
911
+ }
912
+ return _hostname;
913
+ }
914
+ var _username;
915
+ function getUsername() {
916
+ var _a, _b;
917
+ if (_username) return _username;
918
+ try {
919
+ _username = (0, import_node_os.userInfo)().username;
920
+ } catch (e) {
921
+ _username = (_b = (_a = process.env.USER) != null ? _a : process.env.USERNAME) != null ? _b : "unknown";
922
+ }
923
+ return _username;
924
+ }
925
+
926
+ // src/internal/subscriber.ts
927
+ function createSubscriber(agent, eventShipper, traceShipper, defaultOptions, options, debug) {
928
+ var _a, _b, _c, _d, _e;
929
+ const userId = (_a = options.userId) != null ? _a : defaultOptions.userId;
930
+ const convoId = (_b = options.convoId) != null ? _b : defaultOptions.convoId;
931
+ const eventName = (_c = options.eventName) != null ? _c : defaultOptions.eventName;
932
+ const properties = {
933
+ ...(_d = defaultOptions.properties) != null ? _d : {},
934
+ ...(_e = options.properties) != null ? _e : {}
935
+ };
936
+ let currentRun;
937
+ function log(msg) {
938
+ if (debug) console.log(`[raindrop-ai/pi-agent] ${msg}`);
939
+ }
940
+ function handleAgentStart() {
941
+ try {
942
+ if (currentRun) {
943
+ if (traceShipper) {
944
+ for (const [, span] of currentRun.toolSpans) {
945
+ traceShipper.endSpan(span);
946
+ }
947
+ }
948
+ if (currentRun.currentTurnSpan && traceShipper) {
949
+ traceShipper.endSpan(currentRun.currentTurnSpan);
950
+ }
951
+ if (currentRun.rootSpan && traceShipper) {
952
+ traceShipper.endSpan(currentRun.rootSpan, {
953
+ error: "Previous run was not finalized"
954
+ });
955
+ }
956
+ if (eventShipper) {
957
+ eventShipper.finish(currentRun.eventId, {
958
+ userId: userId != null ? userId : "anonymous",
959
+ properties: { sdk_version: libraryVersion, incomplete: true }
960
+ }).catch(() => {
961
+ });
962
+ }
963
+ currentRun = void 0;
964
+ }
965
+ const eventId = randomUUID();
966
+ const rootSpan = traceShipper ? traceShipper.startSpan({
967
+ name: "ai.event",
968
+ eventId,
969
+ attributes: [
970
+ attrString("hostname", getHostname()),
971
+ attrString("os", process.platform),
972
+ attrString("username", getUsername())
973
+ ]
974
+ }) : void 0;
975
+ currentRun = {
976
+ eventId,
977
+ rootSpan,
978
+ currentInput: "",
979
+ outputParts: [],
980
+ toolSpans: /* @__PURE__ */ new Map(),
981
+ toolArgs: /* @__PURE__ */ new Map(),
982
+ toolCallToLlmSpan: /* @__PURE__ */ new Map(),
983
+ lastModel: "",
984
+ turnNumber: 0,
985
+ totalInputTokens: 0,
986
+ totalOutputTokens: 0,
987
+ totalCacheReadTokens: 0
988
+ };
989
+ if (eventShipper) {
990
+ eventShipper.patch(eventId, {
991
+ isPending: true,
992
+ userId: userId != null ? userId : "anonymous",
993
+ convoId,
994
+ eventName,
995
+ properties: {
996
+ ...properties,
997
+ sdk_version: libraryVersion,
998
+ hostname: getHostname(),
999
+ os: process.platform
1000
+ }
1001
+ }).catch(() => {
1002
+ });
1003
+ }
1004
+ } catch (err) {
1005
+ log(`Error in agent_start handler: ${err instanceof Error ? err.message : String(err)}`);
1006
+ }
1007
+ }
1008
+ function handleMessageEnd(message) {
1009
+ try {
1010
+ if (!currentRun) return;
1011
+ const userText = extractUserText(message);
1012
+ if (userText !== void 0) {
1013
+ currentRun.currentInput = userText;
1014
+ if (eventShipper) {
1015
+ eventShipper.patch(currentRun.eventId, { input: userText }).catch(() => {
1016
+ });
1017
+ }
1018
+ return;
1019
+ }
1020
+ if (!("role" in message) || message.role !== "assistant") return;
1021
+ const model = extractModelName(message);
1022
+ const usage = extractTokenUsage(message);
1023
+ const assistantText = extractAssistantText(message);
1024
+ if (model) currentRun.lastModel = model;
1025
+ if (usage) {
1026
+ currentRun.totalInputTokens += usage.input;
1027
+ currentRun.totalOutputTokens += usage.output;
1028
+ if (usage.cacheRead) currentRun.totalCacheReadTokens += usage.cacheRead;
1029
+ }
1030
+ if (!traceShipper || !currentRun.currentTurnSpan) return;
1031
+ const rawProvider = "provider" in message && typeof message.provider === "string" ? message.provider : void 0;
1032
+ const rawModelId = typeof message.model === "string" ? message.model : void 0;
1033
+ const stopReason = "stopReason" in message && typeof message.stopReason === "string" ? message.stopReason : void 0;
1034
+ const llmAttrs = [
1035
+ attrString("ai.operationId", "generateText")
1036
+ ];
1037
+ if (rawProvider) {
1038
+ llmAttrs.push(attrString("gen_ai.system", rawProvider));
1039
+ }
1040
+ if (rawModelId) {
1041
+ llmAttrs.push(
1042
+ attrString("gen_ai.response.model", rawModelId),
1043
+ attrString("gen_ai.request.model", rawModelId)
1044
+ );
1045
+ }
1046
+ if (usage) {
1047
+ llmAttrs.push(
1048
+ attrInt("gen_ai.usage.input_tokens", usage.input),
1049
+ attrInt("gen_ai.usage.output_tokens", usage.output)
1050
+ );
1051
+ if (usage.cacheRead) {
1052
+ llmAttrs.push(attrInt("gen_ai.usage.cache_read_tokens", usage.cacheRead));
1053
+ }
1054
+ }
1055
+ if (assistantText) {
1056
+ llmAttrs.push(attrString("ai.response.text", truncate(assistantText)));
1057
+ }
1058
+ if (currentRun.currentInput) {
1059
+ llmAttrs.push(attrString("ai.prompt", truncate(currentRun.currentInput)));
1060
+ }
1061
+ if (stopReason) {
1062
+ llmAttrs.push(attrString("ai.stop_reason", stopReason));
1063
+ }
1064
+ const llmSpan = traceShipper.startSpan({
1065
+ name: model != null ? model : "llm",
1066
+ parent: currentRun.currentTurnSpan.ids,
1067
+ eventId: currentRun.eventId,
1068
+ attributes: llmAttrs
1069
+ });
1070
+ const errorForSpan = stopReason === "error" || stopReason === "aborted" ? "errorMessage" in message && typeof message.errorMessage === "string" ? message.errorMessage : `Assistant ${stopReason}` : void 0;
1071
+ traceShipper.endSpan(llmSpan, errorForSpan ? { error: errorForSpan } : void 0);
1072
+ const toolCallIds = extractToolCallIds(message);
1073
+ for (const tcId of toolCallIds) {
1074
+ currentRun.toolCallToLlmSpan.set(tcId, llmSpan);
1075
+ }
1076
+ } catch (err) {
1077
+ log(`Error in message_end handler: ${err instanceof Error ? err.message : String(err)}`);
1078
+ }
1079
+ }
1080
+ function handleMessageUpdate(event) {
1081
+ try {
1082
+ if (!currentRun) return;
1083
+ const ame = event.assistantMessageEvent;
1084
+ if (ame.type === "text_delta" && "delta" in ame && typeof ame.delta === "string") {
1085
+ currentRun.outputParts.push(ame.delta);
1086
+ }
1087
+ } catch (err) {
1088
+ log(`Error in message_update handler: ${err instanceof Error ? err.message : String(err)}`);
1089
+ }
1090
+ }
1091
+ function handleTurnStart() {
1092
+ try {
1093
+ if (!currentRun) return;
1094
+ currentRun.outputParts = [];
1095
+ if (!traceShipper || !currentRun.rootSpan) return;
1096
+ if (currentRun.currentTurnSpan) {
1097
+ traceShipper.endSpan(currentRun.currentTurnSpan);
1098
+ }
1099
+ currentRun.turnNumber += 1;
1100
+ currentRun.currentTurnSpan = traceShipper.startSpan({
1101
+ name: `Turn ${currentRun.turnNumber}`,
1102
+ parent: currentRun.rootSpan.ids,
1103
+ eventId: currentRun.eventId,
1104
+ attributes: [
1105
+ attrString("ai.operationId", "ai.turn"),
1106
+ attrInt("ai.turn_number", currentRun.turnNumber)
1107
+ ]
1108
+ });
1109
+ } catch (err) {
1110
+ log(`Error in turn_start handler: ${err instanceof Error ? err.message : String(err)}`);
1111
+ }
1112
+ }
1113
+ function handleTurnEnd() {
1114
+ try {
1115
+ if (!currentRun || !traceShipper || !currentRun.currentTurnSpan) return;
1116
+ traceShipper.endSpan(currentRun.currentTurnSpan);
1117
+ currentRun.currentTurnSpan = void 0;
1118
+ } catch (err) {
1119
+ log(`Error in turn_end handler: ${err instanceof Error ? err.message : String(err)}`);
1120
+ }
1121
+ }
1122
+ function handleToolExecutionStart(toolCallId, toolName, args) {
1123
+ var _a2;
1124
+ try {
1125
+ if (!currentRun) return;
1126
+ currentRun.toolArgs.set(toolCallId, args);
1127
+ if (!traceShipper) return;
1128
+ const parentLlmSpan = currentRun.toolCallToLlmSpan.get(toolCallId);
1129
+ const parentSpan = (_a2 = parentLlmSpan != null ? parentLlmSpan : currentRun.currentTurnSpan) != null ? _a2 : currentRun.rootSpan;
1130
+ if (!parentSpan) return;
1131
+ const toolSpan = traceShipper.startSpan({
1132
+ name: formatToolSpanName(toolName, args),
1133
+ parent: parentSpan.ids,
1134
+ eventId: currentRun.eventId,
1135
+ attributes: [
1136
+ attrString("ai.operationId", "ai.toolCall"),
1137
+ attrString("ai.toolCall.name", toolName),
1138
+ attrString("ai.toolCall.id", toolCallId)
1139
+ ]
1140
+ });
1141
+ currentRun.toolSpans.set(toolCallId, toolSpan);
1142
+ } catch (err) {
1143
+ log(`Error in tool_execution_start handler: ${err instanceof Error ? err.message : String(err)}`);
1144
+ }
1145
+ }
1146
+ function handleToolExecutionEnd(toolCallId, toolName, result, isError) {
1147
+ try {
1148
+ if (!currentRun) return;
1149
+ const toolSpan = currentRun.toolSpans.get(toolCallId);
1150
+ currentRun.toolSpans.delete(toolCallId);
1151
+ currentRun.toolCallToLlmSpan.delete(toolCallId);
1152
+ const args = currentRun.toolArgs.get(toolCallId);
1153
+ currentRun.toolArgs.delete(toolCallId);
1154
+ if (!traceShipper || !toolSpan) return;
1155
+ const endAttrs = [];
1156
+ const argsStr = truncate(safeStringify(args));
1157
+ if (argsStr) endAttrs.push(attrString("ai.toolCall.args", argsStr));
1158
+ const resultStr = truncate(safeStringify(result));
1159
+ if (resultStr) endAttrs.push(attrString("ai.toolCall.result", resultStr));
1160
+ traceShipper.endSpan(toolSpan, {
1161
+ attributes: endAttrs,
1162
+ ...isError ? { error: `Tool "${toolName}" failed` } : {}
1163
+ });
1164
+ } catch (err) {
1165
+ log(`Error in tool_execution_end handler: ${err instanceof Error ? err.message : String(err)}`);
1166
+ }
1167
+ }
1168
+ function handleAgentEnd() {
1169
+ try {
1170
+ if (!currentRun) return;
1171
+ const run = currentRun;
1172
+ currentRun = void 0;
1173
+ if (traceShipper) {
1174
+ for (const [, span] of run.toolSpans) {
1175
+ traceShipper.endSpan(span);
1176
+ }
1177
+ }
1178
+ run.toolSpans.clear();
1179
+ run.toolCallToLlmSpan.clear();
1180
+ if (run.currentTurnSpan && traceShipper) {
1181
+ traceShipper.endSpan(run.currentTurnSpan);
1182
+ run.currentTurnSpan = void 0;
1183
+ }
1184
+ const outputText = run.outputParts.join("");
1185
+ if (traceShipper && run.rootSpan) {
1186
+ const rootAttrs = [
1187
+ attrString("ai.operationId", "generateText")
1188
+ ];
1189
+ if (run.lastModel) {
1190
+ run.rootSpan.name = run.lastModel;
1191
+ rootAttrs.push(attrString("gen_ai.response.model", run.lastModel));
1192
+ }
1193
+ if (run.currentInput) {
1194
+ rootAttrs.push(attrString("ai.prompt", truncate(run.currentInput)));
1195
+ }
1196
+ if (outputText) {
1197
+ rootAttrs.push(attrString("ai.response.text", truncate(outputText)));
1198
+ }
1199
+ if (run.totalInputTokens > 0) {
1200
+ rootAttrs.push(attrInt("gen_ai.usage.input_tokens", run.totalInputTokens));
1201
+ }
1202
+ if (run.totalOutputTokens > 0) {
1203
+ rootAttrs.push(attrInt("gen_ai.usage.output_tokens", run.totalOutputTokens));
1204
+ }
1205
+ if (run.totalCacheReadTokens > 0) {
1206
+ rootAttrs.push(attrInt("gen_ai.usage.cache_read_tokens", run.totalCacheReadTokens));
1207
+ }
1208
+ rootAttrs.push(attrInt("ai.total_turns", run.turnNumber));
1209
+ traceShipper.endSpan(run.rootSpan, { attributes: rootAttrs });
1210
+ }
1211
+ if (eventShipper) {
1212
+ eventShipper.finish(run.eventId, {
1213
+ userId: userId != null ? userId : "anonymous",
1214
+ model: run.lastModel || void 0,
1215
+ output: outputText || void 0,
1216
+ properties: {
1217
+ ...properties,
1218
+ sdk_version: libraryVersion,
1219
+ ...run.totalInputTokens > 0 ? { "ai.usage.prompt_tokens": run.totalInputTokens } : {},
1220
+ ...run.totalOutputTokens > 0 ? { "ai.usage.completion_tokens": run.totalOutputTokens } : {},
1221
+ ...run.totalCacheReadTokens > 0 ? { "ai.usage.cache_read_tokens": run.totalCacheReadTokens } : {}
1222
+ }
1223
+ }).catch(() => {
1224
+ });
1225
+ }
1226
+ Promise.all([
1227
+ eventShipper == null ? void 0 : eventShipper.flush(),
1228
+ traceShipper == null ? void 0 : traceShipper.flush()
1229
+ ]).catch(() => {
1230
+ });
1231
+ } catch (err) {
1232
+ log(`Error in agent_end handler: ${err instanceof Error ? err.message : String(err)}`);
1233
+ }
1234
+ }
1235
+ const unsubscribe = agent.subscribe((event) => {
1236
+ try {
1237
+ switch (event.type) {
1238
+ case "agent_start":
1239
+ handleAgentStart();
1240
+ break;
1241
+ case "message_end":
1242
+ handleMessageEnd(event.message);
1243
+ break;
1244
+ case "message_update":
1245
+ handleMessageUpdate(event);
1246
+ break;
1247
+ case "turn_start":
1248
+ handleTurnStart();
1249
+ break;
1250
+ case "turn_end":
1251
+ handleTurnEnd();
1252
+ break;
1253
+ case "tool_execution_start":
1254
+ handleToolExecutionStart(event.toolCallId, event.toolName, event.args);
1255
+ break;
1256
+ case "tool_execution_end":
1257
+ handleToolExecutionEnd(
1258
+ event.toolCallId,
1259
+ event.toolName,
1260
+ event.result,
1261
+ event.isError
1262
+ );
1263
+ break;
1264
+ case "agent_end":
1265
+ handleAgentEnd();
1266
+ break;
1267
+ }
1268
+ } catch (err) {
1269
+ log(`Unhandled error in event handler: ${err instanceof Error ? err.message : String(err)}`);
1270
+ }
1271
+ });
1272
+ return unsubscribe;
1273
+ }
1274
+
1275
+ // src/index.ts
1276
+ function envDebugEnabled() {
1277
+ var _a;
1278
+ if (typeof process === "undefined") return false;
1279
+ const flag = (_a = process.env) == null ? void 0 : _a.RAINDROP_AI_DEBUG;
1280
+ return flag === "1" || flag === "true";
1281
+ }
1282
+ function createRaindropPiAgent(opts) {
1283
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
1284
+ const hasWriteKey = typeof opts.writeKey === "string" && opts.writeKey.trim().length > 0;
1285
+ const eventsEnabled = ((_a = opts.events) == null ? void 0 : _a.enabled) !== false;
1286
+ const tracesEnabled = ((_b = opts.traces) == null ? void 0 : _b.enabled) !== false;
1287
+ if (!hasWriteKey && !opts.endpoint) {
1288
+ console.warn(
1289
+ "[raindrop-ai/pi-agent] writeKey not provided; telemetry shipping is disabled"
1290
+ );
1291
+ }
1292
+ const envDebug = envDebugEnabled();
1293
+ 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({
1295
+ writeKey: opts.writeKey,
1296
+ endpoint: opts.endpoint,
1297
+ enabled: true,
1298
+ debug: ((_e = opts.events) == null ? void 0 : _e.debug) === true || envDebug,
1299
+ partialFlushMs: (_f = opts.events) == null ? void 0 : _f.partialFlushMs
1300
+ }) : null;
1301
+ const traceShipper = tracesEnabled && (hasWriteKey || opts.endpoint) ? new TraceShipper2({
1302
+ writeKey: opts.writeKey,
1303
+ endpoint: opts.endpoint,
1304
+ enabled: true,
1305
+ debug: ((_g = opts.traces) == null ? void 0 : _g.debug) === true || envDebug,
1306
+ debugSpans: ((_h = opts.traces) == null ? void 0 : _h.debugSpans) === true || envDebug,
1307
+ flushIntervalMs: (_i = opts.traces) == null ? void 0 : _i.flushIntervalMs,
1308
+ maxBatchSize: (_j = opts.traces) == null ? void 0 : _j.maxBatchSize,
1309
+ maxQueueSize: (_k = opts.traces) == null ? void 0 : _k.maxQueueSize
1310
+ }) : null;
1311
+ const defaultOptions = {
1312
+ userId: opts.userId,
1313
+ convoId: opts.convoId,
1314
+ eventName: opts.eventName,
1315
+ properties: opts.properties
1316
+ };
1317
+ return {
1318
+ subscribe(agent, options) {
1319
+ return createSubscriber(
1320
+ agent,
1321
+ eventShipper,
1322
+ traceShipper,
1323
+ defaultOptions,
1324
+ options != null ? options : {},
1325
+ debug
1326
+ );
1327
+ },
1328
+ events: {
1329
+ async patch(eventId, data) {
1330
+ if (!eventShipper) return;
1331
+ await eventShipper.patch(eventId, data);
1332
+ },
1333
+ async addAttachments(eventId, attachments) {
1334
+ if (!eventShipper) return;
1335
+ await eventShipper.patch(eventId, { attachments });
1336
+ },
1337
+ async setProperties(eventId, properties) {
1338
+ if (!eventShipper) return;
1339
+ await eventShipper.patch(eventId, { properties });
1340
+ },
1341
+ async finish(eventId) {
1342
+ if (!eventShipper) return;
1343
+ await eventShipper.finish(eventId, {});
1344
+ }
1345
+ },
1346
+ users: {
1347
+ async identify(params) {
1348
+ var _a2;
1349
+ if (!eventShipper) return;
1350
+ await eventShipper.identify([
1351
+ { userId: params.userId, traits: (_a2 = params.traits) != null ? _a2 : {} }
1352
+ ]);
1353
+ }
1354
+ },
1355
+ signals: {
1356
+ async track(params) {
1357
+ if (!eventShipper) return;
1358
+ if (!params.name || !params.name.trim()) {
1359
+ console.warn("[raindrop-ai/pi-agent] signal name is required");
1360
+ return;
1361
+ }
1362
+ const {
1363
+ eventId,
1364
+ name,
1365
+ type,
1366
+ sentiment,
1367
+ timestamp,
1368
+ attachmentId,
1369
+ comment,
1370
+ after,
1371
+ ...otherProperties
1372
+ } = params;
1373
+ await eventShipper.trackSignal({
1374
+ eventId: eventId != null ? eventId : "",
1375
+ name,
1376
+ type,
1377
+ sentiment,
1378
+ timestamp,
1379
+ attachmentId,
1380
+ comment,
1381
+ after,
1382
+ properties: otherProperties
1383
+ });
1384
+ }
1385
+ },
1386
+ async flush() {
1387
+ var _a2, _b2;
1388
+ await Promise.all([
1389
+ (_a2 = eventShipper == null ? void 0 : eventShipper.flush()) != null ? _a2 : Promise.resolve(),
1390
+ (_b2 = traceShipper == null ? void 0 : traceShipper.flush()) != null ? _b2 : Promise.resolve()
1391
+ ]);
1392
+ },
1393
+ async shutdown() {
1394
+ var _a2, _b2;
1395
+ await Promise.all([
1396
+ (_a2 = eventShipper == null ? void 0 : eventShipper.shutdown()) != null ? _a2 : Promise.resolve(),
1397
+ (_b2 = traceShipper == null ? void 0 : traceShipper.shutdown()) != null ? _b2 : Promise.resolve()
1398
+ ]);
1399
+ }
1400
+ };
1401
+ }
1402
+ // Annotate the CommonJS export names for ESM import in node:
1403
+ 0 && (module.exports = {
1404
+ createRaindropPiAgent
1405
+ });