@raindrop-ai/deep-agents 0.1.0 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.mjs CHANGED
@@ -1,7 +1,521 @@
1
1
  // src/callback-handler.ts
2
2
  import { BaseCallbackHandler } from "@langchain/core/callbacks/base";
3
3
 
4
- // ../core/dist/chunk-267IXHO5.js
4
+ // ../core/dist/chunk-BYBMRLZM.js
5
+ var EVAL_CORRELATION_ID_ATTRIBUTE = "raindrop.eval_correlation_id";
6
+ var PROBE_SCOPE = { correlationId: "" };
7
+ var EvalScopeStorage = class {
8
+ constructor() {
9
+ this._als = null;
10
+ this._probed = false;
11
+ }
12
+ maybeAdoptAsyncLocalStorage() {
13
+ if (this._probed) return;
14
+ this._probed = true;
15
+ try {
16
+ const Ctor = globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
17
+ if (!Ctor) return;
18
+ const als = new Ctor();
19
+ als.run(PROBE_SCOPE, () => {
20
+ });
21
+ this._als = als;
22
+ } catch (e) {
23
+ this._als = null;
24
+ }
25
+ }
26
+ run(scope, callback) {
27
+ this.maybeAdoptAsyncLocalStorage();
28
+ if (this._als) return this._als.run(scope, callback);
29
+ const previous = this._syncScope;
30
+ this._syncScope = scope;
31
+ try {
32
+ return callback();
33
+ } finally {
34
+ this._syncScope = previous;
35
+ }
36
+ }
37
+ current() {
38
+ this.maybeAdoptAsyncLocalStorage();
39
+ if (this._als) return this._als.getStore();
40
+ return this._syncScope;
41
+ }
42
+ };
43
+ var EVAL_SCOPE_STORAGE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.evalScopeStorage");
44
+ function evalScopeStorage() {
45
+ const holder = globalThis;
46
+ let storage = holder[EVAL_SCOPE_STORAGE_KEY];
47
+ if (!storage) {
48
+ storage = new EvalScopeStorage();
49
+ holder[EVAL_SCOPE_STORAGE_KEY] = storage;
50
+ }
51
+ return storage;
52
+ }
53
+ function currentEvalScope() {
54
+ try {
55
+ return evalScopeStorage().current();
56
+ } catch (e) {
57
+ return void 0;
58
+ }
59
+ }
60
+ function evalScopeAttributes() {
61
+ const scope = currentEvalScope();
62
+ if (!scope) return {};
63
+ return { [EVAL_CORRELATION_ID_ATTRIBUTE]: scope.correlationId };
64
+ }
65
+
66
+ // ../core/dist/chunk-WJOR6M7H.js
67
+ var STATE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.replayTraceRoutingState");
68
+ function state() {
69
+ const holder = globalThis;
70
+ let current = holder[STATE_KEY];
71
+ if (!current) {
72
+ let storage = null;
73
+ try {
74
+ const Ctor = globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
75
+ if (Ctor) storage = new Ctor();
76
+ } catch (e) {
77
+ storage = null;
78
+ }
79
+ current = {
80
+ storage,
81
+ syncDestination: void 0,
82
+ spanDestinations: /* @__PURE__ */ new WeakMap()
83
+ };
84
+ holder[STATE_KEY] = current;
85
+ }
86
+ return current;
87
+ }
88
+ function currentReplayTraceDestination() {
89
+ var _a, _b;
90
+ const routing = state();
91
+ return (_b = (_a = routing.storage) == null ? void 0 : _a.getStore()) != null ? _b : routing.syncDestination;
92
+ }
93
+ function rememberReplayTraceDestination(span) {
94
+ const destination = currentReplayTraceDestination();
95
+ if (destination) state().spanDestinations.set(span, destination);
96
+ }
97
+ function copyReplayTraceDestination(source, target) {
98
+ const destination = state().spanDestinations.get(source);
99
+ if (destination) state().spanDestinations.set(target, destination);
100
+ }
101
+ function replayTraceDestinationFor(value) {
102
+ if (typeof value !== "object" && typeof value !== "function" || value === null) {
103
+ return void 0;
104
+ }
105
+ return state().spanDestinations.get(value);
106
+ }
107
+ function recordReplayExportedSpan(destination, spanId, traceId) {
108
+ var _a, _b;
109
+ if (!destination || !spanId || !traceId) return;
110
+ (_a = destination.exportedSpanIds) == null ? void 0 : _a.add(spanId);
111
+ (_b = destination.exportedTraceIds) == null ? void 0 : _b.add(traceId);
112
+ }
113
+ function replayTraceUrl(baseUrl) {
114
+ return `${baseUrl.replace(/\/+$/, "")}/v1/traces`;
115
+ }
116
+ function getAsyncLocalStorageCtor() {
117
+ return globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
118
+ }
119
+ var MAX_BINDING_STACK = 128;
120
+ var EMPTY_STACK = [];
121
+ var ContextStackStorage = class {
122
+ /** Emitted once when this runtime cannot support an ambient push. */
123
+ constructor(noAmbientBindWarning) {
124
+ this.noAmbientBindWarning = noAmbientBindWarning;
125
+ this._als = null;
126
+ this._enterWithUsable = false;
127
+ this._syncStack = EMPTY_STACK;
128
+ this._adoptionChecked = false;
129
+ this._warnedNoAmbientBind = false;
130
+ }
131
+ maybeAdoptAsyncLocalStorage() {
132
+ if (this._adoptionChecked) return;
133
+ this._adoptionChecked = true;
134
+ const Ctor = getAsyncLocalStorageCtor();
135
+ if (!Ctor) return;
136
+ const als = new Ctor();
137
+ try {
138
+ als.run(EMPTY_STACK, () => {
139
+ });
140
+ } catch (e) {
141
+ return;
142
+ }
143
+ this._als = als;
144
+ if (typeof als.enterWith === "function") {
145
+ try {
146
+ als.enterWith(EMPTY_STACK);
147
+ this._enterWithUsable = true;
148
+ } catch (e) {
149
+ this._enterWithUsable = false;
150
+ }
151
+ }
152
+ }
153
+ getStack() {
154
+ var _a;
155
+ this.maybeAdoptAsyncLocalStorage();
156
+ if (this._als) return (_a = this._als.getStore()) != null ? _a : this._syncStack;
157
+ return this._syncStack;
158
+ }
159
+ /**
160
+ * Persist an ambient stack mutation. Returns false when an ALS is adopted but
161
+ * `enterWith` is unusable (workerd): callers must NOT fall back to the
162
+ * process-shared sync stack, since concurrent isolates would cross-stamp.
163
+ */
164
+ setAmbientStack(stack) {
165
+ if (this._als) {
166
+ if (!this._enterWithUsable) return false;
167
+ this._als.enterWith(stack);
168
+ return true;
169
+ }
170
+ this._syncStack = stack;
171
+ return true;
172
+ }
173
+ push(binding) {
174
+ this.maybeAdoptAsyncLocalStorage();
175
+ if (this._als && !this._enterWithUsable) {
176
+ this.warnNoAmbientBindOnce();
177
+ return;
178
+ }
179
+ let stack = this.getStack();
180
+ if (stack.length >= MAX_BINDING_STACK) {
181
+ stack = stack.filter((b) => b.isLive());
182
+ if (stack.length >= MAX_BINDING_STACK) {
183
+ stack = stack.slice(stack.length - (MAX_BINDING_STACK - 1));
184
+ }
185
+ }
186
+ this.setAmbientStack([...stack, binding]);
187
+ }
188
+ remove(binding) {
189
+ binding.markDead();
190
+ const stack = this.getStack();
191
+ const pruned = stack.filter((b) => b !== binding && b.isLive());
192
+ if (pruned.length !== stack.length) {
193
+ this.setAmbientStack(pruned);
194
+ }
195
+ }
196
+ runWith(binding, callback) {
197
+ this.maybeAdoptAsyncLocalStorage();
198
+ if (this._als) {
199
+ return this._als.run([...this.getStack(), binding], callback);
200
+ }
201
+ const previous = this._syncStack;
202
+ this._syncStack = [...previous, binding];
203
+ try {
204
+ return callback();
205
+ } finally {
206
+ this._syncStack = previous;
207
+ }
208
+ }
209
+ current() {
210
+ const stack = this.getStack();
211
+ if (stack.length === 0) return void 0;
212
+ const top = stack[stack.length - 1];
213
+ if (top.isLive()) return top;
214
+ const pruned = stack.filter((b) => b.isLive());
215
+ this.setAmbientStack(pruned);
216
+ return pruned.length > 0 ? pruned[pruned.length - 1] : void 0;
217
+ }
218
+ warnNoAmbientBindOnce() {
219
+ if (this._warnedNoAmbientBind) return;
220
+ this._warnedNoAmbientBind = true;
221
+ console.warn(this.noAmbientBindWarning);
222
+ }
223
+ };
224
+ var NO_AMBIENT_ROUTING_BIND_WARNING = "[raindrop] This runtime's AsyncLocalStorage does not implement enterWith (e.g. Cloudflare Workers), so begin()/finish() cannot scope auto-instrumented spans to a project without cross-contaminating concurrent requests. Manual events and explicit span routing are unaffected; use asCurrent()/withSpan (run-based) to route auto-instrumented spans on this runtime.";
225
+ var ROUTING_STORAGE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.routingContextStorage");
226
+ function routingStorage() {
227
+ const holder = globalThis;
228
+ let storage = holder[ROUTING_STORAGE_KEY];
229
+ if (!storage) {
230
+ storage = new ContextStackStorage(NO_AMBIENT_ROUTING_BIND_WARNING);
231
+ holder[ROUTING_STORAGE_KEY] = storage;
232
+ }
233
+ return storage;
234
+ }
235
+ function currentRoutingBinding() {
236
+ const bound = routingStorage().current();
237
+ if (!bound) return void 0;
238
+ return {
239
+ projectId: bound.projectId,
240
+ authHint: bound.authHint,
241
+ ...bound.appGit ? { appGit: bound.appGit } : {},
242
+ ...bound.appGitSource ? { appGitSource: bound.appGitSource } : {}
243
+ };
244
+ }
245
+ var APP_COMMIT_SHA = "raindrop.app.commit_sha";
246
+ var APP_COMMIT_DIRTY = "raindrop.app.commit_dirty";
247
+ var APP_BRANCH = "raindrop.app.branch";
248
+ var APP_GIT_KEYS = [APP_COMMIT_SHA, APP_COMMIT_DIRTY, APP_BRANCH];
249
+ var own = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
250
+ function appGitExplicitKeys(properties) {
251
+ const keys = /* @__PURE__ */ new Set();
252
+ if (!properties) return keys;
253
+ for (const key of APP_GIT_KEYS) {
254
+ if (own(properties, key)) keys.add(key);
255
+ }
256
+ return keys;
257
+ }
258
+ function mergeAppGitSnapshot(base, properties, explicitKeys = /* @__PURE__ */ new Set()) {
259
+ try {
260
+ const result = { ...base };
261
+ if (properties && own(properties, APP_COMMIT_SHA) && properties[APP_COMMIT_SHA] !== result[APP_COMMIT_SHA]) {
262
+ if (!explicitKeys.has(APP_COMMIT_DIRTY) && !own(properties, APP_COMMIT_DIRTY)) {
263
+ delete result[APP_COMMIT_DIRTY];
264
+ }
265
+ if (!explicitKeys.has(APP_BRANCH) && !own(properties, APP_BRANCH)) {
266
+ delete result[APP_BRANCH];
267
+ }
268
+ }
269
+ for (const key of APP_GIT_KEYS) {
270
+ if (properties && own(properties, key)) result[key] = properties[key];
271
+ }
272
+ return Object.freeze(result);
273
+ } catch (e) {
274
+ return Object.freeze({});
275
+ }
276
+ }
277
+ function validAppCommitSha(value) {
278
+ if (typeof value !== "string" || value.length > 128) return void 0;
279
+ const cleaned = value.trim();
280
+ return /^(?:[a-fA-F0-9]{40}|[a-fA-F0-9]{64})$/.test(cleaned) ? cleaned.toLowerCase() : void 0;
281
+ }
282
+ function shortString(value) {
283
+ if (typeof value !== "string" || value.length > 1024) return void 0;
284
+ const cleaned = value.trim();
285
+ return cleaned.length > 0 ? cleaned : void 0;
286
+ }
287
+ function flag(value) {
288
+ if (value === true || value === "true" || value === "1") return true;
289
+ if (value === false || value === "false" || value === "0") return false;
290
+ return void 0;
291
+ }
292
+ function environment() {
293
+ try {
294
+ return typeof process === "undefined" ? {} : process.env;
295
+ } catch (e) {
296
+ return {};
297
+ }
298
+ }
299
+ var DEPLOYMENTS = [
300
+ ["VERCEL", "VERCEL_GIT_COMMIT_SHA", "VERCEL_GIT_COMMIT_REF"],
301
+ ["NETLIFY", "COMMIT_REF", "BRANCH"],
302
+ ["RAILWAY_ENVIRONMENT_NAME", "RAILWAY_GIT_COMMIT_SHA", "RAILWAY_GIT_BRANCH"],
303
+ ["RAILWAY_ENVIRONMENT", "RAILWAY_GIT_COMMIT_SHA", "RAILWAY_GIT_BRANCH"],
304
+ ["RENDER", "RENDER_GIT_COMMIT", "RENDER_GIT_BRANCH"],
305
+ ["DYNO", "HEROKU_BUILD_COMMIT", ""],
306
+ ["DYNO", "HEROKU_SLUG_COMMIT", ""],
307
+ ["AWS_APP_ID", "AWS_COMMIT_ID", "AWS_BRANCH"],
308
+ ["WORKERS_CI", "WORKERS_CI_COMMIT_SHA", "WORKERS_CI_BRANCH"]
309
+ ];
310
+ var CI_SOURCES = [
311
+ ["GITHUB_ACTIONS", "GITHUB_SHA", "GITHUB_REF_NAME"],
312
+ ["GITLAB_CI", "CI_COMMIT_SHA", "CI_COMMIT_REF_NAME"],
313
+ ["CIRCLECI", "CIRCLE_SHA1", "CIRCLE_BRANCH"]
314
+ ];
315
+ function detectedSource(env, table, detectBranch) {
316
+ for (const row of table) {
317
+ const [marker, shaKey, branchKey] = row;
318
+ if (!marker || !shaKey || !shortString(env[marker]) || flag(env[marker]) === false) continue;
319
+ const commitSha = validAppCommitSha(env[shaKey]);
320
+ if (commitSha)
321
+ return {
322
+ commitSha,
323
+ ...detectBranch && branchKey ? { branch: shortString(env[branchKey]) } : {}
324
+ };
325
+ }
326
+ return {};
327
+ }
328
+ var AppGitContextImpl = class {
329
+ constructor(options, runtime = {}) {
330
+ this.defaults = {};
331
+ this.explicit = {};
332
+ this.explicitKeys = /* @__PURE__ */ new Set();
333
+ this.disposed = false;
334
+ this.operations = /* @__PURE__ */ new Map();
335
+ this.operationOverflow = false;
336
+ this.detectBranch = false;
337
+ this.disabled = false;
338
+ var _a, _b, _c, _d, _e, _f;
339
+ try {
340
+ if (options === false) {
341
+ this.disabled = true;
342
+ return;
343
+ }
344
+ const opts = options != null ? options : {};
345
+ const env = (_a = runtime.env) != null ? _a : environment();
346
+ const detectBranch = (_c = (_b = flag(opts.detectBranch)) != null ? _b : flag(env.RAINDROP_GIT_DETECT_BRANCH)) != null ? _c : false;
347
+ this.detectBranch = detectBranch;
348
+ const collectBranch = detectBranch || runtime.captureLegacyReplayBranch === true;
349
+ const autoDetect = runtime.allowDiscovery === false ? false : (_e = (_d = flag(opts.autoDetect)) != null ? _d : flag(env.RAINDROP_GIT_AUTO_DETECT)) != null ? _e : true;
350
+ const configuredSha = opts.commitSha;
351
+ const explicitSha = configuredSha === void 0 ? env.RAINDROP_COMMIT_SHA : configuredSha;
352
+ if (explicitSha === null) this.explicit[APP_COMMIT_SHA] = null;
353
+ else if (typeof explicitSha === "string" && validAppCommitSha(explicitSha))
354
+ this.explicit[APP_COMMIT_SHA] = explicitSha;
355
+ const configuredDirty = opts.commitDirty;
356
+ const explicitDirty = configuredDirty === void 0 ? flag(env.RAINDROP_COMMIT_DIRTY) : configuredDirty;
357
+ if (explicitDirty === null || typeof explicitDirty === "boolean")
358
+ this.explicit[APP_COMMIT_DIRTY] = explicitDirty;
359
+ const configuredBranch = opts.branch;
360
+ const explicitBranch = configuredBranch === void 0 ? env.RAINDROP_BRANCH : configuredBranch;
361
+ if (explicitBranch === null) this.explicit[APP_BRANCH] = null;
362
+ else if (typeof explicitBranch === "string" && explicitBranch.length <= 1024)
363
+ this.explicit[APP_BRANCH] = explicitBranch;
364
+ this.explicitKeys = appGitExplicitKeys(this.explicit);
365
+ this.defaults = { ...this.explicit };
366
+ if (!autoDetect || explicitSha !== void 0) return;
367
+ const sourceDirectory = (_f = shortString(opts.sourceDirectory)) != null ? _f : shortString(env.RAINDROP_GIT_SOURCE_DIRECTORY);
368
+ if (runtime.allowLocalGit === false && !sourceDirectory) return;
369
+ const deploy = sourceDirectory ? {} : detectedSource(env, DEPLOYMENTS, collectBranch);
370
+ if (deploy.commitSha) {
371
+ this.accept(deploy);
372
+ return;
373
+ }
374
+ const fallback = sourceDirectory ? {} : detectedSource(env, CI_SOURCES, collectBranch);
375
+ if (runtime.resolveLocal && (runtime.allowLocalGit !== false || sourceDirectory)) {
376
+ this.cancel = runtime.resolveLocal(sourceDirectory, collectBranch, (result) => {
377
+ try {
378
+ if (!this.disposed) this.accept(result.commitSha ? result : fallback);
379
+ } catch (e) {
380
+ }
381
+ });
382
+ } else this.accept(fallback);
383
+ } catch (e) {
384
+ }
385
+ }
386
+ accept(result) {
387
+ const sha = validAppCommitSha(result.commitSha);
388
+ if (!sha) return;
389
+ this.replayBranch = shortString(result.branch);
390
+ this.defaults = {
391
+ [APP_COMMIT_SHA]: sha,
392
+ ...typeof result.commitDirty === "boolean" ? { [APP_COMMIT_DIRTY]: result.commitDirty } : {},
393
+ ...this.detectBranch && this.replayBranch ? { [APP_BRANCH]: this.replayBranch } : {},
394
+ ...this.explicit
395
+ };
396
+ }
397
+ snapshot(properties) {
398
+ var _a;
399
+ try {
400
+ const binding = currentRoutingBinding();
401
+ const base = this.disabled && (binding == null ? void 0 : binding.appGitSource) !== "replay-override" ? {} : (_a = binding == null ? void 0 : binding.appGit) != null ? _a : this.defaults;
402
+ return this.mergeSnapshot(base, properties);
403
+ } catch (e) {
404
+ return Object.freeze({});
405
+ }
406
+ }
407
+ /** Safe defaults when no operation/span start was observed; never infer identity. */
408
+ snapshotExplicit(properties, eventId) {
409
+ try {
410
+ const base = { ...this.explicit };
411
+ const operation = eventId ? this.operations.get(eventId) : void 0;
412
+ if (operation) {
413
+ for (const key of operation.explicitKeys) base[key] = operation.snapshot[key];
414
+ }
415
+ return this.mergeSnapshot(base, properties, new Set(Object.keys(base)));
416
+ } catch (e) {
417
+ return mergeAppGitSnapshot({}, properties);
418
+ }
419
+ }
420
+ /** Existing replay branch reporting stays separate from opt-in event properties. */
421
+ snapshotForReplay() {
422
+ const snapshot = this.snapshot();
423
+ if (this.replayBranch && !own(snapshot, APP_BRANCH) && snapshot[APP_COMMIT_SHA] === this.defaults[APP_COMMIT_SHA]) {
424
+ return Object.freeze({ ...snapshot, [APP_BRANCH]: this.replayBranch });
425
+ }
426
+ return snapshot;
427
+ }
428
+ /** Merge a frozen span snapshot without losing client-authored provenance. */
429
+ mergeSnapshot(base, properties, explicitKeys = this.explicitKeys) {
430
+ return mergeAppGitSnapshot(base, properties, /* @__PURE__ */ new Set([...this.explicitKeys, ...explicitKeys]));
431
+ }
432
+ /** Shippers belonging to one client share this bounded operation registry. */
433
+ forOperation(eventId, properties, owner) {
434
+ if (!eventId) return this.snapshot(properties);
435
+ let operation = this.operations.get(eventId);
436
+ if (!operation) {
437
+ if (this.operations.size >= 1e4) this.operationOverflow = true;
438
+ if (this.operationOverflow) return this.mergeSnapshot({}, properties);
439
+ operation = {
440
+ snapshot: this.snapshot(properties),
441
+ owners: /* @__PURE__ */ new Set(),
442
+ unowned: owner === void 0,
443
+ explicitKeys: appGitExplicitKeys(properties)
444
+ };
445
+ this.operations.set(eventId, operation);
446
+ } else if (properties && APP_GIT_KEYS.some((key) => own(properties, key))) {
447
+ const explicitKeys = /* @__PURE__ */ new Set([...this.explicitKeys, ...operation.explicitKeys]);
448
+ operation.snapshot = this.mergeSnapshot(operation.snapshot, properties, explicitKeys);
449
+ for (const key of appGitExplicitKeys(properties)) operation.explicitKeys.add(key);
450
+ }
451
+ if (!owner) operation.unowned = true;
452
+ if (owner) operation.owners.add(owner);
453
+ return operation.snapshot;
454
+ }
455
+ releaseOperation(eventId, owner) {
456
+ const operation = this.operations.get(eventId);
457
+ if (!operation) return;
458
+ operation.owners.delete(owner);
459
+ if (operation.owners.size === 0 && !operation.unowned) this.operations.delete(eventId);
460
+ }
461
+ finishOperation(eventId) {
462
+ this.operations.delete(eventId);
463
+ }
464
+ dispose() {
465
+ var _a;
466
+ this.disposed = true;
467
+ try {
468
+ (_a = this.cancel) == null ? void 0 : _a.call(this);
469
+ } catch (e) {
470
+ }
471
+ }
472
+ };
473
+ var AppGitContext = AppGitContextImpl;
474
+ function createAppGitContext(options, runtime = {}) {
475
+ return new AppGitContext(options, runtime);
476
+ }
477
+ function withAppGitProperties(properties, snapshot) {
478
+ try {
479
+ const merged = { ...properties };
480
+ for (const key of APP_GIT_KEYS)
481
+ if (!own(merged, key) && own(snapshot, key)) merged[key] = snapshot[key];
482
+ return merged;
483
+ } catch (e) {
484
+ return properties != null ? properties : {};
485
+ }
486
+ }
487
+ function withAppGitAttributes(attributes, snapshot) {
488
+ try {
489
+ const present = new Set(attributes.flatMap((attr) => attr ? [attr.key] : []));
490
+ const added = [];
491
+ for (const key of APP_GIT_KEYS) {
492
+ if (present.has(key) || present.has(`ai.telemetry.metadata.${key}`) || present.has(`traceloop.association.properties.${key}`))
493
+ continue;
494
+ const value = snapshot[key];
495
+ if (typeof value === "string") added.push({ key, value: { stringValue: value } });
496
+ else if (typeof value === "boolean") added.push({ key, value: { boolValue: value } });
497
+ }
498
+ return added.length ? [...attributes, ...added] : attributes;
499
+ } catch (e) {
500
+ return attributes;
501
+ }
502
+ }
503
+ function appGitPropertiesFromAttributes(attributes) {
504
+ var _a, _b, _c;
505
+ const properties = {};
506
+ try {
507
+ for (const attr of attributes) {
508
+ if (!attr) continue;
509
+ for (const key of APP_GIT_KEYS) {
510
+ if (attr.key === key || attr.key === `ai.telemetry.metadata.${key}` || attr.key === `traceloop.association.properties.${key}`) {
511
+ properties[key] = (_c = (_b = (_a = attr.value.stringValue) != null ? _a : attr.value.boolValue) != null ? _b : attr.value.intValue) != null ? _c : null;
512
+ }
513
+ }
514
+ }
515
+ } catch (e) {
516
+ }
517
+ return properties;
518
+ }
5
519
  function getCrypto() {
6
520
  const c = globalThis.crypto;
7
521
  return c;
@@ -56,6 +570,39 @@ function base64Encode(bytes) {
56
570
  }
57
571
  return out;
58
572
  }
