@raindrop-ai/eve 0.0.10 → 0.0.11

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.js ADDED
@@ -0,0 +1,1089 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var api = require('@opentelemetry/api');
6
+ var aiSdk = require('@raindrop-ai/ai-sdk');
7
+ var module$1 = require('module');
8
+ var async_hooks = require('async_hooks');
9
+
10
+ var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
11
+ // src/index.ts
12
+ function parseEveSessionParent(value) {
13
+ if (typeof value !== "object" || value === null) return void 0;
14
+ const p = value;
15
+ if (typeof p.sessionId !== "string") return void 0;
16
+ if (typeof p.turn !== "object" || p.turn === null) return void 0;
17
+ const t = p.turn;
18
+ if (typeof t.id !== "string" || typeof t.sequence !== "number") return void 0;
19
+ const parent = {
20
+ sessionId: p.sessionId,
21
+ turn: { id: t.id, sequence: t.sequence },
22
+ ...typeof p.rootSessionId === "string" ? { rootSessionId: p.rootSessionId } : {}
23
+ };
24
+ return parent;
25
+ }
26
+ var cached = void 0;
27
+ function loadGetSession() {
28
+ if (cached !== void 0) return cached;
29
+ try {
30
+ const requireFromHere = module$1.createRequire(
31
+ // `import.meta.url` is the ESM spelling; tsup polyfills it for CJS builds.
32
+ typeof __filename !== "undefined" ? __filename : (typeof document === 'undefined' ? require('u' + 'rl').pathToFileURL(__filename).href : (_documentCurrentScript && _documentCurrentScript.tagName.toUpperCase() === 'SCRIPT' && _documentCurrentScript.src || new URL('index.js', document.baseURI).href))
33
+ );
34
+ const mod = requireFromHere("eve/context");
35
+ cached = typeof mod.getSession === "function" ? mod.getSession : null;
36
+ } catch {
37
+ cached = null;
38
+ }
39
+ return cached;
40
+ }
41
+ function isEveSessionShape(value) {
42
+ if (typeof value !== "object" || value === null) return false;
43
+ const v = value;
44
+ if (typeof v.sessionId !== "string") return false;
45
+ if (v.turn !== void 0) {
46
+ if (typeof v.turn !== "object" || v.turn === null) return false;
47
+ const t = v.turn;
48
+ if (typeof t.id !== "string" || typeof t.sequence !== "number") return false;
49
+ }
50
+ if (v.parent === void 0) return true;
51
+ return parseEveSessionParent(v.parent) !== void 0;
52
+ }
53
+ function getEveSessionLineage() {
54
+ const getSession = loadGetSession();
55
+ if (!getSession) return void 0;
56
+ let raw;
57
+ try {
58
+ raw = getSession();
59
+ } catch {
60
+ return void 0;
61
+ }
62
+ return isEveSessionShape(raw) ? raw : void 0;
63
+ }
64
+
65
+ // src/internal/eve-turn-registry.ts
66
+ var EVE_TURN_SPAN_NAME = "ai.eve.turn";
67
+ var EVE_CONTINUATION_TOKEN_ATTR = "eve.continuation_token";
68
+ var EVE_SESSION_ID_ATTR = "eve.session.id";
69
+ var EveTurnRegistry = class {
70
+ constructor() {
71
+ /**
72
+ * Per-trace stack of in-flight `ai.eve.turn` entries.
73
+ *
74
+ * The stack lets us handle multiple concurrent turns on the same
75
+ * `traceId` correctly — both the nested case (turn-within-turn,
76
+ * theoretically possible if Eve ever supports tool-calls-as-turns)
77
+ * and the parallel case (two `ai.eve.turn` spans opened on a shared
78
+ * trace via `Promise.all`, which Workshop's in-process executor can
79
+ * do when running sibling sub-agents under one sandbox).
80
+ *
81
+ * Lookup returns the top of the stack, which is the most-recently
82
+ * opened still-active turn. That's the right answer for both cases:
83
+ * - Nested: the inner turn is the descendant of the active span
84
+ * that fires `ai.streamText.onStart`.
85
+ * - Parallel: tie-broken in favour of the most-recently-started
86
+ * entry. Public OTel APIs don't expose which `ai.eve.turn` is
87
+ * the ancestor of the active `step.execute`, so this is the
88
+ * best we can do without walking parent spans.
89
+ *
90
+ * Empty stacks are deleted from the map so the registry stays small.
91
+ */
92
+ this.stacks = /* @__PURE__ */ new Map();
93
+ }
94
+ /**
95
+ * Record a turn's attributes. Called from the SpanProcessor's
96
+ * `onStart` callback whenever an `ai.eve.turn` span is created.
97
+ * Push onto the per-trace stack — see {@link stacks}.
98
+ */
99
+ record(traceId, spanId, entry) {
100
+ if (!traceId || !spanId) return;
101
+ let stack = this.stacks.get(traceId);
102
+ if (!stack) {
103
+ stack = [];
104
+ this.stacks.set(traceId, stack);
105
+ }
106
+ stack.push({ ...entry, spanId });
107
+ }
108
+ /**
109
+ * Look up the currently-active turn for a trace. Returns `undefined`
110
+ * if no `ai.eve.turn` span has been seen for this trace — for example
111
+ * when running outside Eve, or before the turn span has fired
112
+ * `onStart` (shouldn't happen because Eve opens the turn span before
113
+ * entering its context, but treated defensively).
114
+ */
115
+ lookup(traceId) {
116
+ if (!traceId) return void 0;
117
+ const stack = this.stacks.get(traceId);
118
+ if (!stack || stack.length === 0) return void 0;
119
+ return stack[stack.length - 1];
120
+ }
121
+ /**
122
+ * Release the entry for a specific `(traceId, spanId)`. Called from
123
+ * the SpanProcessor's `onEnd` callback. We schedule the removal on a
124
+ * microtask so any in-flight `ai.streamText` `onStart` (which can
125
+ * fire *after* `ai.eve.turn` ends if Eve's tool-loop is
126
+ * mid-finalization) still finds the entry. The grace window is short
127
+ * — we just need to outlive the synchronous AI SDK fan-out, not
128
+ * minutes of idle time.
129
+ *
130
+ * Targets the exact `spanId` rather than popping the top of the
131
+ * stack so that interleaved parallel turns release their own entries
132
+ * regardless of end order.
133
+ */
134
+ releaseAfterTick(traceId, spanId) {
135
+ if (!traceId || !spanId) return;
136
+ Promise.resolve().then(() => {
137
+ const stack = this.stacks.get(traceId);
138
+ if (!stack) return;
139
+ const idx = stack.findIndex((e) => e.spanId === spanId);
140
+ if (idx !== -1) {
141
+ stack.splice(idx, 1);
142
+ }
143
+ if (stack.length === 0) {
144
+ this.stacks.delete(traceId);
145
+ }
146
+ });
147
+ }
148
+ /**
149
+ * Drop all entries. Called from the SpanProcessor's `shutdown` hook
150
+ * during exporter teardown.
151
+ */
152
+ clear() {
153
+ this.stacks.clear();
154
+ }
155
+ /**
156
+ * Total number of in-flight entries across all traces. For tests +
157
+ * diagnostic logging.
158
+ */
159
+ get size() {
160
+ let total = 0;
161
+ for (const stack of this.stacks.values()) total += stack.length;
162
+ return total;
163
+ }
164
+ };
165
+ var registry = new EveTurnRegistry();
166
+ function createEveTurnSpanProcessor() {
167
+ return {
168
+ onStart(span) {
169
+ if (span.name !== EVE_TURN_SPAN_NAME) return;
170
+ const attrs = span.attributes;
171
+ if (!attrs) return;
172
+ const ctx = span.spanContext();
173
+ const continuationToken = typeof attrs[EVE_CONTINUATION_TOKEN_ATTR] === "string" ? attrs[EVE_CONTINUATION_TOKEN_ATTR] : void 0;
174
+ const sessionId = typeof attrs[EVE_SESSION_ID_ATTR] === "string" ? attrs[EVE_SESSION_ID_ATTR] : void 0;
175
+ registry.record(ctx.traceId, ctx.spanId, {
176
+ continuationToken,
177
+ sessionId
178
+ });
179
+ },
180
+ onEnd(span) {
181
+ if (span.name !== EVE_TURN_SPAN_NAME) return;
182
+ const ctx = span.spanContext();
183
+ registry.releaseAfterTick(ctx.traceId, ctx.spanId);
184
+ },
185
+ forceFlush() {
186
+ return Promise.resolve();
187
+ },
188
+ shutdown() {
189
+ registry.clear();
190
+ return Promise.resolve();
191
+ }
192
+ };
193
+ }
194
+ function lookupEveTurn(traceId) {
195
+ return registry.lookup(traceId);
196
+ }
197
+ function installEveTurnSpanProcessor(traceApi) {
198
+ if (installState.installed) return true;
199
+ try {
200
+ let provider = traceApi.getTracerProvider();
201
+ const proxyProvider = provider;
202
+ if (typeof proxyProvider.getDelegate === "function") {
203
+ const delegate = proxyProvider.getDelegate();
204
+ if (delegate) provider = delegate;
205
+ }
206
+ const tp = provider;
207
+ if (typeof tp.addSpanProcessor !== "function") {
208
+ return false;
209
+ }
210
+ tp.addSpanProcessor(createEveTurnSpanProcessor());
211
+ installState.installed = true;
212
+ return true;
213
+ } catch {
214
+ return false;
215
+ }
216
+ }
217
+ var installState = { installed: false };
218
+
219
+ // ../core/dist/chunk-SK6EJEO7.js
220
+ var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
221
+ var MAX_RETRY_DELAY_MS = 3e4;
222
+ function wait(ms) {
223
+ return new Promise((resolve) => setTimeout(resolve, ms));
224
+ }
225
+ function formatEndpoint(endpoint) {
226
+ if (!endpoint) return void 0;
227
+ return endpoint.endsWith("/") ? endpoint : `${endpoint}/`;
228
+ }
229
+ function redactUrlForLog(url) {
230
+ try {
231
+ const parsed = new URL(url);
232
+ parsed.username = "";
233
+ parsed.password = "";
234
+ parsed.search = "";
235
+ parsed.hash = "";
236
+ return parsed.toString();
237
+ } catch (e) {
238
+ return "<unparseable-url>";
239
+ }
240
+ }
241
+ function parseRetryAfter(headers) {
242
+ var _a;
243
+ const value = (_a = headers.get("Retry-After")) != null ? _a : headers.get("retry-after");
244
+ if (!value) return void 0;
245
+ const asNumber = Number(value);
246
+ if (value.trim() !== "" && !Number.isNaN(asNumber)) return asNumber * 1e3;
247
+ const asDate = new Date(value).getTime();
248
+ if (!Number.isNaN(asDate)) {
249
+ const delta = asDate - Date.now();
250
+ return delta > 0 ? delta : 0;
251
+ }
252
+ return void 0;
253
+ }
254
+ function getRetryDelayMs(attemptNumber, previousError) {
255
+ if (previousError && typeof previousError === "object" && previousError !== null && "retryAfterMs" in previousError) {
256
+ const v = previousError.retryAfterMs;
257
+ if (typeof v === "number") return Math.min(Math.max(0, v), MAX_RETRY_DELAY_MS);
258
+ }
259
+ if (attemptNumber <= 1) return 0;
260
+ const base = 500;
261
+ const factor = Math.pow(2, attemptNumber - 2);
262
+ return Math.min(base * factor, MAX_RETRY_DELAY_MS);
263
+ }
264
+ async function withRetry(operation, opName, opts) {
265
+ const prefix = opts.sdkName ? `[raindrop-ai/${opts.sdkName}]` : "[raindrop-ai/core]";
266
+ let lastError = void 0;
267
+ for (let attemptNumber = 1; attemptNumber <= opts.maxAttempts; attemptNumber++) {
268
+ if (attemptNumber > 1) {
269
+ const delay = getRetryDelayMs(attemptNumber, lastError);
270
+ if (opts.debug) {
271
+ console.warn(
272
+ `${prefix} ${opName} retry ${attemptNumber}/${opts.maxAttempts} in ${delay}ms`
273
+ );
274
+ }
275
+ if (delay > 0) await wait(delay);
276
+ } else if (opts.debug) {
277
+ console.log(`${prefix} ${opName} attempt ${attemptNumber}/${opts.maxAttempts}`);
278
+ }
279
+ try {
280
+ return await operation();
281
+ } catch (err) {
282
+ lastError = err;
283
+ if (opts.debug) {
284
+ const msg = err instanceof Error ? err.message : String(err);
285
+ console.warn(
286
+ `${prefix} ${opName} attempt ${attemptNumber} failed: ${msg}${attemptNumber === opts.maxAttempts ? " (no more retries)" : ""}`
287
+ );
288
+ }
289
+ if (lastError && typeof lastError === "object" && "retryable" in lastError && !lastError.retryable)
290
+ break;
291
+ if (attemptNumber === opts.maxAttempts) break;
292
+ }
293
+ }
294
+ throw lastError instanceof Error ? lastError : new Error(String(lastError));
295
+ }
296
+ async function postJson(url, body, headers, opts) {
297
+ var _a;
298
+ const opName = `POST ${redactUrlForLog(url)}`;
299
+ const timeoutMs = (_a = opts.timeoutMs) != null ? _a : DEFAULT_REQUEST_TIMEOUT_MS;
300
+ await withRetry(
301
+ async () => {
302
+ const resp = await fetch(url, {
303
+ method: "POST",
304
+ headers: {
305
+ "Content-Type": "application/json",
306
+ ...headers
307
+ },
308
+ body: JSON.stringify(body),
309
+ signal: AbortSignal.timeout(timeoutMs)
310
+ });
311
+ if (!resp.ok) {
312
+ const text = await resp.text().catch(() => "");
313
+ const err = new Error(
314
+ `HTTP ${resp.status} ${resp.statusText}${text ? `: ${text}` : ""}`
315
+ );
316
+ const retryAfterMs = parseRetryAfter(resp.headers);
317
+ if (typeof retryAfterMs === "number") err.retryAfterMs = retryAfterMs;
318
+ err.retryable = resp.status === 429 || resp.status >= 500;
319
+ throw err;
320
+ }
321
+ },
322
+ opName,
323
+ opts
324
+ );
325
+ }
326
+ var SpanStatusCode = {
327
+ UNSET: 0,
328
+ OK: 1,
329
+ ERROR: 2
330
+ };
331
+ function buildExportTraceServiceRequest(spans, serviceName = "raindrop.core", serviceVersion = "0.0.0") {
332
+ return {
333
+ resourceSpans: [
334
+ {
335
+ resource: {
336
+ attributes: [{ key: "service.name", value: { stringValue: serviceName } }]
337
+ },
338
+ scopeSpans: [
339
+ {
340
+ scope: { name: serviceName, version: serviceVersion },
341
+ spans
342
+ }
343
+ ]
344
+ }
345
+ ]
346
+ };
347
+ }
348
+ var LOCAL_DEBUGGER_ENV_VAR = "RAINDROP_LOCAL_DEBUGGER";
349
+ var WORKSHOP_ENV_VAR = "RAINDROP_WORKSHOP";
350
+ var DEFAULT_LOCAL_WORKSHOP_URL = "http://localhost:5899/v1/";
351
+ function readEnvVar(name) {
352
+ var _a;
353
+ try {
354
+ const env = (_a = globalThis == null ? void 0 : globalThis.process) == null ? void 0 : _a.env;
355
+ if (env && typeof env[name] === "string" && env[name].length > 0) {
356
+ return env[name];
357
+ }
358
+ } catch (e) {
359
+ }
360
+ return void 0;
361
+ }
362
+ function readWorkshopEnv() {
363
+ const raw = readEnvVar(WORKSHOP_ENV_VAR);
364
+ if (raw === void 0) return void 0;
365
+ const trimmed = raw.trim();
366
+ if (trimmed.length === 0) return void 0;
367
+ if (/^https?:\/\//i.test(trimmed)) return { url: trimmed };
368
+ if (/^(1|true|yes|on)$/i.test(trimmed)) return "enable";
369
+ if (/^(0|false|no|off)$/i.test(trimmed)) return "disable";
370
+ return void 0;
371
+ }
372
+ function isLocalDevHost(hostname) {
373
+ if (!hostname) return false;
374
+ if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "0.0.0.0" || hostname === "::1") {
375
+ return true;
376
+ }
377
+ if (hostname.endsWith(".localhost")) return true;
378
+ return false;
379
+ }
380
+ function readRuntimeHostname() {
381
+ try {
382
+ const loc = globalThis == null ? void 0 : globalThis.location;
383
+ if (loc && typeof loc.hostname === "string" && loc.hostname.length > 0) {
384
+ return loc.hostname;
385
+ }
386
+ } catch (e) {
387
+ }
388
+ return void 0;
389
+ }
390
+ function shouldAutoEnableLocalWorkshop() {
391
+ if (isLocalDevHost(readRuntimeHostname())) return true;
392
+ if (readEnvVar("NODE_ENV") === "development") return true;
393
+ return false;
394
+ }
395
+ function resolveLocalDebuggerBaseUrl(baseUrl) {
396
+ var _a, _b, _c;
397
+ if (baseUrl === null) return null;
398
+ if (typeof baseUrl === "string" && baseUrl.length > 0) {
399
+ return (_a = formatEndpoint(baseUrl)) != null ? _a : null;
400
+ }
401
+ const explicitUrlEnv = readEnvVar(LOCAL_DEBUGGER_ENV_VAR);
402
+ if (explicitUrlEnv) return (_b = formatEndpoint(explicitUrlEnv)) != null ? _b : null;
403
+ const workshopEnv = readWorkshopEnv();
404
+ if (workshopEnv === "disable") return null;
405
+ if (workshopEnv === "enable") return DEFAULT_LOCAL_WORKSHOP_URL;
406
+ if (workshopEnv && "url" in workshopEnv) return (_c = formatEndpoint(workshopEnv.url)) != null ? _c : null;
407
+ if (shouldAutoEnableLocalWorkshop()) return DEFAULT_LOCAL_WORKSHOP_URL;
408
+ return null;
409
+ }
410
+ function mirrorTraceExportToLocalDebugger(body, options = {}) {
411
+ var _a;
412
+ const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
413
+ if (!baseUrl) return;
414
+ void postJson(`${baseUrl}traces`, body, {}, {
415
+ maxAttempts: 1,
416
+ debug: (_a = options.debug) != null ? _a : false,
417
+ sdkName: options.sdkName
418
+ }).catch(() => {
419
+ });
420
+ }
421
+ var PROJECT_ID_HEADER = "X-Raindrop-Project-Id";
422
+ var PROJECT_ID_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
423
+ function isValidProjectIdSlug(value) {
424
+ return PROJECT_ID_SLUG_PATTERN.test(value);
425
+ }
426
+ function normalizeProjectId(raw, opts) {
427
+ if (typeof raw !== "string") return void 0;
428
+ const trimmed = raw.trim();
429
+ if (!trimmed) return void 0;
430
+ if (!isValidProjectIdSlug(trimmed) && opts.debug) {
431
+ console.warn(
432
+ `${opts.prefix} projectId "${trimmed}" does not match slug ${PROJECT_ID_SLUG_PATTERN.source}; sending anyway \u2014 backend may reject with HTTP 400`
433
+ );
434
+ }
435
+ return trimmed;
436
+ }
437
+ function projectIdHeaders(projectId) {
438
+ return projectId ? { [PROJECT_ID_HEADER]: projectId } : {};
439
+ }
440
+ var DEFAULT_REDACT_ATTRIBUTE_KEYS = [
441
+ "ai.request.providerOptions",
442
+ "ai.response.providerMetadata"
443
+ ];
444
+ new Set(DEFAULT_REDACT_ATTRIBUTE_KEYS);
445
+ globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = async_hooks.AsyncLocalStorage;
446
+
447
+ // src/internal/limits.ts
448
+ var DEFAULT_MAX_TEXT_FIELD_CHARS2 = 1e6;
449
+ var TRUNCATION_MARKER2 = "...[truncated by raindrop]";
450
+ function effectiveAttributeLimit(configured) {
451
+ let limit = typeof configured === "number" && Number.isFinite(configured) && configured > 0 ? Math.floor(configured) : DEFAULT_MAX_TEXT_FIELD_CHARS2;
452
+ try {
453
+ const raw = globalThis?.process?.env?.OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT;
454
+ if (raw) {
455
+ const envLimit = Number.parseInt(raw, 10);
456
+ if (Number.isFinite(envLimit) && envLimit > 0) {
457
+ limit = Math.min(limit, envLimit);
458
+ }
459
+ }
460
+ } catch {
461
+ }
462
+ return limit;
463
+ }
464
+ function truncateText(value, limit) {
465
+ if (value.length <= limit) return value;
466
+ if (limit > TRUNCATION_MARKER2.length) {
467
+ return value.slice(0, limit - TRUNCATION_MARKER2.length) + TRUNCATION_MARKER2;
468
+ }
469
+ return value.slice(0, Math.max(0, limit));
470
+ }
471
+
472
+ // src/internal/exporter.ts
473
+ function hexToBase64(hex) {
474
+ if (!hex) return void 0;
475
+ if (hex.length === 0 || /^0+$/.test(hex)) return void 0;
476
+ const bytes = new Uint8Array(hex.length / 2);
477
+ for (let i = 0; i < bytes.length; i++) {
478
+ bytes[i] = parseInt(hex.substr(i * 2, 2), 16);
479
+ }
480
+ if (typeof Buffer !== "undefined") return Buffer.from(bytes).toString("base64");
481
+ let bin = "";
482
+ for (let i = 0; i < bytes.length; i++) bin += String.fromCharCode(bytes[i]);
483
+ return globalThis.btoa(bin);
484
+ }
485
+ function hrTimeToNanoString(hr) {
486
+ const [s, ns] = hr;
487
+ return (BigInt(Math.trunc(s)) * 1000000000n + BigInt(Math.trunc(ns))).toString();
488
+ }
489
+ function attributeToKeyValue(key, value, maxChars) {
490
+ if (value === void 0 || value === null) return void 0;
491
+ if (typeof value === "string") return { key, value: { stringValue: truncateText(value, maxChars) } };
492
+ if (typeof value === "boolean") return { key, value: { boolValue: value } };
493
+ if (typeof value === "number") {
494
+ return Number.isInteger(value) ? { key, value: { intValue: String(value) } } : { key, value: { doubleValue: value } };
495
+ }
496
+ if (Array.isArray(value)) {
497
+ return {
498
+ key,
499
+ value: {
500
+ arrayValue: {
501
+ values: value.map((v) => {
502
+ if (v === null || v === void 0) return void 0;
503
+ if (typeof v === "string") return { stringValue: truncateText(v, maxChars) };
504
+ if (typeof v === "boolean") return { boolValue: v };
505
+ if (typeof v === "number") {
506
+ return Number.isInteger(v) ? { intValue: String(v) } : { doubleValue: v };
507
+ }
508
+ return void 0;
509
+ }).filter((v) => v !== void 0)
510
+ }
511
+ }
512
+ };
513
+ }
514
+ return void 0;
515
+ }
516
+ function attributesToKeyValues(attrs, maxChars) {
517
+ if (!attrs) return [];
518
+ const out = [];
519
+ for (const [k, v] of Object.entries(attrs)) {
520
+ const kv = attributeToKeyValue(k, v, maxChars);
521
+ if (kv) out.push(kv);
522
+ }
523
+ return out;
524
+ }
525
+ function statusFromReadable(span) {
526
+ const code = span.status?.code;
527
+ if (code === void 0) return void 0;
528
+ if (code === 2) {
529
+ return { code: SpanStatusCode.ERROR, message: span.status.message };
530
+ }
531
+ if (code === 1) {
532
+ return { code: SpanStatusCode.OK };
533
+ }
534
+ return { code: SpanStatusCode.UNSET };
535
+ }
536
+ function readableSpanToOtlp(span, maxChars) {
537
+ const ctx = span.spanContext();
538
+ const parentSpanIdHex = span.parentSpanContext?.spanId ?? span.parentSpanId;
539
+ const traceId = hexToBase64(ctx.traceId);
540
+ const spanId = hexToBase64(ctx.spanId);
541
+ if (!traceId || !spanId) {
542
+ throw new Error(
543
+ `span has invalid context: traceId=${ctx.traceId} spanId=${ctx.spanId}`
544
+ );
545
+ }
546
+ const parentSpanId = hexToBase64(parentSpanIdHex);
547
+ const attrs = attributesToKeyValues(span.attributes, maxChars);
548
+ const otlp = {
549
+ traceId,
550
+ spanId,
551
+ name: span.name,
552
+ startTimeUnixNano: hrTimeToNanoString(span.startTime),
553
+ endTimeUnixNano: hrTimeToNanoString(span.endTime)
554
+ };
555
+ if (parentSpanId) otlp.parentSpanId = parentSpanId;
556
+ if (attrs.length) otlp.attributes = attrs;
557
+ const status = statusFromReadable(span);
558
+ if (status) otlp.status = status;
559
+ return otlp;
560
+ }
561
+ var RaindropEveSpanExporter = class {
562
+ constructor(opts = {}) {
563
+ this.inFlight = /* @__PURE__ */ new Set();
564
+ this.shuttingDown = false;
565
+ this.auxShutdowns = [];
566
+ this.writeKey = opts.writeKey?.trim();
567
+ this.baseUrl = formatEndpoint(opts.endpoint) ?? "https://api.raindrop.ai/v1/";
568
+ this.sdkName = opts.sdkName ?? "eve";
569
+ this.maxTextFieldChars = opts.maxTextFieldChars;
570
+ this.serviceName = opts.serviceName ?? "raindrop.eve";
571
+ this.serviceVersion = opts.serviceVersion ?? "0.0.0";
572
+ this.debug = opts.debug === true;
573
+ this.prefix = `[raindrop-ai/${this.sdkName}]`;
574
+ this.projectId = normalizeProjectId(opts.projectId, {
575
+ debug: this.debug,
576
+ prefix: this.prefix
577
+ });
578
+ const explicit = opts.localWorkshopUrl === false ? null : opts.localWorkshopUrl;
579
+ this.localDebuggerUrl = resolveLocalDebuggerBaseUrl(explicit) ?? void 0;
580
+ if (this.debug) {
581
+ console.log(
582
+ `${this.prefix} Initialized`,
583
+ {
584
+ raindrop: this.writeKey ? this.baseUrl : "disabled (no writeKey)",
585
+ workshop: this.localDebuggerUrl ?? "disabled"
586
+ }
587
+ );
588
+ }
589
+ }
590
+ /** True when we have at least one destination (Raindrop or Workshop). */
591
+ hasDestinations() {
592
+ return Boolean(this.writeKey || this.localDebuggerUrl);
593
+ }
594
+ /**
595
+ * Update the OTLP `service.name` attribute. Called by Eve's
596
+ * `setup({ agentName })` so the resource attribute reflects the actual
597
+ * agent name when the caller didn't pin one via `opts.serviceName`.
598
+ */
599
+ setServiceName(serviceName) {
600
+ if (!serviceName || serviceName === this.serviceName) return;
601
+ this.serviceName = serviceName;
602
+ if (this.debug) {
603
+ console.log(`${this.prefix} serviceName updated \u2192 ${serviceName}`);
604
+ }
605
+ }
606
+ export(spans, resultCallback) {
607
+ if (this.shuttingDown) {
608
+ resultCallback({ code: 1, error: new Error("exporter shut down") });
609
+ return;
610
+ }
611
+ if (spans.length === 0) {
612
+ resultCallback({ code: 0 });
613
+ return;
614
+ }
615
+ const maxChars = effectiveAttributeLimit(this.maxTextFieldChars);
616
+ const otlpSpans = [];
617
+ for (const span of spans) {
618
+ try {
619
+ otlpSpans.push(readableSpanToOtlp(span, maxChars));
620
+ } catch (err) {
621
+ if (this.debug) {
622
+ console.warn(`${this.prefix} failed to convert span`, err);
623
+ }
624
+ }
625
+ }
626
+ if (otlpSpans.length === 0) {
627
+ resultCallback({ code: 0 });
628
+ return;
629
+ }
630
+ const body = buildExportTraceServiceRequest(otlpSpans, this.serviceName, this.serviceVersion);
631
+ if (this.localDebuggerUrl) {
632
+ mirrorTraceExportToLocalDebugger(body, {
633
+ baseUrl: this.localDebuggerUrl,
634
+ debug: this.debug,
635
+ sdkName: this.sdkName
636
+ });
637
+ }
638
+ if (!this.writeKey) {
639
+ if (this.debug) {
640
+ console.log(`${this.prefix} exported ${otlpSpans.length} spans (workshop-only)`);
641
+ }
642
+ resultCallback({ code: 0 });
643
+ return;
644
+ }
645
+ const url = `${this.baseUrl}traces`;
646
+ if (this.debug) {
647
+ console.log(`${this.prefix} sending ${otlpSpans.length} spans -> ${url}`);
648
+ }
649
+ const p = postJson(
650
+ url,
651
+ body,
652
+ {
653
+ Authorization: `Bearer ${this.writeKey}`,
654
+ ...projectIdHeaders(this.projectId)
655
+ },
656
+ { maxAttempts: 3, debug: this.debug, sdkName: this.sdkName }
657
+ ).then(() => {
658
+ if (this.debug) console.log(`${this.prefix} sent ${otlpSpans.length} spans`);
659
+ resultCallback({ code: 0 });
660
+ }).catch((err) => {
661
+ const msg = err instanceof Error ? err.message : String(err);
662
+ console.warn(`${this.prefix} failed to send ${otlpSpans.length} spans: ${msg}`);
663
+ resultCallback({ code: 1, error: err instanceof Error ? err : new Error(msg) });
664
+ }).finally(() => {
665
+ this.inFlight.delete(p);
666
+ });
667
+ this.inFlight.add(p);
668
+ }
669
+ async forceFlush() {
670
+ await Promise.all([...this.inFlight].map((p) => p.catch(() => {
671
+ })));
672
+ }
673
+ async shutdown() {
674
+ this.shuttingDown = true;
675
+ await this.forceFlush();
676
+ await Promise.all(
677
+ this.auxShutdowns.map((fn) => fn().catch(() => {
678
+ }))
679
+ );
680
+ }
681
+ /**
682
+ * Register an extra teardown hook to run during {@link shutdown}. Used to
683
+ * drain the AI SDK trace + event shippers that the `@raindrop-ai/eve`
684
+ * integration builds alongside this exporter — without this, pending
685
+ * `track_partial` events and AI SDK trace spans would be dropped on
686
+ * SIGINT / SIGTERM.
687
+ */
688
+ attachAuxShutdown(fn) {
689
+ this.auxShutdowns.push(fn);
690
+ }
691
+ };
692
+
693
+ // package.json
694
+ var package_default = {
695
+ name: "@raindrop-ai/eve",
696
+ version: "0.0.10"};
697
+
698
+ // src/internal/version.ts
699
+ var libraryName = package_default.name;
700
+ var libraryVersion = package_default.version;
701
+
702
+ // src/index.ts
703
+ var RAINDROP_EVE_SDK_NAME = libraryName;
704
+ var RAINDROP_EVE_SDK_VERSION = libraryVersion;
705
+ var canonicalTurnIdBySession = /* @__PURE__ */ new Map();
706
+ var MAX_CANONICAL_TURN_SESSIONS = 1024;
707
+ function _resetCanonicalTurnIds() {
708
+ canonicalTurnIdBySession.clear();
709
+ }
710
+ var RAINDROP_EVE_INTEGRATION = /* @__PURE__ */ Symbol.for("raindrop.eve.integration");
711
+ var RAINDROP_EVE_OTEL_REGISTERED = /* @__PURE__ */ Symbol.for("raindrop.eve.otel.registered");
712
+ function wrapWithDebugLogs(integration, prefix) {
713
+ const methodNames = [
714
+ "onStart",
715
+ "onStepStart",
716
+ "onLanguageModelCallStart",
717
+ "onLanguageModelCallEnd",
718
+ "onToolExecutionStart",
719
+ "onToolExecutionEnd",
720
+ "onToolCallStart",
721
+ "onToolCallFinish",
722
+ "onStepFinish",
723
+ "onObjectStepStart",
724
+ "onObjectStepFinish",
725
+ "onEmbedStart",
726
+ "onEmbedEnd",
727
+ "onRerankStart",
728
+ "onRerankEnd",
729
+ // `onFinish` is the v7-canary-and-earlier name; `onEnd` is the
730
+ // post-canary.144 name (see `injectEveCallContext` for the alias).
731
+ // Both are listed so the wrapper logs whichever the underlying
732
+ // integration / dispatcher actually invokes.
733
+ "onFinish",
734
+ "onEnd",
735
+ "onError",
736
+ // `onAbort` (v7 canary post-beta.116) fires when a streamText call is
737
+ // cancelled via its AbortSignal — neither `onEnd` nor `onError` runs then.
738
+ "onAbort"
739
+ ];
740
+ const wrapped = integration;
741
+ for (const name of methodNames) {
742
+ const original = wrapped[name];
743
+ if (typeof original !== "function") continue;
744
+ const fn = original;
745
+ wrapped[name] = function(event) {
746
+ try {
747
+ const ev = event;
748
+ const op = ev && (ev.operationId ?? ev["operation_id"]);
749
+ console.log(`${prefix} ai-sdk-tel ${name} op=${String(op ?? "?")}`);
750
+ } catch {
751
+ }
752
+ return fn.call(integration, event);
753
+ };
754
+ }
755
+ return integration;
756
+ }
757
+ function injectEveCallContext(integration, opts) {
758
+ const target = integration;
759
+ if (typeof target.onFinish === "function" && typeof target.onEnd !== "function") {
760
+ target.onEnd = target.onFinish;
761
+ }
762
+ const original = target.onStart;
763
+ if (typeof original !== "function") return integration;
764
+ const fn = original;
765
+ target.onStart = function(event) {
766
+ try {
767
+ const ev = event;
768
+ if (envDebug()) {
769
+ try {
770
+ const ctxAny = ev.runtimeContext;
771
+ const messages = ev.messages ?? [];
772
+ const firstMsgContent = messages[0]?.content;
773
+ const firstMsgPreview = typeof firstMsgContent === "string" ? firstMsgContent.slice(0, 220) : Array.isArray(firstMsgContent) ? JSON.stringify(firstMsgContent).slice(0, 220) : void 0;
774
+ const activeSpanForDebug = api.trace.getActiveSpan();
775
+ const traceIdForDebug = activeSpanForDebug?.spanContext?.()?.traceId;
776
+ const turnEntryForDebug = lookupEveTurn(traceIdForDebug);
777
+ const lineageForDebug = getEveSessionLineage();
778
+ console.log(
779
+ `[raindrop-ai/eve][probe] agentName=${opts.agentName} fn=${ev.functionId} traceId=${traceIdForDebug} activeSpan=${activeSpanForDebug?.name} runtimeContextKeys=${ctxAny ? Object.keys(ctxAny).join(",") : "<none>"} turnEntry=${JSON.stringify(turnEntryForDebug)} eveSession=${JSON.stringify(lineageForDebug)} firstMsg=${JSON.stringify(firstMsgPreview)}`
780
+ );
781
+ } catch (e) {
782
+ console.log(`[raindrop-ai/eve][probe] error: ${e.message}`);
783
+ }
784
+ }
785
+ const ctx = ev.runtimeContext;
786
+ const activeSpan = api.trace.getActiveSpan();
787
+ const spanAttrs = activeSpan?.attributes;
788
+ const traceId = activeSpan?.spanContext?.()?.traceId;
789
+ const turnEntry = lookupEveTurn(traceId);
790
+ const eveSession = getEveSessionLineage();
791
+ const sessionFromContext = eveSession?.sessionId ?? (typeof ctx?.["eve.session.id"] === "string" ? ctx["eve.session.id"] : void 0) ?? turnEntry?.sessionId ?? (typeof spanAttrs?.["eve.session.id"] === "string" ? spanAttrs["eve.session.id"] : void 0);
792
+ const convoFromContext = (typeof ctx?.["eve.continuation_token"] === "string" ? ctx["eve.continuation_token"] : void 0) ?? turnEntry?.continuationToken ?? (typeof spanAttrs?.["eve.continuation_token"] === "string" ? spanAttrs["eve.continuation_token"] : void 0) ?? // eve >= 0.45 stopped forwarding `eve.continuation_token`,
793
+ // the legacy convo key — leaving `raindrop.convoId` null so every
794
+ // multi-turn run un-grouped on the Conversations view. The session id is
795
+ // stable across a run's turns and distinct per run, so falling back to
796
+ // it restores turn-to-conversation grouping. An author-supplied
797
+ // `raindrop.convoId` (e.g. a durable Slack thread id mapped in the step
798
+ // hook) still wins: it is already on `meta` before this is applied.
799
+ sessionFromContext;
800
+ const ctxTurnId = typeof ctx?.["eve.turn.id"] === "string" ? ctx["eve.turn.id"] : void 0;
801
+ if (sessionFromContext && ctxTurnId) {
802
+ if (canonicalTurnIdBySession.size >= MAX_CANONICAL_TURN_SESSIONS && !canonicalTurnIdBySession.has(sessionFromContext)) {
803
+ const oldest = canonicalTurnIdBySession.keys().next().value;
804
+ if (oldest !== void 0) canonicalTurnIdBySession.delete(oldest);
805
+ }
806
+ canonicalTurnIdBySession.set(sessionFromContext, ctxTurnId);
807
+ }
808
+ const turnIdFromContext = ctxTurnId ?? (sessionFromContext ? canonicalTurnIdBySession.get(sessionFromContext) : void 0) ?? (typeof eveSession?.turn?.id === "string" ? eveSession.turn.id : void 0) ?? (typeof spanAttrs?.["eve.turn.id"] === "string" ? spanAttrs["eve.turn.id"] : void 0);
809
+ const meta = ev.metadata ?? {};
810
+ let userProps;
811
+ for (const k of Object.keys(meta)) {
812
+ if (k === "raindrop.properties") continue;
813
+ if (k.startsWith("raindrop.") || k.startsWith("eve.")) continue;
814
+ (userProps ?? (userProps = {}))[k] = meta[k];
815
+ }
816
+ if (ctx) {
817
+ for (const [k, v] of Object.entries(ctx)) {
818
+ if (typeof v !== "string") continue;
819
+ if (k.startsWith("eve.")) continue;
820
+ if (k.startsWith("raindrop.")) {
821
+ if (meta[k] === void 0) meta[k] = v;
822
+ } else if (!userProps || userProps[k] === void 0) {
823
+ (userProps ?? (userProps = {}))[k] = v;
824
+ }
825
+ }
826
+ }
827
+ if (opts.authoredMetadata) {
828
+ for (const [k, v] of Object.entries(opts.authoredMetadata)) {
829
+ if (k.startsWith("raindrop.") || k.startsWith("eve.")) {
830
+ if (meta[k] === void 0) meta[k] = v;
831
+ } else if (!userProps || userProps[k] === void 0) {
832
+ (userProps ?? (userProps = {}))[k] = v;
833
+ }
834
+ }
835
+ }
836
+ if (userProps) {
837
+ const existing = meta["raindrop.properties"];
838
+ const existingProps = existing && typeof existing === "object" ? existing : void 0;
839
+ meta["raindrop.properties"] = { ...userProps, ...existingProps };
840
+ }
841
+ const parentToolContext = aiSdk.getCurrentParentToolContext();
842
+ const crossSandboxParent = parentToolContext === void 0 ? eveSession?.parent : void 0;
843
+ const runtimeParentSessionId = parentToolContext === void 0 && crossSandboxParent === void 0 && typeof meta["raindrop.parent.sessionId"] === "string" ? meta["raindrop.parent.sessionId"] : void 0;
844
+ const crossSandboxAgentName = typeof ev.functionId === "string" && ev.functionId ? ev.functionId : opts.agentName;
845
+ const detected = parentToolContext?.toolName ?? (crossSandboxParent !== void 0 || runtimeParentSessionId !== void 0 ? crossSandboxAgentName : void 0);
846
+ const activeTraceId = parentToolContext ? void 0 : api.trace.getActiveSpan()?.spanContext()?.traceId;
847
+ const isSubAgent = parentToolContext !== void 0 || crossSandboxParent !== void 0 || runtimeParentSessionId !== void 0;
848
+ const rootTurnEventId = !isSubAgent && sessionFromContext && turnIdFromContext ? eveTurnEventId(sessionFromContext, turnIdFromContext) : void 0;
849
+ const eventId = rootTurnEventId ?? activeTraceId;
850
+ if (sessionFromContext && meta["raindrop.userId"] === void 0) {
851
+ meta["raindrop.userId"] = sessionFromContext;
852
+ }
853
+ if (meta["raindrop.convoId"] === void 0) {
854
+ const parentConvo = isSubAgent && typeof meta["raindrop.parent.rootSessionId"] === "string" ? meta["raindrop.parent.rootSessionId"] : isSubAgent && typeof meta["raindrop.parent.sessionId"] === "string" ? meta["raindrop.parent.sessionId"] : void 0;
855
+ const convo = parentConvo ?? convoFromContext;
856
+ if (convo) meta["raindrop.convoId"] = convo;
857
+ }
858
+ if (eventId && meta["raindrop.eventId"] === void 0) {
859
+ meta["raindrop.eventId"] = eventId;
860
+ }
861
+ if (detected && meta["eve.subagent.name"] === void 0) {
862
+ meta["eve.subagent.name"] = detected;
863
+ }
864
+ if (meta["eve.agent.role"] === void 0) {
865
+ meta["eve.agent.role"] = detected ? "subagent" : "root";
866
+ }
867
+ if (parentToolContext) {
868
+ if (meta["raindrop.parent.callId"] === void 0) {
869
+ meta["raindrop.parent.callId"] = parentToolContext.parentCallId;
870
+ }
871
+ if (meta["raindrop.parent.toolCallId"] === void 0) {
872
+ meta["raindrop.parent.toolCallId"] = parentToolContext.toolCallId;
873
+ }
874
+ if (meta["raindrop.parent.toolName"] === void 0) {
875
+ meta["raindrop.parent.toolName"] = parentToolContext.toolName;
876
+ }
877
+ } else if (crossSandboxParent) {
878
+ for (const [key, value] of Object.entries(parentLineageMetadata(crossSandboxParent))) {
879
+ if (meta[key] === void 0) meta[key] = value;
880
+ }
881
+ }
882
+ if (Object.keys(meta).length > 0) ev.metadata = meta;
883
+ } catch {
884
+ }
885
+ return fn.call(integration, event);
886
+ };
887
+ return integration;
888
+ }
889
+ function registerAISdkTelemetry(integration) {
890
+ const g = globalThis;
891
+ if (!Array.isArray(g.AI_SDK_TELEMETRY_INTEGRATIONS)) {
892
+ g.AI_SDK_TELEMETRY_INTEGRATIONS = [];
893
+ }
894
+ const tagged = integration;
895
+ tagged[RAINDROP_EVE_INTEGRATION] = true;
896
+ g.AI_SDK_TELEMETRY_INTEGRATIONS = g.AI_SDK_TELEMETRY_INTEGRATIONS.filter(
897
+ (e) => !e[RAINDROP_EVE_INTEGRATION]
898
+ );
899
+ g.AI_SDK_TELEMETRY_INTEGRATIONS.push(tagged);
900
+ }
901
+ function envWriteKey() {
902
+ if (typeof process === "undefined") return void 0;
903
+ const v = process.env?.RAINDROP_WRITE_KEY;
904
+ return typeof v === "string" && v.length > 0 ? v : void 0;
905
+ }
906
+ function envProjectId() {
907
+ if (typeof process === "undefined") return void 0;
908
+ const v = process.env?.RAINDROP_PROJECT_ID;
909
+ return v && v.length > 0 ? v : void 0;
910
+ }
911
+ function envEndpoint() {
912
+ if (typeof process === "undefined") return void 0;
913
+ const v = process.env?.RAINDROP_ENDPOINT;
914
+ return typeof v === "string" && v.length > 0 ? v : void 0;
915
+ }
916
+ function envDebug() {
917
+ if (typeof process === "undefined") return false;
918
+ const v = process.env?.RAINDROP_AI_DEBUG;
919
+ return v === "1" || v === "true";
920
+ }
921
+ function isEveMetadataConfig(m) {
922
+ return typeof m === "object" && m !== null && typeof m["step.started"] === "function";
923
+ }
924
+ function eveTurnEventId(sessionId, turnId) {
925
+ return `eve:${sessionId}:${turnId}`;
926
+ }
927
+ function parentLineageMetadata(parent) {
928
+ const out = {
929
+ "raindrop.parent.sessionId": parent.sessionId,
930
+ "raindrop.parent.eventId": eveTurnEventId(parent.sessionId, parent.turn.id),
931
+ "raindrop.parent.turnId": parent.turn.id,
932
+ "raindrop.parent.turnSequence": String(parent.turn.sequence)
933
+ };
934
+ if (parent.rootSessionId !== void 0) {
935
+ out["raindrop.parent.rootSessionId"] = parent.rootSessionId;
936
+ }
937
+ return out;
938
+ }
939
+ function resolveCrossSandboxParentMetadata(input) {
940
+ const parent = parseEveSessionParent(input.session.parent);
941
+ if (parent === void 0) return {};
942
+ return parentLineageMetadata(parent);
943
+ }
944
+ var RAINDROP_PARENT_PREFIX = "raindrop.parent.";
945
+ function stripReservedParentMetadata(meta) {
946
+ if (meta == null) return {};
947
+ const out = {};
948
+ for (const [key, value] of Object.entries(meta)) {
949
+ if (!key.startsWith(RAINDROP_PARENT_PREFIX)) out[key] = value;
950
+ }
951
+ return out;
952
+ }
953
+ function resolveStaticMetadata(opts) {
954
+ const legacyFlat = isEveMetadataConfig(opts.metadata) ? void 0 : opts.metadata;
955
+ if (opts.staticMetadata === void 0 && legacyFlat === void 0) return void 0;
956
+ return stripReservedParentMetadata({ ...legacyFlat, ...opts.staticMetadata });
957
+ }
958
+ function buildEveStepStartedResolver(opts, staticMetadata) {
959
+ const metadataConfig = isEveMetadataConfig(opts.metadata) ? opts.metadata : void 0;
960
+ const eventsConfig = opts.events;
961
+ const eventsStepStarted = eventsConfig?.["step.started"];
962
+ const metadataStepStarted = metadataConfig?.["step.started"];
963
+ return (input) => {
964
+ const userMetadata = eventsStepStarted ? (
965
+ // Invoke with the authored config as the receiver so callbacks defined
966
+ // as object methods (`{ "step.started"() { return this... } }`) keep
967
+ // their `this` binding. The 0.53 hook returns `{ runtimeContext }`.
968
+ eventsStepStarted.call(eventsConfig, input)?.runtimeContext ?? {}
969
+ ) : metadataStepStarted ? metadataStepStarted.call(metadataConfig, input) : {};
970
+ return {
971
+ ...staticMetadata,
972
+ ...stripReservedParentMetadata(userMetadata),
973
+ ...resolveCrossSandboxParentMetadata(input)
974
+ };
975
+ };
976
+ }
977
+ function buildEveMetadataConfig(opts, staticMetadata) {
978
+ const resolve = buildEveStepStartedResolver(opts, staticMetadata);
979
+ return { "step.started": (input) => resolve(input) };
980
+ }
981
+ function buildEveEventsConfig(opts, staticMetadata) {
982
+ const resolve = buildEveStepStartedResolver(opts, staticMetadata);
983
+ return { "step.started": (input) => ({ runtimeContext: resolve(input) }) };
984
+ }
985
+ function defineRaindropInstrumentation(opts = {}) {
986
+ const debug = opts.debug === true || envDebug();
987
+ const writeKey = opts.writeKey ?? envWriteKey();
988
+ const endpoint = opts.endpoint ?? envEndpoint();
989
+ const projectId = opts.projectId ?? envProjectId();
990
+ const exporter = new RaindropEveSpanExporter({
991
+ writeKey,
992
+ endpoint,
993
+ projectId,
994
+ localWorkshopUrl: opts.localWorkshopUrl,
995
+ serviceName: opts.serviceName,
996
+ serviceVersion: opts.serviceVersion ?? libraryVersion,
997
+ sdkName: "eve",
998
+ debug,
999
+ maxTextFieldChars: opts.maxTextFieldChars
1000
+ });
1001
+ const localWorkshopUrl = opts.localWorkshopUrl === false ? false : opts.localWorkshopUrl;
1002
+ const raindrop = aiSdk.createRaindropAISDK({
1003
+ writeKey,
1004
+ endpoint,
1005
+ projectId,
1006
+ localWorkshopUrl,
1007
+ events: { debug },
1008
+ traces: { debug }
1009
+ });
1010
+ exporter.attachAuxShutdown(() => raindrop.shutdown());
1011
+ const prefix = "[raindrop-ai/eve]";
1012
+ const staticMetadata = resolveStaticMetadata(opts);
1013
+ const eveMetadata = buildEveMetadataConfig(opts, staticMetadata);
1014
+ const eveEvents = buildEveEventsConfig(opts, staticMetadata);
1015
+ return {
1016
+ functionId: opts.functionId,
1017
+ metadata: eveMetadata,
1018
+ events: eveEvents,
1019
+ recordInputs: opts.recordInputs,
1020
+ recordOutputs: opts.recordOutputs,
1021
+ exporter,
1022
+ raindrop,
1023
+ setup({ agentName }) {
1024
+ if (!exporter.hasDestinations()) {
1025
+ console.warn(
1026
+ `${prefix} no destinations configured \u2014 set RAINDROP_WRITE_KEY for hosted Raindrop, or run \`raindrop workshop\` for local mirroring.`
1027
+ );
1028
+ }
1029
+ const serviceName = opts.serviceName ?? agentName;
1030
+ exporter.setServiceName(serviceName);
1031
+ if (opts.registerOTel) {
1032
+ const g = globalThis;
1033
+ const already = g[RAINDROP_EVE_OTEL_REGISTERED];
1034
+ if (already === void 0) {
1035
+ opts.registerOTel({
1036
+ serviceName,
1037
+ traceExporter: exporter
1038
+ });
1039
+ g[RAINDROP_EVE_OTEL_REGISTERED] = { exporter };
1040
+ if (debug) {
1041
+ console.log(`${prefix} registered OTel for serviceName=${serviceName}`);
1042
+ }
1043
+ } else if (debug) {
1044
+ console.log(
1045
+ `${prefix} skipping duplicate registerOTel \u2014 already registered (hot reload). Restart the process to re-register.`
1046
+ );
1047
+ }
1048
+ } else {
1049
+ console.warn(
1050
+ `${prefix} no \`registerOTel\` passed \u2014 Eve's own OTel spans (workflow/step/fetch) will not be exported. Pass \`registerOTel\` from \`@vercel/otel\`.`
1051
+ );
1052
+ }
1053
+ const installed = installEveTurnSpanProcessor(api.trace);
1054
+ if (!installed && debug) {
1055
+ console.log(
1056
+ `${prefix} could not install ai.eve.turn SpanProcessor \u2014 cross-sandbox sub-agent detection will fall back to active-span attributes only. (Global tracer provider missing addSpanProcessor \u2014 register \`registerOTel\` from \`@vercel/otel\` before \`defineRaindropInstrumentation\`'s \`setup()\` runs.)`
1057
+ );
1058
+ }
1059
+ const integration = raindrop.createTelemetryIntegration({
1060
+ userId: opts.userId ?? agentName,
1061
+ eventName: opts.eventName
1062
+ });
1063
+ injectEveCallContext(integration, {
1064
+ agentName,
1065
+ rootFunctionId: opts.functionId ?? agentName,
1066
+ authoredMetadata: staticMetadata
1067
+ });
1068
+ const wrapped = debug ? wrapWithDebugLogs(integration, prefix) : integration;
1069
+ registerAISdkTelemetry(wrapped);
1070
+ if (debug) {
1071
+ console.log(`${prefix} registered AI SDK telemetry integration (events + traces).`);
1072
+ const g = globalThis;
1073
+ console.log(
1074
+ `${prefix} globalThis.AI_SDK_TELEMETRY_INTEGRATIONS length=${g.AI_SDK_TELEMETRY_INTEGRATIONS?.length ?? 0}`
1075
+ );
1076
+ }
1077
+ }
1078
+ };
1079
+ }
1080
+ var index_default = defineRaindropInstrumentation;
1081
+
1082
+ exports.RAINDROP_EVE_SDK_NAME = RAINDROP_EVE_SDK_NAME;
1083
+ exports.RAINDROP_EVE_SDK_VERSION = RAINDROP_EVE_SDK_VERSION;
1084
+ exports.RaindropEveSpanExporter = RaindropEveSpanExporter;
1085
+ exports._resetCanonicalTurnIds = _resetCanonicalTurnIds;
1086
+ exports.default = index_default;
1087
+ exports.defineRaindropInstrumentation = defineRaindropInstrumentation;
1088
+ //# sourceMappingURL=index.js.map
1089
+ //# sourceMappingURL=index.js.map