573
+ function base64ToHex(value) {
574
+ if (!value) return "";
575
+ const maybeBuffer = globalThis.Buffer;
576
+ if (maybeBuffer) {
577
+ return maybeBuffer.from(value, "base64").toString("hex");
578
+ }
579
+ const atobFn = globalThis.atob;
580
+ if (typeof atobFn !== "function") return "";
581
+ try {
582
+ const binary = atobFn(value);
583
+ let hex = "";
584
+ for (let i = 0; i < binary.length; i++) {
585
+ hex += (binary.charCodeAt(i) & 255).toString(16).padStart(2, "0");
586
+ }
587
+ return hex;
588
+ } catch (e) {
589
+ return "";
590
+ }
591
+ }
592
+ var HANDOFF_ATTRIBUTE_SUFFIXES = {
593
+ mode: "raindrop.handoff.mode",
594
+ childEventId: "raindrop.handoff.childEventId",
595
+ parentEventId: "raindrop.handoff.parentEventId",
596
+ parentSpanId: "raindrop.handoff.parentSpanId",
597
+ name: "raindrop.handoff.name",
598
+ terminal: "raindrop.handoff.terminal",
599
+ agentRole: "raindrop.agent.role"
600
+ };
601
+ var HANDOFF_TERMINAL_PROPERTY_KEY = HANDOFF_ATTRIBUTE_SUFFIXES.terminal;
602
+ var TRACEPARENT_HEADER = "traceparent";
603
+ var BAGGAGE_HEADER = "baggage";
604
+ var HANDOFF_HEADER = "x-raindrop-handoff";
605
+ var UNRESOLVED_CARRIER_WARNING = `[raindrop] resume: headers were supplied but no hand-off carrier was found on them (searched ${HANDOFF_HEADER}, ${TRACEPARENT_HEADER}, ${BAGGAGE_HEADER}). This run reports as an UNLINKED event, and the launcher that dispatched it will stay on "queued" forever because nothing ever references its child. Passing headers means a parent handed off, so no carrier on them is almost certainly a defect: a gateway or proxy stripping ${HANDOFF_HEADER}, a middleware overwriting ${BAGGAGE_HEADER}, a request forwarded without its headers, or a hand-built carrier whose field names do not match. Send every header the launcher's dispatch returned. Logged once per process; pass no headers for a directly-invoked sub-agent to silence it.`;
59
606
  function runWithTracingSuppressed(fn) {
60
607
  const hook = globalThis.RAINDROP_SUPPRESS_TRACING;
61
608
  if (typeof hook !== "function") return fn();
@@ -73,7 +620,7 @@ function runWithTracingSuppressed(fn) {
73
620
  var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
74
621
  var MAX_RETRY_DELAY_MS = 3e4;
75
622
  function wait(ms) {
76
- return new Promise((resolve) => setTimeout(resolve, ms));
623
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
77
624
  }
78
625
  function formatEndpoint(endpoint) {
79
626
  if (!endpoint) return void 0;
@@ -110,9 +657,9 @@ async function raceWithTimeout(promise, timeoutMs) {
110
657
  () => true,
111
658
  () => true
112
659
  ),
113
- new Promise((resolve) => {
660
+ new Promise((resolve2) => {
114
661
  var _a;
115
- timer = setTimeout(() => resolve(false), Math.max(0, timeoutMs));
662
+ timer = setTimeout(() => resolve2(false), Math.max(0, timeoutMs));
116
663
  (_a = timer.unref) == null ? void 0 : _a.call(timer);
117
664
  })
118
665
  ]);
@@ -183,6 +730,7 @@ async function postJson(url, body, headers, opts) {
183
730
  const resp = await runWithTracingSuppressed(
184
731
  () => fetch(url, {
185
732
  method: "POST",
733
+ redirect: headers["X-Raindrop-Replay-Id"] !== void 0 ? "error" : "follow",
186
734
  headers: {
187
735
  "Content-Type": "application/json",
188
736
  ...headers
@@ -346,26 +894,29 @@ function resolveLocalDebuggerBaseUrl(baseUrl) {
346
894
  if (shouldAutoEnableLocalWorkshop()) return DEFAULT_LOCAL_WORKSHOP_URL;
347
895
  return null;
348
896
  }
897
+ var LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS = 2e3;
349
898
  function mirrorTraceExportToLocalDebugger(body, options = {}) {
350
899
  var _a;
351
900
  const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
352
- if (!baseUrl) return;
353
- void postJson(`${baseUrl}traces`, body, {}, {
901
+ if (!baseUrl) return Promise.resolve();
902
+ return postJson(`${baseUrl}traces`, body, {}, {
354
903
  maxAttempts: 1,
355
904
  debug: (_a = options.debug) != null ? _a : false,
356
- sdkName: options.sdkName
905
+ sdkName: options.sdkName,
906
+ timeoutMs: LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS
357
907
  }).catch(() => {
358
908
  });
359
909
  }
360
910
  function mirrorPartialEventToLocalDebugger(event, options = {}) {
361
911
  var _a;
362
912
  const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
363
- if (!baseUrl) return;
913
+ if (!baseUrl) return Promise.resolve();
364
914
  const headers = options.writeKey ? { Authorization: `Bearer ${options.writeKey}` } : {};
365
- void postJson(`${baseUrl}events/track_partial`, event, headers, {
915
+ return postJson(`${baseUrl}events/track_partial`, event, headers, {
366
916
  maxAttempts: 1,
367
917
  debug: (_a = options.debug) != null ? _a : false,
368
- sdkName: options.sdkName
918
+ sdkName: options.sdkName,
919
+ timeoutMs: LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS
369
920
  }).catch(() => {
370
921
  });
371
922
  }
@@ -390,38 +941,81 @@ function projectIdHeaders(projectId) {
390
941
  }
391
942
  var SHUTDOWN_DEADLINE_MS = 1e4;
392
943
  var POST_SHUTDOWN_TIMEOUT_MS = 5e3;
944
+ function appGitOwnerId(prefix) {
945
+ try {
946
+ return `${prefix}:${randomUUID()}`;
947
+ } catch (e) {
948
+ return `${prefix}:${Date.now().toString(36)}:${Math.random().toString(36).slice(2)}`;
949
+ }
950
+ }
393
951
  function mergePatches(target, source) {
394
- var _a, _b, _c, _d, _e, _f;
952
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
395
953
  const out = { ...target, ...source };
396
954
  if (target.properties || source.properties) {
397
955
  out.properties = { ...(_a = target.properties) != null ? _a : {}, ...(_b = source.properties) != null ? _b : {} };
398
956
  }
957
+ if (target.usage || source.usage) {
958
+ out.usage = { ...(_c = target.usage) != null ? _c : {} };
959
+ if (((_d = source.usage) == null ? void 0 : _d.promptTokens) !== void 0) {
960
+ out.usage.promptTokens = source.usage.promptTokens;
961
+ }
962
+ if (((_e = source.usage) == null ? void 0 : _e.completionTokens) !== void 0) {
963
+ out.usage.completionTokens = source.usage.completionTokens;
964
+ }
965
+ }
966
+ if (source.error === void 0) {
967
+ out.error = target.error;
968
+ }
399
969
  if (target.featureFlags || source.featureFlags) {
400
- out.featureFlags = { ...(_c = target.featureFlags) != null ? _c : {}, ...(_d = source.featureFlags) != null ? _d : {} };
970
+ out.featureFlags = { ...(_f = target.featureFlags) != null ? _f : {}, ...(_g = source.featureFlags) != null ? _g : {} };
401
971
  }
402
972
  if (target.attachments || source.attachments) {
403
- out.attachments = [...(_e = target.attachments) != null ? _e : [], ...(_f = source.attachments) != null ? _f : []];
973
+ out.attachments = [...(_h = target.attachments) != null ? _h : [], ...(_i = source.attachments) != null ? _i : []];
404
974
  }
405
975
  return out;
406
976
  }
977
+ function isErrorLike(value) {
978
+ return value !== null && typeof value === "object";
979
+ }
980
+ function eventTelemetryProperties(patch) {
981
+ var _a, _b;
982
+ const properties = {};
983
+ if (((_a = patch.usage) == null ? void 0 : _a.promptTokens) !== void 0 && Number.isFinite(patch.usage.promptTokens)) {
984
+ properties["ai.usage.prompt_tokens"] = patch.usage.promptTokens;
985
+ }
986
+ if (((_b = patch.usage) == null ? void 0 : _b.completionTokens) !== void 0 && Number.isFinite(patch.usage.completionTokens)) {
987
+ properties["ai.usage.completion_tokens"] = patch.usage.completionTokens;
988
+ }
989
+ if (patch.error !== void 0 && patch.error !== null) {
990
+ const constructorName = patch.error instanceof Error && patch.error.constructor !== Error ? patch.error.constructor.name : void 0;
991
+ const errorType = patch.error instanceof Error ? patch.error.name && patch.error.name !== "Error" ? patch.error.name : constructorName || patch.error.name || "Error" : isErrorLike(patch.error) && typeof patch.error.name === "string" && patch.error.name.length > 0 ? patch.error.name : "Error";
992
+ const errorMessage = patch.error instanceof Error ? patch.error.message : isErrorLike(patch.error) && typeof patch.error.message === "string" ? patch.error.message : String(patch.error);
993
+ properties["error.type"] = errorType;
994
+ properties["error.message"] = errorMessage;
995
+ }
996
+ return properties;
997
+ }
407
998
  var EventShipper = class {
408
999
  constructor(opts) {
1000
+ this.appGitOwner = appGitOwnerId("event");
409
1001
  this.buffers = /* @__PURE__ */ new Map();
410
1002
  this.sticky = /* @__PURE__ */ new Map();
411
1003
  this.timers = /* @__PURE__ */ new Map();
412
1004
  this.inFlight = /* @__PURE__ */ new Set();
413
1005
  this.hasShutdown = false;
414
- var _a, _b, _c, _d, _e, _f, _g, _h;
415
- this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
416
- this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
1006
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1007
+ this.appGitContext = (_a = opts.appGitContext) != null ? _a : createAppGitContext(opts.appGit);
1008
+ this.ownsAppGitContext = opts.appGitContext === void 0;
1009
+ this.writeKey = (_b = opts.writeKey) == null ? void 0 : _b.trim();
1010
+ this.baseUrl = (_c = formatEndpoint(opts.endpoint)) != null ? _c : "https://api.raindrop.ai/v1/";
417
1011
  this.enabled = opts.enabled !== false;
418
1012
  this.debug = opts.debug;
419
- this.partialFlushMs = (_c = opts.partialFlushMs) != null ? _c : 1e3;
420
- this.sdkName = (_d = opts.sdkName) != null ? _d : "core";
1013
+ this.partialFlushMs = (_d = opts.partialFlushMs) != null ? _d : 1e3;
1014
+ this.sdkName = (_e = opts.sdkName) != null ? _e : "core";
421
1015
  this.prefix = `[raindrop-ai/${this.sdkName}]`;
422
- this.defaultEventName = (_e = opts.defaultEventName) != null ? _e : "ai_generation";
1016
+ this.defaultEventName = (_f = opts.defaultEventName) != null ? _f : "ai_generation";
423
1017
  this.maxTextFieldCharsOpt = opts.maxTextFieldChars;
424
- this.localDebuggerUrl = (_f = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _f : void 0;
1018
+ this.localDebuggerUrl = (_g = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _g : void 0;
425
1019
  if (this.debug && this.localDebuggerUrl) {
426
1020
  console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
427
1021
  }
@@ -432,8 +1026,8 @@ var EventShipper = class {
432
1026
  const isNode = typeof process !== "undefined" && typeof process.version === "string";
433
1027
  this.context = {
434
1028
  library: {
435
- name: (_g = opts.libraryName) != null ? _g : "@raindrop-ai/core",
436
- version: (_h = opts.libraryVersion) != null ? _h : "0.0.0"
1029
+ name: (_h = opts.libraryName) != null ? _h : "@raindrop-ai/core",
1030
+ version: (_i = opts.libraryVersion) != null ? _i : "0.0.0"
437
1031
  },
438
1032
  metadata: {
439
1033
  jsRuntime: isNode ? "node" : "web",
@@ -441,6 +1035,9 @@ var EventShipper = class {
441
1035
  }
442
1036
  };
443
1037
  }
1038
+ ownAppGitContextForShutdown() {
1039
+ this.ownsAppGitContext = true;
1040
+ }
444
1041
  isDebugEnabled() {
445
1042
  return this.debug;
446
1043
  }
@@ -489,6 +1086,15 @@ var EventShipper = class {
489
1086
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
490
1087
  if (!this.enabled) return;
491
1088
  if (!eventId || !eventId.trim()) return;
1089
+ const capturedSticky = this.sticky.get(eventId);
1090
+ const eventAlreadyKnown = capturedSticky !== void 0 || this.buffers.has(eventId);
1091
+ const destination = currentReplayTraceDestination();
1092
+ const cloudReplay = destination !== void 0 && destination.kind !== "workshop";
1093
+ if ((capturedSticky == null ? void 0 : capturedSticky.replayOnly) === true || !eventAlreadyKnown && cloudReplay) {
1094
+ if (patch.isPending === false) this.sticky.delete(eventId);
1095
+ else this.sticky.set(eventId, { ...capturedSticky, replayOnly: true });
1096
+ return;
1097
+ }
492
1098
  const maxChars = resolveMaxTextFieldChars(this.maxTextFieldCharsOpt);
493
1099
  if (typeof patch.input === "string" && patch.input.length > maxChars) {
494
1100
  patch = { ...patch, input: capText(patch.input, maxChars) };
@@ -510,6 +1116,13 @@ var EventShipper = class {
510
1116
  }
511
1117
  const sticky = (_c = this.sticky.get(eventId)) != null ? _c : {};
512
1118
  const existing = (_d = this.buffers.get(eventId)) != null ? _d : {};
1119
+ patch = {
1120
+ ...patch,
1121
+ properties: withAppGitProperties(
1122
+ patch.properties,
1123
+ this.appGitContext.forOperation(eventId, patch.properties, this.appGitOwner)
1124
+ )
1125
+ };
513
1126
  const merged = mergePatches(existing, patch);
514
1127
  merged.isPending = (_g = (_f = (_e = patch.isPending) != null ? _e : existing.isPending) != null ? _f : sticky.isPending) != null ? _g : true;
515
1128
  this.buffers.set(eventId, merged);
@@ -523,6 +1136,8 @@ var EventShipper = class {
523
1136
  if (t) clearTimeout(t);
524
1137
  if (merged.isPending === false) {
525
1138
  await this.flushOne(eventId);
1139
+ if (this.appGitContext.releaseOperation) this.appGitContext.releaseOperation(eventId, this.appGitOwner);
1140
+ else this.appGitContext.finishOperation(eventId);
526
1141
  return;
527
1142
  }
528
1143
  const timeout = setTimeout(() => {
@@ -547,15 +1162,21 @@ var EventShipper = class {
547
1162
  try {
548
1163
  for (const t of this.timers.values()) clearTimeout(t);
549
1164
  this.timers.clear();
1165
+ for (const [eventId, sticky] of this.sticky) {
1166
+ if (sticky.replayOnly) this.sticky.delete(eventId);
1167
+ }
550
1168
  const settled = await raceWithTimeout(this.flush(), SHUTDOWN_DEADLINE_MS);
551
1169
  if (!settled) this.warnShutdownDrop("in-flight request(s) at shutdown");
552
1170
  } finally {
553
1171
  this.shutdownDeadlineAt = void 0;
1172
+ if (this.ownsAppGitContext) this.appGitContext.dispose();
554
1173
  }
555
1174
  }
556
1175
  async trackSignal(signal) {
557
1176
  var _a, _b;
558
1177
  if (!this.enabled) return;
1178
+ const destination = currentReplayTraceDestination();
1179
+ if (destination && destination.kind !== "workshop") return;
559
1180
  const body = [
560
1181
  {
561
1182
  event_id: signal.eventId,
@@ -590,6 +1211,8 @@ var EventShipper = class {
590
1211
  }
591
1212
  async identify(users) {
592
1213
  if (!this.enabled) return;
1214
+ const destination = currentReplayTraceDestination();
1215
+ if (destination && destination.kind !== "workshop") return;
593
1216
  const list = Array.isArray(users) ? users : [users];
594
1217
  const body = list.filter((user) => {
595
1218
  if (!(user == null ? void 0 : user.userId) || !user.userId.trim()) {
@@ -642,8 +1265,9 @@ var EventShipper = class {
642
1265
  this.buffers.delete(eventId);
643
1266
  if (!accumulated) return;
644
1267
  const sticky = (_a = this.sticky.get(eventId)) != null ? _a : {};
645
- const eventName = (_c = (_b = accumulated.eventName) != null ? _b : sticky.eventName) != null ? _c : this.defaultEventName;
646
- const userId = (_d = accumulated.userId) != null ? _d : sticky.userId;
1268
+ const isPending = (_c = (_b = accumulated.isPending) != null ? _b : sticky.isPending) != null ? _c : true;
1269
+ const eventName = (_e = (_d = accumulated.eventName) != null ? _d : sticky.eventName) != null ? _e : this.defaultEventName;
1270
+ const userId = (_f = accumulated.userId) != null ? _f : sticky.userId;
647
1271
  if (!userId) {
648
1272
  if (this.debug) {
649
1273
  console.warn(`${this.prefix} skipping track_partial for ${eventId}: missing userId`);
@@ -651,9 +1275,13 @@ var EventShipper = class {
651
1275
  this.sticky.delete(eventId);
652
1276
  return;
653
1277
  }
654
- const { wizardSession, ...restProperties } = (_e = accumulated.properties) != null ? _e : {};
655
- const convoId = (_f = accumulated.convoId) != null ? _f : sticky.convoId;
656
- const isPending = (_h = (_g = accumulated.isPending) != null ? _g : sticky.isPending) != null ? _h : true;
1278
+ const { wizardSession, ...restProperties } = (_g = accumulated.properties) != null ? _g : {};
1279
+ let telemetryProperties = {};
1280
+ try {
1281
+ telemetryProperties = eventTelemetryProperties(accumulated);
1282
+ } catch (e) {
1283
+ }
1284
+ const convoId = (_h = accumulated.convoId) != null ? _h : sticky.convoId;
657
1285
  const payload = {
658
1286
  event_id: eventId,
659
1287
  user_id: userId,
@@ -661,12 +1289,13 @@ var EventShipper = class {
661
1289
  timestamp: (_i = accumulated.timestamp) != null ? _i : (/* @__PURE__ */ new Date()).toISOString(),
662
1290
  ai_data: {
663
1291
  input: accumulated.input,
664
- output: accumulated.output,
1292
+ output: accumulated.error !== void 0 && accumulated.error !== null ? void 0 : accumulated.output,
665
1293
  model: accumulated.model,
666
1294
  convo_id: convoId
667
1295
  },
668
1296
  properties: {
669
1297
  ...restProperties,
1298
+ ...telemetryProperties,
670
1299
  ...wizardSession ? { "raindrop.wizardSession": wizardSession } : {},
671
1300
  $context: this.context
672
1301
  },
@@ -694,29 +1323,30 @@ var EventShipper = class {
694
1323
  endpoint: url
695
1324
  });
696
1325
  }
697
- if (this.localDebuggerUrl) {
698
- mirrorPartialEventToLocalDebugger(payload, {
699
- baseUrl: this.localDebuggerUrl,
700
- writeKey: this.writeKey,
701
- debug: this.debug,
702
- sdkName: this.sdkName
703
- });
704
- }
1326
+ const mirror = this.localDebuggerUrl ? mirrorPartialEventToLocalDebugger(payload, {
1327
+ baseUrl: this.localDebuggerUrl,
1328
+ writeKey: this.writeKey,
1329
+ debug: this.debug,
1330
+ sdkName: this.sdkName
1331
+ }) : void 0;
705
1332
  if (!this.writeKey) {
706
1333
  if (!isPending) this.sticky.delete(eventId);
1334
+ if (mirror) await mirror;
707
1335
  return;
708
1336
  }
709
1337
  const opts = this.requestOpts();
710
1338
  if (!opts) {
711
1339
  this.warnShutdownDrop(`track_partial ${eventId}`);
712
1340
  if (!isPending) this.sticky.delete(eventId);
1341
+ if (mirror) await mirror;
713
1342
  return;
714
1343
  }
715
1344
  const p = postJson(url, payload, this.requestHeaders(), opts);
716
- this.inFlight.add(p);
1345
+ const combined = mirror ? Promise.all([mirror, p]).then(() => void 0) : p;
1346
+ this.inFlight.add(combined);
717
1347
  try {
718
1348
  try {
719
- await p;
1349
+ await combined;
720
1350
  if (this.debug) {
721
1351
  console.log(`${this.prefix} sent track_partial ${eventId} (${eventName})`);
722
1352
  }
@@ -728,13 +1358,156 @@ var EventShipper = class {
728
1358
  );
729
1359
  }
730
1360
  } finally {
731
- this.inFlight.delete(p);
1361
+ this.inFlight.delete(combined);
732
1362
  }
733
1363
  if (!isPending) {
734
1364
  this.sticky.delete(eventId);
735
1365
  }
736
1366
  }
737
1367
  };
1368
+ var MODEL_USAGE_ATTRIBUTES = {
1369
+ usageSource: "raindrop.usage.source",
1370
+ providerName: "gen_ai.provider.name",
1371
+ requestModel: "gen_ai.request.model",
1372
+ responseModel: "gen_ai.response.model",
1373
+ inputTokens: "gen_ai.usage.input_tokens",
1374
+ outputTokens: "gen_ai.usage.output_tokens",
1375
+ reasoningTokens: "gen_ai.usage.reasoning_tokens",
1376
+ cacheReadInputTokens: "gen_ai.usage.cache_read_input_tokens",
1377
+ cacheWriteInputTokens: "gen_ai.usage.cache_write_input_tokens",
1378
+ providerReportedCost: "gen_ai.usage.provider_reported_cost",
1379
+ nonCachedInputTokens: "raindrop.usage.input_tokens.non_cached",
1380
+ nonReasoningOutputTokens: "raindrop.usage.output_tokens.non_reasoning",
1381
+ totalOutputTokens: "raindrop.usage.output_tokens.total",
1382
+ reasoningOutputTokens: "raindrop.usage.output_tokens.reasoning",
1383
+ cacheReadTokens: "raindrop.usage.input_tokens.cache_read",
1384
+ cacheWriteTokens: "raindrop.usage.input_tokens.cache_write"
1385
+ };
1386
+ var MODEL_PROVIDER_NAMES = [
1387
+ ["google.vertex.anthropic", "google-vertex"],
1388
+ ["google.vertex_ai", "google-vertex"],
1389
+ ["google.vertex", "google-vertex"],
1390
+ ["gcp.vertex_ai", "google-vertex"],
1391
+ ["gcp.gemini", "google"],
1392
+ ["google_vertexai", "google-vertex"],
1393
+ ["vertex.anthropic", "google-vertex"],
1394
+ ["amazon-bedrock", "amazon-bedrock"],
1395
+ ["aws.bedrock", "amazon-bedrock"],
1396
+ ["bedrock", "amazon-bedrock"],
1397
+ ["anthropic", "anthropic"],
1398
+ ["openai", "openai"],
1399
+ ["google", "google"],
1400
+ ["az.ai.openai", "azure"],
1401
+ ["azure", "azure"],
1402
+ ["openrouter", "openrouter"]
1403
+ ];
1404
+ function canonicalModelProvider(provider) {
1405
+ var _a;
1406
+ const normalizedProvider = provider.trim().toLowerCase();
1407
+ if (normalizedProvider === "gateway") return "vercel";
1408
+ const match = MODEL_PROVIDER_NAMES.find(
1409
+ ([family]) => normalizedProvider === family || normalizedProvider.startsWith(`${family}.`)
1410
+ );
1411
+ return (_a = match == null ? void 0 : match[1]) != null ? _a : normalizedProvider;
1412
+ }
1413
+ var STRING_ALIASES = {
1414
+ [MODEL_USAGE_ATTRIBUTES.requestModel]: ["ai.model.id", "ai.model"]
1415
+ };
1416
+ var NUMBER_ALIASES = {
1417
+ [MODEL_USAGE_ATTRIBUTES.inputTokens]: [
1418
+ "gen_ai.usage.prompt_tokens",
1419
+ "ai.usage.prompt_tokens",
1420
+ "ai.usage.promptTokens",
1421
+ "ai.usage.input_tokens",
1422
+ "ai.usage.inputTokens"
1423
+ ],
1424
+ [MODEL_USAGE_ATTRIBUTES.outputTokens]: [
1425
+ "gen_ai.usage.completion_tokens",
1426
+ "ai.usage.completion_tokens",
1427
+ "ai.usage.completionTokens",
1428
+ "ai.usage.output_tokens",
1429
+ "ai.usage.outputTokens"
1430
+ ],
1431
+ [MODEL_USAGE_ATTRIBUTES.reasoningTokens]: [
1432
+ "gen_ai.usage.reasoning.output_tokens",
1433
+ "ai.usage.reasoningTokens",
1434
+ "ai.usage.thoughts_tokens"
1435
+ ],
1436
+ [MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens]: [
1437
+ "gen_ai.usage.cache_read_tokens",
1438
+ "gen_ai.usage.cache_read.input_tokens",
1439
+ "ai.usage.cachedInputTokens",
1440
+ "ai.usage.cached_tokens",
1441
+ "ai.usage.cache_read_tokens",
1442
+ "ai.usage.cache_read_input_tokens",
1443
+ "ai.usage.cacheReadInputTokens"
1444
+ ],
1445
+ [MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens]: [
1446
+ "gen_ai.usage.cache_creation_input_tokens",
1447
+ "gen_ai.usage.cache_creation.input_tokens",
1448
+ "ai.usage.cacheWriteInputTokens",
1449
+ "ai.usage.cache_creation_input_tokens",
1450
+ "ai.usage.cacheCreationInputTokens"
1451
+ ]
1452
+ };
1453
+ function hasAttribute(attributes, key) {
1454
+ return attributes.some((attribute) => attribute.key === key);
1455
+ }
1456
+ function findStringAttribute(attributes, keys) {
1457
+ return attributes.find(
1458
+ (attribute) => keys.includes(attribute.key) && typeof attribute.value.stringValue === "string" && attribute.value.stringValue.length > 0
1459
+ );
1460
+ }
1461
+ function findNumberAttribute(attributes, keys) {
1462
+ return attributes.find((attribute) => {
1463
+ if (!keys.includes(attribute.key)) return false;
1464
+ if (typeof attribute.value.doubleValue === "number" && Number.isSafeInteger(attribute.value.doubleValue) && attribute.value.doubleValue >= 0) {
1465
+ return true;
1466
+ }
1467
+ const intValue = attribute.value.intValue;
1468
+ return integerValue(intValue) !== void 0;
1469
+ });
1470
+ }
1471
+ function integerValue(value) {
1472
+ if (typeof value === "number") {
1473
+ return Number.isSafeInteger(value) && value >= 0 ? value : void 0;
1474
+ }
1475
+ if (typeof value !== "string") return void 0;
1476
+ const parsed = Number(value);
1477
+ return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : void 0;
1478
+ }
1479
+ function appendAlias(attributes, target, source) {
1480
+ if (!source || hasAttribute(attributes, target)) return attributes;
1481
+ return [...attributes, { key: target, value: { ...source.value } }];
1482
+ }
1483
+ function appendProviderAlias(attributes) {
1484
+ if (hasAttribute(attributes, MODEL_USAGE_ATTRIBUTES.providerName)) return attributes;
1485
+ const source = findStringAttribute(attributes, ["gen_ai.system", "ai.model.provider"]);
1486
+ if (!(source == null ? void 0 : source.value.stringValue)) return attributes;
1487
+ const attribute = attrString(
1488
+ MODEL_USAGE_ATTRIBUTES.providerName,
1489
+ canonicalModelProvider(source.value.stringValue)
1490
+ );
1491
+ return attribute ? [...attributes, attribute] : attributes;
1492
+ }
1493
+ function normalizeModelUsageSpan(span) {
1494
+ const original = span.attributes;
1495
+ if (!original || original.length === 0) return span;
1496
+ const responseModel = findStringAttribute(original, [
1497
+ MODEL_USAGE_ATTRIBUTES.responseModel,
1498
+ "ai.response.model"
1499
+ ]);
1500
+ if (!responseModel) return span;
1501
+ let attributes = appendAlias(original, MODEL_USAGE_ATTRIBUTES.responseModel, responseModel);
1502
+ attributes = appendProviderAlias(attributes);
1503
+ for (const [target, aliases] of Object.entries(STRING_ALIASES)) {
1504
+ attributes = appendAlias(attributes, target, findStringAttribute(attributes, aliases));
1505
+ }
1506
+ for (const [target, aliases] of Object.entries(NUMBER_ALIASES)) {
1507
+ attributes = appendAlias(attributes, target, findNumberAttribute(attributes, aliases));
1508
+ }
1509
+ return attributes === original ? span : { ...span, attributes };
1510
+ }
738
1511
  var DEFAULT_SECRET_KEY_NAMES = [
739
1512
  "apikey",
740
1513
  "apisecret",
@@ -824,6 +1597,20 @@ function redactJsonAttributeValue(key, value) {
824
1597
  if (scrubbedJson === json) return void 0;
825
1598
  return { stringValue: scrubbedJson };
826
1599
  }
1600
+ function appGitOwnerId2(prefix) {
1601
+ try {
1602
+ return `${prefix}:${randomUUID()}`;
1603
+ } catch (e) {
1604
+ return `${prefix}:${Date.now().toString(36)}:${Math.random().toString(36).slice(2)}`;
1605
+ }
1606
+ }
1607
+ function identityAttrs(args) {
1608
+ return [
1609
+ attrString("ai.telemetry.metadata.raindrop.ai.userId", args.userId),
1610
+ attrString("ai.telemetry.metadata.raindrop.convoId", args.convoId),
1611
+ attrString("ai.telemetry.metadata.raindrop.eventName", args.eventName)
1612
+ ];
1613
+ }
827
1614
  function applyOtelSpanAttributeLimit(limit) {
828
1615
  var _a, _b;
829
1616
  try {
@@ -839,23 +1626,30 @@ function applyOtelSpanAttributeLimit(limit) {
839
1626
  }
840
1627
  var TraceShipper = class {
841
1628
  constructor(opts) {
1629
+ this.appGitOwner = appGitOwnerId2("trace");
1630
+ this.appGitEventIds = /* @__PURE__ */ new WeakMap();
1631
+ this.appGitActiveSpans = /* @__PURE__ */ new Map();
1632
+ this.appGitCaptured = /* @__PURE__ */ new WeakSet();
1633
+ this.appGitAdded = /* @__PURE__ */ new WeakMap();
842
1634
  this.queue = [];
843
1635
  this.inFlight = /* @__PURE__ */ new Set();
844
1636
  this.hasShutdown = false;
845
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
846
- this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
847
- this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
1637
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
1638
+ this.appGitContext = (_a = opts.appGitContext) != null ? _a : createAppGitContext(opts.appGit);
1639
+ this.ownsAppGitContext = opts.appGitContext === void 0;
1640
+ this.writeKey = (_b = opts.writeKey) == null ? void 0 : _b.trim();
1641
+ this.baseUrl = (_c = formatEndpoint(opts.endpoint)) != null ? _c : "https://api.raindrop.ai/v1/";
848
1642
  this.enabled = opts.enabled !== false;
849
1643
  this.debug = opts.debug;
850
1644
  this.debugSpans = opts.debugSpans === true;
851
- this.flushIntervalMs = (_c = opts.flushIntervalMs) != null ? _c : 1e3;
852
- this.maxBatchSize = (_d = opts.maxBatchSize) != null ? _d : 50;
853
- this.maxQueueSize = (_e = opts.maxQueueSize) != null ? _e : 5e3;
854
- this.sdkName = (_f = opts.sdkName) != null ? _f : "core";
1645
+ this.flushIntervalMs = (_d = opts.flushIntervalMs) != null ? _d : 1e3;
1646
+ this.maxBatchSize = (_e = opts.maxBatchSize) != null ? _e : 50;
1647
+ this.maxQueueSize = (_f = opts.maxQueueSize) != null ? _f : 5e3;
1648
+ this.sdkName = (_g = opts.sdkName) != null ? _g : "core";
855
1649
  this.prefix = `[raindrop-ai/${this.sdkName}]`;
856
- this.serviceName = (_g = opts.serviceName) != null ? _g : "raindrop.core";
857
- this.serviceVersion = (_h = opts.serviceVersion) != null ? _h : "0.0.0";
858
- this.localDebuggerUrl = (_i = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _i : void 0;
1650
+ this.serviceName = (_h = opts.serviceName) != null ? _h : "raindrop.core";
1651
+ this.serviceVersion = (_i = opts.serviceVersion) != null ? _i : "0.0.0";
1652
+ this.localDebuggerUrl = (_j = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _j : void 0;
859
1653
  if (this.debug && this.localDebuggerUrl) {
860
1654
  console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
861
1655
  }
@@ -919,7 +1713,10 @@ var TraceShipper = class {
919
1713
  try {
920
1714
  const result = this.transformSpanHook(current);
921
1715
  if (result === null) return null;
922
- if (result !== void 0) current = result;
1716
+ if (result !== void 0) {
1717
+ copyReplayTraceDestination(current, result);
1718
+ current = result;
1719
+ }
923
1720
  } catch (err) {
924
1721
  if (this.debug) {
925
1722
  const msg = err instanceof Error ? err.message : String(err);
@@ -928,10 +1725,20 @@ var TraceShipper = class {
928
1725
  return null;
929
1726
  }
930
1727
  }
1728
+ try {
1729
+ const normalized = normalizeModelUsageSpan(current);
1730
+ copyReplayTraceDestination(current, normalized);
1731
+ current = normalized;
1732
+ } catch (e) {
1733
+ }
931
1734
  if (!this.disableDefaultRedaction) {
932
- current = defaultTransformSpan(current);
1735
+ const redacted = defaultTransformSpan(current);
1736
+ copyReplayTraceDestination(current, redacted);
1737
+ current = redacted;
933
1738
  }
934
- return this.capSpanAttributes(current);
1739
+ const capped = this.capSpanAttributes(current);
1740
+ copyReplayTraceDestination(current, capped);
1741
+ return capped;
935
1742
  }
936
1743
  isDebugEnabled() {
937
1744
  return this.debug;
@@ -943,45 +1750,84 @@ var TraceShipper = class {
943
1750
  return { ...this.authHeaders(), ...projectIdHeaders(this.projectId) };
944
1751
  }
945
1752
  startSpan(args) {
946
- var _a, _b;
1753
+ var _a, _b, _c;
947
1754
  const ids = createSpanIds(args.parent);
948
1755
  const started = (_a = args.startTimeUnixNano) != null ? _a : nowUnixNanoString();
949
1756
  const attrs = [
950
1757
  attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId),
951
- attrString("ai.operationId", args.operationId)
1758
+ ...identityAttrs(args),
1759
+ attrString("ai.operationId", args.operationId),
1760
+ ...Object.entries(evalScopeAttributes()).map(([key, value]) => attrString(key, value))
952
1761
  ];
953
1762
  if ((_b = args.attributes) == null ? void 0 : _b.length) attrs.push(...args.attributes);
954
- const span = { ids, name: args.name, startTimeUnixNano: started, attributes: attrs };
955
- this.mirrorToLocalDebugger(
956
- buildOtlpSpan({
957
- ids: span.ids,
958
- name: span.name,
959
- startTimeUnixNano: span.startTimeUnixNano,
960
- endTimeUnixNano: span.startTimeUnixNano,
961
- // placeholder — will be updated on endSpan
962
- attributes: span.attributes,
963
- status: { code: SpanStatusCode.UNSET }
964
- })
965
- );
1763
+ const tracksAppGit = this.appGitActiveSpans.has(args.eventId) || this.appGitActiveSpans.size < 1e4;
1764
+ const appGitOverrides = appGitPropertiesFromAttributes(attrs);
1765
+ const span = {
1766
+ ids,
1767
+ name: args.name,
1768
+ startTimeUnixNano: started,
1769
+ attributes: withAppGitAttributes(
1770
+ attrs,
1771
+ this.appGitContext.forOperation(args.eventId, appGitOverrides, this.appGitOwner)
1772
+ )
1773
+ };
1774
+ rememberReplayTraceDestination(span);
1775
+ this.appGitCaptured.add(span);
1776
+ this.appGitEventIds.set(span, args.eventId);
1777
+ if (tracksAppGit) {
1778
+ this.appGitActiveSpans.set(args.eventId, ((_c = this.appGitActiveSpans.get(args.eventId)) != null ? _c : 0) + 1);
1779
+ }
1780
+ this.appGitAdded.set(span, new Set(span.attributes.filter((attr) => !attrs.includes(attr))));
1781
+ const openSpan = buildOtlpSpan({
1782
+ ids: span.ids,
1783
+ name: span.name,
1784
+ startTimeUnixNano: span.startTimeUnixNano,
1785
+ endTimeUnixNano: span.startTimeUnixNano,
1786
+ // placeholder — will be updated on endSpan
1787
+ attributes: span.attributes,
1788
+ status: { code: SpanStatusCode.UNSET }
1789
+ });
1790
+ copyReplayTraceDestination(span, openSpan);
1791
+ this.mirrorToLocalDebugger(openSpan);
966
1792
  return span;
967
1793
  }
968
- mirrorToLocalDebugger(span) {
969
- if (!this.localDebuggerUrl) return;
1794
+ mirrorToLocalDebugger(span, completed = false) {
1795
+ const destination = replayTraceDestinationFor(span);
1796
+ if (destination && destination.kind !== "workshop") return;
1797
+ const localDebuggerUrl = (destination == null ? void 0 : destination.kind) === "workshop" ? destination.url : this.localDebuggerUrl;
1798
+ if (!localDebuggerUrl) return;
970
1799
  const redacted = this.redactSpan(span);
971
1800
  if (redacted === null) return;
1801
+ if (completed && (destination == null ? void 0 : destination.kind) === "workshop") {
1802
+ recordReplayExportedSpan(
1803
+ destination,
1804
+ base64ToHex(redacted.spanId),
1805
+ base64ToHex(redacted.traceId)
1806
+ );
1807
+ }
972
1808
  const body = buildExportTraceServiceRequest([redacted], this.serviceName, this.serviceVersion);
973
- mirrorTraceExportToLocalDebugger(body, {
974
- baseUrl: this.localDebuggerUrl,
1809
+ const p = mirrorTraceExportToLocalDebugger(body, {
1810
+ baseUrl: localDebuggerUrl,
975
1811
  debug: false,
976
1812
  sdkName: this.sdkName
977
1813
  });
1814
+ this.inFlight.add(p);
1815
+ void p.finally(() => {
1816
+ this.inFlight.delete(p);
1817
+ });
978
1818
  }
979
1819
  endSpan(span, extra) {
980
- var _a, _b;
1820
+ var _a, _b, _c;
981
1821
  if (span.endTimeUnixNano) return;
982
1822
  span.endTimeUnixNano = (_a = extra == null ? void 0 : extra.endTimeUnixNano) != null ? _a : nowUnixNanoString();
983
1823
  if ((_b = extra == null ? void 0 : extra.attributes) == null ? void 0 : _b.length) {
1824
+ const overrides = appGitPropertiesFromAttributes(extra.attributes);
1825
+ const eventId2 = this.appGitEventIds.get(span);
1826
+ const snapshot = eventId2 ? this.appGitContext.forOperation(eventId2, overrides, this.appGitOwner) : overrides;
1827
+ const added = this.appGitAdded.get(span);
1828
+ span.attributes = span.attributes.filter((attr) => !(added == null ? void 0 : added.has(attr)) || !attr || !Object.prototype.hasOwnProperty.call(overrides, APP_COMMIT_SHA) && !Object.prototype.hasOwnProperty.call(overrides, attr.key));
984
1829
  span.attributes.push(...extra.attributes);
1830
+ span.attributes = withAppGitAttributes(span.attributes, snapshot);
985
1831
  }
986
1832
  let status = extra == null ? void 0 : extra.status;
987
1833
  if (!status && (extra == null ? void 0 : extra.error) !== void 0) {
@@ -996,29 +1842,65 @@ var TraceShipper = class {
996
1842
  attributes: span.attributes,
997
1843
  status
998
1844
  });
1845
+ copyReplayTraceDestination(span, otlp);
1846
+ this.appGitCaptured.add(otlp);
999
1847
  this.enqueue(otlp);
1000
- this.mirrorToLocalDebugger(otlp);
1848
+ this.mirrorToLocalDebugger(otlp, true);
1849
+ const eventId = this.appGitEventIds.get(span);
1850
+ if (eventId && this.appGitActiveSpans.has(eventId)) {
1851
+ const remaining = ((_c = this.appGitActiveSpans.get(eventId)) != null ? _c : 1) - 1;
1852
+ if (remaining > 0) this.appGitActiveSpans.set(eventId, remaining);
1853
+ else {
1854
+ this.appGitActiveSpans.delete(eventId);
1855
+ if (this.appGitContext.releaseOperation) this.appGitContext.releaseOperation(eventId, this.appGitOwner);
1856
+ else if (this.ownsAppGitContext) this.appGitContext.finishOperation(eventId);
1857
+ }
1858
+ }
1001
1859
  }
1002
1860
  createSpan(args) {
1003
1861
  var _a;
1004
1862
  const ids = createSpanIds(args.parent);
1005
1863
  const attrs = [
1006
- attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId)
1864
+ attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId),
1865
+ ...identityAttrs(args),
1866
+ ...Object.entries(evalScopeAttributes()).map(([key, value]) => attrString(key, value))
1007
1867
  ];
1008
1868
  if ((_a = args.attributes) == null ? void 0 : _a.length) attrs.push(...args.attributes);
1869
+ const tracksAppGit = !this.appGitActiveSpans.has(args.eventId);
1009
1870
  const otlp = buildOtlpSpan({
1010
1871
  ids,
1011
1872
  name: args.name,
1012
1873
  startTimeUnixNano: args.startTimeUnixNano,
1013
1874
  endTimeUnixNano: args.endTimeUnixNano,
1014
- attributes: attrs,
1875
+ attributes: withAppGitAttributes(
1876
+ attrs,
1877
+ this.appGitContext.forOperation(
1878
+ args.eventId,
1879
+ appGitPropertiesFromAttributes(attrs),
1880
+ this.appGitOwner
1881
+ )
1882
+ ),
1015
1883
  status: args.status
1016
1884
  });
1885
+ rememberReplayTraceDestination(otlp);
1886
+ this.appGitCaptured.add(otlp);
1887
+ if (tracksAppGit) {
1888
+ if (this.appGitContext.releaseOperation) this.appGitContext.releaseOperation(args.eventId, this.appGitOwner);
1889
+ else if (this.ownsAppGitContext) this.appGitContext.finishOperation(args.eventId);
1890
+ }
1017
1891
  this.enqueue(otlp);
1018
- this.mirrorToLocalDebugger(otlp);
1892
+ this.mirrorToLocalDebugger(otlp, true);
1019
1893
  }
1020
1894
  enqueue(span) {
1895
+ var _a;
1021
1896
  if (!this.enabled) return;
1897
+ const attributes = (_a = span.attributes) != null ? _a : [];
1898
+ const enriched = this.appGitCaptured.has(span) ? attributes : withAppGitAttributes(attributes, this.appGitContext.snapshot(appGitPropertiesFromAttributes(attributes)));
1899
+ if (enriched !== attributes) {
1900
+ const original = span;
1901
+ span = { ...span, attributes: enriched.filter((attr) => attr !== void 0) };
1902
+ copyReplayTraceDestination(original, span);
1903
+ }
1022
1904
  if (this.debugSpans) {
1023
1905
  const short = (s) => s ? s.slice(-8) : "none";
1024
1906
  console.log(
@@ -1029,6 +1911,13 @@ var TraceShipper = class {
1029
1911
  }
1030
1912
  const redacted = this.redactSpan(span);
1031
1913
  if (redacted === null) return;
1914
+ const destination = replayTraceDestinationFor(redacted);
1915
+ recordReplayExportedSpan(
1916
+ destination,
1917
+ base64ToHex(redacted.spanId),
1918
+ base64ToHex(redacted.traceId)
1919
+ );
1920
+ if ((destination == null ? void 0 : destination.kind) === "workshop") return;
1032
1921
  if (this.queue.length >= this.maxQueueSize) {
1033
1922
  this.queue.shift();
1034
1923
  }
@@ -1047,47 +1936,67 @@ var TraceShipper = class {
1047
1936
  }
1048
1937
  }
1049
1938
  async flush() {
1050
- if (!this.enabled) return;
1939
+ var _a;
1940
+ if (!this.enabled) {
1941
+ await Promise.all([...this.inFlight].map((p) => p.catch(() => {
1942
+ })));
1943
+ return;
1944
+ }
1051
1945
  if (this.timer) {
1052
1946
  clearTimeout(this.timer);
1053
1947
  this.timer = void 0;
1054
1948
  }
1055
1949
  while (this.queue.length > 0) {
1056
1950
  const batch = this.queue.splice(0, this.maxBatchSize);
1057
- if (!this.writeKey) continue;
1058
- const opts = this.requestOpts();
1059
- if (!opts) {
1060
- rateLimitedLog(
1061
- `${this.prefix}.shutdown_deadline`,
1062
- () => console.warn(
1063
- `${this.prefix} shutdown flush deadline exceeded; dropping ${batch.length} spans`
1064
- )
1065
- );
1066
- continue;
1067
- }
1068
- const body = buildExportTraceServiceRequest(batch, this.serviceName, this.serviceVersion);
1069
- const url = `${this.baseUrl}traces`;
1070
- if (this.debug) {
1071
- console.log(`${this.prefix} sending traces batch`, {
1072
- spans: batch.length,
1073
- endpoint: url
1074
- });
1951
+ const groups = /* @__PURE__ */ new Map();
1952
+ for (const span of batch) {
1953
+ const destination = replayTraceDestinationFor(span);
1954
+ const spans = groups.get(destination);
1955
+ if (spans) spans.push(span);
1956
+ else groups.set(destination, [span]);
1075
1957
  }
1076
- const p = postJson(url, body, this.requestHeaders(), opts);
1077
- this.inFlight.add(p);
1078
- try {
1079
- try {
1080
- await p;
1081
- if (this.debug) console.log(`${this.prefix} sent ${batch.length} spans`);
1082
- } catch (err) {
1083
- const msg = err instanceof Error ? err.message : String(err);
1958
+ for (const [destination, spans] of groups) {
1959
+ if (!destination && !this.writeKey) continue;
1960
+ if ((destination == null ? void 0 : destination.kind) === "workshop") continue;
1961
+ const opts = this.requestOpts();
1962
+ if (!opts) {
1084
1963
  rateLimitedLog(
1085
- `${this.prefix}.send_spans_failed`,
1086
- () => console.warn(`${this.prefix} failed to send ${batch.length} spans: ${msg}`)
1964
+ `${this.prefix}.shutdown_deadline`,
1965
+ () => console.warn(
1966
+ `${this.prefix} shutdown flush deadline exceeded; dropping ${spans.length} spans`
1967
+ )
1087
1968
  );
1969
+ continue;
1970
+ }
1971
+ const body = buildExportTraceServiceRequest(spans, this.serviceName, this.serviceVersion);
1972
+ const url = destination ? replayTraceUrl(destination.url) : `${this.baseUrl}traces`;
1973
+ const headers = destination ? {
1974
+ Authorization: `Bearer ${destination.apiKey}`,
1975
+ "X-Raindrop-Replay-Id": destination.replayId,
1976
+ "X-Raindrop-Project-Id": (_a = destination.projectId) != null ? _a : "default"
1977
+ } : this.requestHeaders();
1978
+ if (this.debug) {
1979
+ console.log(`${this.prefix} sending traces batch`, {
1980
+ spans: spans.length,
1981
+ endpoint: url
1982
+ });
1983
+ }
1984
+ const p = postJson(url, body, headers, opts);
1985
+ this.inFlight.add(p);
1986
+ try {
1987
+ try {
1988
+ await p;
1989
+ if (this.debug) console.log(`${this.prefix} sent ${spans.length} spans`);
1990
+ } catch (err) {
1991
+ const msg = err instanceof Error ? err.message : String(err);
1992
+ rateLimitedLog(
1993
+ `${this.prefix}.send_spans_failed`,
1994
+ () => console.warn(`${this.prefix} failed to send ${spans.length} spans: ${msg}`)
1995
+ );
1996
+ }
1997
+ } finally {
1998
+ this.inFlight.delete(p);
1088
1999
  }
1089
- } finally {
1090
- this.inFlight.delete(p);
1091
2000
  }
1092
2001
  }
1093
2002
  }
@@ -1130,17 +2039,165 @@ var TraceShipper = class {
1130
2039
  if (!settled) {
1131
2040
  rateLimitedLog(
1132
2041
  `${this.prefix}.shutdown_deadline`,
1133
- () => console.warn(`${this.prefix} shutdown flush deadline exceeded; abandoning in-flight spans`)
2042
+ () => console.warn(
2043
+ `${this.prefix} shutdown flush deadline exceeded; abandoning in-flight spans`
2044
+ )
1134
2045
  );
1135
2046
  }
1136
2047
  } finally {
1137
2048
  this.shutdownDeadlineAt = void 0;
2049
+ if (this.ownsAppGitContext) this.appGitContext.dispose();
1138
2050
  }
1139
2051
  }
1140
2052
  };
1141
2053
 
1142
2054
  // ../core/dist/index.node.js
1143
2055
  import { AsyncLocalStorage } from "async_hooks";
2056
+ import { execFile } from "child_process";
2057
+ import { resolve } from "path";
2058
+ var resolveLocal = (sourceDirectory, detectBranch, completed) => {
2059
+ const cwd = sourceDirectory ? resolve(sourceDirectory) : process.cwd();
2060
+ let cancelled = false;
2061
+ let active;
2062
+ let deadlineTimer;
2063
+ const deadline = Date.now() + 1e3;
2064
+ const run = (args, done) => {
2065
+ if (cancelled) return;
2066
+ const remaining = deadline - Date.now();
2067
+ if (remaining <= 0) {
2068
+ done(void 0);
2069
+ return;
2070
+ }
2071
+ try {
2072
+ active = execFile(
2073
+ "git",
2074
+ args,
2075
+ {
2076
+ cwd,
2077
+ encoding: "utf8",
2078
+ maxBuffer: 4096,
2079
+ windowsHide: true,
2080
+ env: {
2081
+ ...process.env,
2082
+ // The selected application cwd, not the invoking shell's Git plumbing, owns identity.
2083
+ GIT_DIR: void 0,
2084
+ GIT_WORK_TREE: void 0,
2085
+ GIT_COMMON_DIR: void 0,
2086
+ GIT_NAMESPACE: void 0,
2087
+ GIT_INDEX_FILE: void 0,
2088
+ GIT_OBJECT_DIRECTORY: void 0,
2089
+ GIT_ALTERNATE_OBJECT_DIRECTORIES: void 0,
2090
+ GIT_CONFIG_PARAMETERS: void 0,
2091
+ GIT_CONFIG_COUNT: "0",
2092
+ GIT_TERMINAL_PROMPT: "0",
2093
+ GIT_OPTIONAL_LOCKS: "0"
2094
+ }
2095
+ },
2096
+ (error, stdout) => {
2097
+ clearTimeout(deadlineTimer);
2098
+ deadlineTimer = void 0;
2099
+ active = void 0;
2100
+ if (!cancelled) {
2101
+ try {
2102
+ done(error ? void 0 : stdout.trim());
2103
+ } catch (e) {
2104
+ }
2105
+ }
2106
+ }
2107
+ );
2108
+ active.unref();
2109
+ if (active.stdout && "unref" in active.stdout && typeof active.stdout.unref === "function")
2110
+ active.stdout.unref();
2111
+ if (active.stderr && "unref" in active.stderr && typeof active.stderr.unref === "function")
2112
+ active.stderr.unref();
2113
+ deadlineTimer = setTimeout(() => {
2114
+ try {
2115
+ active == null ? void 0 : active.kill("SIGKILL");
2116
+ } catch (e) {
2117
+ }
2118
+ }, remaining);
2119
+ deadlineTimer.unref();
2120
+ } catch (e) {
2121
+ try {
2122
+ done(void 0);
2123
+ } catch (e2) {
2124
+ }
2125
+ }
2126
+ };
2127
+ const scheduled = setTimeout(() => {
2128
+ try {
2129
+ run(["rev-parse", "HEAD"], (rawSha) => {
2130
+ const commitSha = validAppCommitSha(rawSha);
2131
+ if (!commitSha) {
2132
+ completed({});
2133
+ return;
2134
+ }
2135
+ run(["-c", "core.fsmonitor=false", "status", "--porcelain"], (status) => {
2136
+ const finish = (branch) => {
2137
+ run(["rev-parse", "HEAD"], (finalSha) => {
2138
+ const coherent = validAppCommitSha(finalSha) === commitSha;
2139
+ completed({
2140
+ commitSha,
2141
+ ...coherent && status !== void 0 ? { commitDirty: status !== "" } : {},
2142
+ ...coherent && branch && branch !== "HEAD" ? { branch } : {}
2143
+ });
2144
+ });
2145
+ };
2146
+ if (detectBranch) run(["symbolic-ref", "--quiet", "--short", "HEAD"], finish);
2147
+ else finish();
2148
+ });
2149
+ });
2150
+ } catch (e) {
2151
+ completed({});
2152
+ }
2153
+ }, 0);
2154
+ scheduled.unref();
2155
+ return () => {
2156
+ cancelled = true;
2157
+ clearTimeout(scheduled);
2158
+ clearTimeout(deadlineTimer);
2159
+ try {
2160
+ active == null ? void 0 : active.kill("SIGKILL");
2161
+ } catch (e) {
2162
+ }
2163
+ };
2164
+ };
2165
+ function createAppGitContext2(options, runtime = {}) {
2166
+ return new AppGitContext(options, { ...runtime, resolveLocal });
2167
+ }
2168
+ function hasDestination(options) {
2169
+ var _a;
2170
+ if (options.enabled === false) return false;
2171
+ return Boolean(((_a = options.writeKey) == null ? void 0 : _a.trim()) || resolveLocalDebuggerBaseUrl(options.localDebuggerUrl));
2172
+ }
2173
+ var EventShipper2 = class extends EventShipper {
2174
+ constructor(options) {
2175
+ var _a;
2176
+ const ownsAppGitContext = options.appGitContext === void 0;
2177
+ const appGitContext = (_a = options.appGitContext) != null ? _a : createAppGitContext2(options.appGit, { allowDiscovery: hasDestination(options) });
2178
+ try {
2179
+ super({ ...options, appGitContext });
2180
+ } catch (error) {
2181
+ if (ownsAppGitContext) appGitContext.dispose();
2182
+ throw error;
2183
+ }
2184
+ if (ownsAppGitContext) this.ownAppGitContextForShutdown();
2185
+ }
2186
+ };
2187
+ var TraceShipper2 = class extends TraceShipper {
2188
+ constructor(options) {
2189
+ var _a;
2190
+ const ownsAppGitContext = options.appGitContext === void 0;
2191
+ const appGitContext = (_a = options.appGitContext) != null ? _a : createAppGitContext2(options.appGit, { allowDiscovery: hasDestination(options) });
2192
+ try {
2193
+ super({ ...options, appGitContext });
2194
+ } catch (error) {
2195
+ if (ownsAppGitContext) appGitContext.dispose();
2196
+ throw error;
2197
+ }
2198
+ this.ownsAppGitContext = ownsAppGitContext;
2199
+ }
2200
+ };
1144
2201
  globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = AsyncLocalStorage;
1145
2202
  var SUPPRESS_TRACING_KEY = /* @__PURE__ */ Symbol.for(
1146
2203
  "OpenTelemetry SDK Context Key SUPPRESS_TRACING"
@@ -1282,6 +2339,10 @@ var RaindropDeepAgentsHandler = class extends BaseCallbackHandler {
1282
2339
  });
1283
2340
  }
1284
2341
  }
2342
+ rootErrorPatch(runId, error) {
2343
+ const rootId = this.rootRunIds.get(runId) ?? runId;
2344
+ return rootId === runId ? { error } : void 0;
2345
+ }
1285
2346
  // ---------------------------------------------------------------------------
1286
2347
  // LLM events
1287
2348
  // ---------------------------------------------------------------------------
@@ -1377,8 +2438,6 @@ var RaindropDeepAgentsHandler = class extends BaseCallbackHandler {
1377
2438
  ]
1378
2439
  });
1379
2440
  const properties = {};
1380
- if (promptTokens != null) properties["ai.usage.prompt_tokens"] = promptTokens;
1381
- if (completionTokens != null) properties["ai.usage.completion_tokens"] = completionTokens;
1382
2441
  if (cachedTokens != null) properties["ai.usage.cached_tokens"] = cachedTokens;
1383
2442
  if (reasoningTokens != null) properties["ai.usage.thoughts_tokens"] = reasoningTokens;
1384
2443
  if (finishReason != null) properties["ai.finish_reason"] = finishReason;
@@ -1386,6 +2445,7 @@ var RaindropDeepAgentsHandler = class extends BaseCallbackHandler {
1386
2445
  await this.finalizeEventIfRoot(runId, {
1387
2446
  output: cappedOutput,
1388
2447
  model,
2448
+ usage: { promptTokens, completionTokens },
1389
2449
  properties: Object.keys(properties).length > 0 ? properties : void 0
1390
2450
  });
1391
2451
  } catch {
@@ -1403,14 +2463,7 @@ var RaindropDeepAgentsHandler = class extends BaseCallbackHandler {
1403
2463
  if (span) {
1404
2464
  this.traceShipper.endSpan(span, { error: err });
1405
2465
  }
1406
- const errorInfo = extractErrorInfo(err);
1407
- await this.finalizeEventIfRoot(runId, {
1408
- output: `[Error] ${errorInfo.type}: ${errorInfo.message}`,
1409
- properties: {
1410
- "error.type": errorInfo.type,
1411
- "error.message": errorInfo.message
1412
- }
1413
- });
2466
+ await this.finalizeEventIfRoot(runId, this.rootErrorPatch(runId, err));
1414
2467
  } catch {
1415
2468
  } finally {
1416
2469
  this.cleanup(runId);
@@ -1472,14 +2525,7 @@ var RaindropDeepAgentsHandler = class extends BaseCallbackHandler {
1472
2525
  const span = this.spans.get(runId);
1473
2526
  if (span) this.traceShipper.endSpan(span, { error: err });
1474
2527
  }
1475
- const errorInfo = extractErrorInfo(err);
1476
- await this.finalizeEventIfRoot(runId, {
1477
- output: `[Error] ${errorInfo.type}: ${errorInfo.message}`,
1478
- properties: {
1479
- "error.type": errorInfo.type,
1480
- "error.message": errorInfo.message
1481
- }
1482
- });
2528
+ await this.finalizeEventIfRoot(runId, this.rootErrorPatch(runId, err));
1483
2529
  } catch {
1484
2530
  } finally {
1485
2531
  this.cleanup(runId);
@@ -1534,14 +2580,7 @@ var RaindropDeepAgentsHandler = class extends BaseCallbackHandler {
1534
2580
  try {
1535
2581
  const span = this.spans.get(runId);
1536
2582
  if (span) this.traceShipper.endSpan(span, { error: err });
1537
- const errorInfo = extractErrorInfo(err);
1538
- await this.finalizeEventIfRoot(runId, {
1539
- output: `[Error] ${errorInfo.type}: ${errorInfo.message}`,
1540
- properties: {
1541
- "error.type": errorInfo.type,
1542
- "error.message": errorInfo.message
1543
- }
1544
- });
2583
+ await this.finalizeEventIfRoot(runId, this.rootErrorPatch(runId, err));
1545
2584
  } catch {
1546
2585
  } finally {
1547
2586
  this.cleanup(runId);
@@ -1706,22 +2745,78 @@ function asNumber(val) {
1706
2745
  const n = typeof val === "number" ? val : Number(val);
1707
2746
  return Number.isFinite(n) ? n : void 0;
1708
2747
  }
1709
- function extractErrorInfo(err) {
1710
- if (err instanceof Error) {
1711
- return { type: err.name || err.constructor.name, message: err.message };
1712
- }
1713
- if (typeof err === "object" && err !== null) {
1714
- const e = err;
1715
- const type = e.name ?? e.constructor?.name ?? "Error";
1716
- const message = e.message ?? safeStringify(err);
1717
- return { type, message };
2748
+
2749
+ // package.json
2750
+ var package_default = {
2751
+ name: "@raindrop-ai/deep-agents",
2752
+ version: "0.1.2",
2753
+ description: "Raindrop integration for LangChain Deep Agents",
2754
+ main: "dist/index.js",
2755
+ module: "dist/index.mjs",
2756
+ types: "dist/index.d.ts",
2757
+ license: "MIT",
2758
+ homepage: "https://www.raindrop.ai/docs/integrations/deepagents/",
2759
+ bugs: {
2760
+ url: "https://www.raindrop.ai/docs/support/"
2761
+ },
2762
+ exports: {
2763
+ ".": {
2764
+ types: "./dist/index.d.ts",
2765
+ import: "./dist/index.mjs",
2766
+ require: "./dist/index.js"
2767
+ }
2768
+ },
2769
+ sideEffects: false,
2770
+ files: [
2771
+ "dist/**"
2772
+ ],
2773
+ scripts: {
2774
+ build: "tsup",
2775
+ dev: "tsup --watch",
2776
+ clean: "rm -rf dist",
2777
+ test: "vitest run"
2778
+ },
2779
+ peerDependencies: {
2780
+ "@langchain/core": ">=0.3.0",
2781
+ deepagents: ">=0.5.0"
2782
+ },
2783
+ devDependencies: {
2784
+ "@langchain/anthropic": "~0.3.34",
2785
+ "@langchain/core": ">=0.3.0",
2786
+ "@langchain/openai": "~0.3.17",
2787
+ "@raindrop-ai/core": "workspace:*",
2788
+ "@types/node": "^20.11.17",
2789
+ deepagents: "1.0.0",
2790
+ msw: "^2.12.7",
2791
+ tsup: "^8.4.0",
2792
+ typescript: "^5.3.3",
2793
+ vitest: "^2.1.9",
2794
+ zod: "^3.23.0"
2795
+ },
2796
+ tsup: {
2797
+ entry: [
2798
+ "src/index.ts"
2799
+ ],
2800
+ format: [
2801
+ "cjs",
2802
+ "esm"
2803
+ ],
2804
+ dts: {
2805
+ resolve: true
2806
+ },
2807
+ clean: true,
2808
+ noExternal: [
2809
+ "@raindrop-ai/core"
2810
+ ]
2811
+ },
2812
+ publishConfig: {
2813
+ access: "public"
1718
2814
  }
1719
- return { type: "Error", message: String(err) };
1720
- }
2815
+ };
1721
2816
 
1722
2817
  // src/version.ts
1723
- var libraryName = "@raindrop-ai/deep-agents";
1724
- var libraryVersion = "0.0.1";
2818
+ var libraryName = package_default.name;
2819
+ var libraryVersion = package_default.version;
1725
2820
 
1726
2821
  // src/index.ts
1727
2822
  function createRaindropDeepAgents(opts) {
@@ -1732,7 +2827,8 @@ function createRaindropDeepAgents(opts) {
1732
2827
  "[raindrop-ai/deep-agents] writeKey not provided; telemetry shipping is disabled"
1733
2828
  );
1734
2829
  }
1735
- const eventShipper = new EventShipper({
2830
+ const appGitContext = createAppGitContext2(writeKey?.trim() ? opts.appGit : false, { allowLocalGit: true });
2831
+ const eventShipper = new EventShipper2({
1736
2832
  writeKey,
1737
2833
  endpoint: opts.endpoint,
1738
2834
  enabled,
@@ -1740,9 +2836,10 @@ function createRaindropDeepAgents(opts) {
1740
2836
  projectId: opts.projectId,
1741
2837
  sdkName: "deep-agents",
1742
2838
  libraryName,
1743
- libraryVersion
2839
+ libraryVersion,
2840
+ appGitContext
1744
2841
  });
1745
- const traceShipper = new TraceShipper({
2842
+ const traceShipper = new TraceShipper2({
1746
2843
  writeKey,
1747
2844
  endpoint: opts.endpoint,
1748
2845
  enabled,
@@ -1750,7 +2847,8 @@ function createRaindropDeepAgents(opts) {
1750
2847
  projectId: opts.projectId,
1751
2848
  sdkName: "deep-agents",
1752
2849
  serviceName: "raindrop.deep-agents",
1753
- serviceVersion: libraryVersion
2850
+ serviceVersion: libraryVersion,
2851
+ appGitContext
1754
2852
  });
1755
2853
  const handler = new RaindropDeepAgentsHandler({
1756
2854
  eventShipper,
@@ -1770,7 +2868,14 @@ function createRaindropDeepAgents(opts) {
1770
2868
  await Promise.all([eventShipper.flush(), traceShipper.flush()]);
1771
2869
  },
1772
2870
  async shutdown() {
1773
- await Promise.all([eventShipper.shutdown(), traceShipper.shutdown()]);
2871
+ try {
2872
+ await Promise.all([eventShipper.shutdown(), traceShipper.shutdown()]);
2873
+ } finally {
2874
+ try {
2875
+ appGitContext.dispose();
2876
+ } catch {
2877
+ }
2878
+ }
1774
2879
  },
1775
2880
  events: {
1776
2881
  async patch(eventId, patch) {