@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.js CHANGED
@@ -28,7 +28,521 @@ module.exports = __toCommonJS(index_exports);
28
28
  // src/callback-handler.ts
29
29
  var import_base = require("@langchain/core/callbacks/base");
30
30
 
31
- // ../core/dist/chunk-267IXHO5.js
31
+ // ../core/dist/chunk-BYBMRLZM.js
32
+ var EVAL_CORRELATION_ID_ATTRIBUTE = "raindrop.eval_correlation_id";
33
+ var PROBE_SCOPE = { correlationId: "" };
34
+ var EvalScopeStorage = class {
35
+ constructor() {
36
+ this._als = null;
37
+ this._probed = false;
38
+ }
39
+ maybeAdoptAsyncLocalStorage() {
40
+ if (this._probed) return;
41
+ this._probed = true;
42
+ try {
43
+ const Ctor = globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
44
+ if (!Ctor) return;
45
+ const als = new Ctor();
46
+ als.run(PROBE_SCOPE, () => {
47
+ });
48
+ this._als = als;
49
+ } catch (e) {
50
+ this._als = null;
51
+ }
52
+ }
53
+ run(scope, callback) {
54
+ this.maybeAdoptAsyncLocalStorage();
55
+ if (this._als) return this._als.run(scope, callback);
56
+ const previous = this._syncScope;
57
+ this._syncScope = scope;
58
+ try {
59
+ return callback();
60
+ } finally {
61
+ this._syncScope = previous;
62
+ }
63
+ }
64
+ current() {
65
+ this.maybeAdoptAsyncLocalStorage();
66
+ if (this._als) return this._als.getStore();
67
+ return this._syncScope;
68
+ }
69
+ };
70
+ var EVAL_SCOPE_STORAGE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.evalScopeStorage");
71
+ function evalScopeStorage() {
72
+ const holder = globalThis;
73
+ let storage = holder[EVAL_SCOPE_STORAGE_KEY];
74
+ if (!storage) {
75
+ storage = new EvalScopeStorage();
76
+ holder[EVAL_SCOPE_STORAGE_KEY] = storage;
77
+ }
78
+ return storage;
79
+ }
80
+ function currentEvalScope() {
81
+ try {
82
+ return evalScopeStorage().current();
83
+ } catch (e) {
84
+ return void 0;
85
+ }
86
+ }
87
+ function evalScopeAttributes() {
88
+ const scope = currentEvalScope();
89
+ if (!scope) return {};
90
+ return { [EVAL_CORRELATION_ID_ATTRIBUTE]: scope.correlationId };
91
+ }
92
+
93
+ // ../core/dist/chunk-WJOR6M7H.js
94
+ var STATE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.replayTraceRoutingState");
95
+ function state() {
96
+ const holder = globalThis;
97
+ let current = holder[STATE_KEY];
98
+ if (!current) {
99
+ let storage = null;
100
+ try {
101
+ const Ctor = globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
102
+ if (Ctor) storage = new Ctor();
103
+ } catch (e) {
104
+ storage = null;
105
+ }
106
+ current = {
107
+ storage,
108
+ syncDestination: void 0,
109
+ spanDestinations: /* @__PURE__ */ new WeakMap()
110
+ };
111
+ holder[STATE_KEY] = current;
112
+ }
113
+ return current;
114
+ }
115
+ function currentReplayTraceDestination() {
116
+ var _a, _b;
117
+ const routing = state();
118
+ return (_b = (_a = routing.storage) == null ? void 0 : _a.getStore()) != null ? _b : routing.syncDestination;
119
+ }
120
+ function rememberReplayTraceDestination(span) {
121
+ const destination = currentReplayTraceDestination();
122
+ if (destination) state().spanDestinations.set(span, destination);
123
+ }
124
+ function copyReplayTraceDestination(source, target) {
125
+ const destination = state().spanDestinations.get(source);
126
+ if (destination) state().spanDestinations.set(target, destination);
127
+ }
128
+ function replayTraceDestinationFor(value) {
129
+ if (typeof value !== "object" && typeof value !== "function" || value === null) {
130
+ return void 0;
131
+ }
132
+ return state().spanDestinations.get(value);
133
+ }
134
+ function recordReplayExportedSpan(destination, spanId, traceId) {
135
+ var _a, _b;
136
+ if (!destination || !spanId || !traceId) return;
137
+ (_a = destination.exportedSpanIds) == null ? void 0 : _a.add(spanId);
138
+ (_b = destination.exportedTraceIds) == null ? void 0 : _b.add(traceId);
139
+ }
140
+ function replayTraceUrl(baseUrl) {
141
+ return `${baseUrl.replace(/\/+$/, "")}/v1/traces`;
142
+ }
143
+ function getAsyncLocalStorageCtor() {
144
+ return globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
145
+ }
146
+ var MAX_BINDING_STACK = 128;
147
+ var EMPTY_STACK = [];
148
+ var ContextStackStorage = class {
149
+ /** Emitted once when this runtime cannot support an ambient push. */
150
+ constructor(noAmbientBindWarning) {
151
+ this.noAmbientBindWarning = noAmbientBindWarning;
152
+ this._als = null;
153
+ this._enterWithUsable = false;
154
+ this._syncStack = EMPTY_STACK;
155
+ this._adoptionChecked = false;
156
+ this._warnedNoAmbientBind = false;
157
+ }
158
+ maybeAdoptAsyncLocalStorage() {
159
+ if (this._adoptionChecked) return;
160
+ this._adoptionChecked = true;
161
+ const Ctor = getAsyncLocalStorageCtor();
162
+ if (!Ctor) return;
163
+ const als = new Ctor();
164
+ try {
165
+ als.run(EMPTY_STACK, () => {
166
+ });
167
+ } catch (e) {
168
+ return;
169
+ }
170
+ this._als = als;
171
+ if (typeof als.enterWith === "function") {
172
+ try {
173
+ als.enterWith(EMPTY_STACK);
174
+ this._enterWithUsable = true;
175
+ } catch (e) {
176
+ this._enterWithUsable = false;
177
+ }
178
+ }
179
+ }
180
+ getStack() {
181
+ var _a;
182
+ this.maybeAdoptAsyncLocalStorage();
183
+ if (this._als) return (_a = this._als.getStore()) != null ? _a : this._syncStack;
184
+ return this._syncStack;
185
+ }
186
+ /**
187
+ * Persist an ambient stack mutation. Returns false when an ALS is adopted but
188
+ * `enterWith` is unusable (workerd): callers must NOT fall back to the
189
+ * process-shared sync stack, since concurrent isolates would cross-stamp.
190
+ */
191
+ setAmbientStack(stack) {
192
+ if (this._als) {
193
+ if (!this._enterWithUsable) return false;
194
+ this._als.enterWith(stack);
195
+ return true;
196
+ }
197
+ this._syncStack = stack;
198
+ return true;
199
+ }
200
+ push(binding) {
201
+ this.maybeAdoptAsyncLocalStorage();
202
+ if (this._als && !this._enterWithUsable) {
203
+ this.warnNoAmbientBindOnce();
204
+ return;
205
+ }
206
+ let stack = this.getStack();
207
+ if (stack.length >= MAX_BINDING_STACK) {
208
+ stack = stack.filter((b) => b.isLive());
209
+ if (stack.length >= MAX_BINDING_STACK) {
210
+ stack = stack.slice(stack.length - (MAX_BINDING_STACK - 1));
211
+ }
212
+ }
213
+ this.setAmbientStack([...stack, binding]);
214
+ }
215
+ remove(binding) {
216
+ binding.markDead();
217
+ const stack = this.getStack();
218
+ const pruned = stack.filter((b) => b !== binding && b.isLive());
219
+ if (pruned.length !== stack.length) {
220
+ this.setAmbientStack(pruned);
221
+ }
222
+ }
223
+ runWith(binding, callback) {
224
+ this.maybeAdoptAsyncLocalStorage();
225
+ if (this._als) {
226
+ return this._als.run([...this.getStack(), binding], callback);
227
+ }
228
+ const previous = this._syncStack;
229
+ this._syncStack = [...previous, binding];
230
+ try {
231
+ return callback();
232
+ } finally {
233
+ this._syncStack = previous;
234
+ }
235
+ }
236
+ current() {
237
+ const stack = this.getStack();
238
+ if (stack.length === 0) return void 0;
239
+ const top = stack[stack.length - 1];
240
+ if (top.isLive()) return top;
241
+ const pruned = stack.filter((b) => b.isLive());
242
+ this.setAmbientStack(pruned);
243
+ return pruned.length > 0 ? pruned[pruned.length - 1] : void 0;
244
+ }
245
+ warnNoAmbientBindOnce() {
246
+ if (this._warnedNoAmbientBind) return;
247
+ this._warnedNoAmbientBind = true;
248
+ console.warn(this.noAmbientBindWarning);
249
+ }
250
+ };
251
+ 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.";
252
+ var ROUTING_STORAGE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.routingContextStorage");
253
+ function routingStorage() {
254
+ const holder = globalThis;
255
+ let storage = holder[ROUTING_STORAGE_KEY];
256
+ if (!storage) {
257
+ storage = new ContextStackStorage(NO_AMBIENT_ROUTING_BIND_WARNING);
258
+ holder[ROUTING_STORAGE_KEY] = storage;
259
+ }
260
+ return storage;
261
+ }
262
+ function currentRoutingBinding() {
263
+ const bound = routingStorage().current();
264
+ if (!bound) return void 0;
265
+ return {
266
+ projectId: bound.projectId,
267
+ authHint: bound.authHint,
268
+ ...bound.appGit ? { appGit: bound.appGit } : {},
269
+ ...bound.appGitSource ? { appGitSource: bound.appGitSource } : {}
270
+ };
271
+ }
272
+ var APP_COMMIT_SHA = "raindrop.app.commit_sha";
273
+ var APP_COMMIT_DIRTY = "raindrop.app.commit_dirty";
274
+ var APP_BRANCH = "raindrop.app.branch";
275
+ var APP_GIT_KEYS = [APP_COMMIT_SHA, APP_COMMIT_DIRTY, APP_BRANCH];
276
+ var own = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
277
+ function appGitExplicitKeys(properties) {
278
+ const keys = /* @__PURE__ */ new Set();
279
+ if (!properties) return keys;
280
+ for (const key of APP_GIT_KEYS) {
281
+ if (own(properties, key)) keys.add(key);
282
+ }
283
+ return keys;
284
+ }
285
+ function mergeAppGitSnapshot(base, properties, explicitKeys = /* @__PURE__ */ new Set()) {
286
+ try {
287
+ const result = { ...base };
288
+ if (properties && own(properties, APP_COMMIT_SHA) && properties[APP_COMMIT_SHA] !== result[APP_COMMIT_SHA]) {
289
+ if (!explicitKeys.has(APP_COMMIT_DIRTY) && !own(properties, APP_COMMIT_DIRTY)) {
290
+ delete result[APP_COMMIT_DIRTY];
291
+ }
292
+ if (!explicitKeys.has(APP_BRANCH) && !own(properties, APP_BRANCH)) {
293
+ delete result[APP_BRANCH];
294
+ }
295
+ }
296
+ for (const key of APP_GIT_KEYS) {
297
+ if (properties && own(properties, key)) result[key] = properties[key];
298
+ }
299
+ return Object.freeze(result);
300
+ } catch (e) {
301
+ return Object.freeze({});
302
+ }
303
+ }
304
+ function validAppCommitSha(value) {
305
+ if (typeof value !== "string" || value.length > 128) return void 0;
306
+ const cleaned = value.trim();
307
+ return /^(?:[a-fA-F0-9]{40}|[a-fA-F0-9]{64})$/.test(cleaned) ? cleaned.toLowerCase() : void 0;
308
+ }
309
+ function shortString(value) {
310
+ if (typeof value !== "string" || value.length > 1024) return void 0;
311
+ const cleaned = value.trim();
312
+ return cleaned.length > 0 ? cleaned : void 0;
313
+ }
314
+ function flag(value) {
315
+ if (value === true || value === "true" || value === "1") return true;
316
+ if (value === false || value === "false" || value === "0") return false;
317
+ return void 0;
318
+ }
319
+ function environment() {
320
+ try {
321
+ return typeof process === "undefined" ? {} : process.env;
322
+ } catch (e) {
323
+ return {};
324
+ }
325
+ }
326
+ var DEPLOYMENTS = [
327
+ ["VERCEL", "VERCEL_GIT_COMMIT_SHA", "VERCEL_GIT_COMMIT_REF"],
328
+ ["NETLIFY", "COMMIT_REF", "BRANCH"],
329
+ ["RAILWAY_ENVIRONMENT_NAME", "RAILWAY_GIT_COMMIT_SHA", "RAILWAY_GIT_BRANCH"],
330
+ ["RAILWAY_ENVIRONMENT", "RAILWAY_GIT_COMMIT_SHA", "RAILWAY_GIT_BRANCH"],
331
+ ["RENDER", "RENDER_GIT_COMMIT", "RENDER_GIT_BRANCH"],
332
+ ["DYNO", "HEROKU_BUILD_COMMIT", ""],
333
+ ["DYNO", "HEROKU_SLUG_COMMIT", ""],
334
+ ["AWS_APP_ID", "AWS_COMMIT_ID", "AWS_BRANCH"],
335
+ ["WORKERS_CI", "WORKERS_CI_COMMIT_SHA", "WORKERS_CI_BRANCH"]
336
+ ];
337
+ var CI_SOURCES = [
338
+ ["GITHUB_ACTIONS", "GITHUB_SHA", "GITHUB_REF_NAME"],
339
+ ["GITLAB_CI", "CI_COMMIT_SHA", "CI_COMMIT_REF_NAME"],
340
+ ["CIRCLECI", "CIRCLE_SHA1", "CIRCLE_BRANCH"]
341
+ ];
342
+ function detectedSource(env, table, detectBranch) {
343
+ for (const row of table) {
344
+ const [marker, shaKey, branchKey] = row;
345
+ if (!marker || !shaKey || !shortString(env[marker]) || flag(env[marker]) === false) continue;
346
+ const commitSha = validAppCommitSha(env[shaKey]);
347
+ if (commitSha)
348
+ return {
349
+ commitSha,
350
+ ...detectBranch && branchKey ? { branch: shortString(env[branchKey]) } : {}
351
+ };
352
+ }
353
+ return {};
354
+ }
355
+ var AppGitContextImpl = class {
356
+ constructor(options, runtime = {}) {
357
+ this.defaults = {};
358
+ this.explicit = {};
359
+ this.explicitKeys = /* @__PURE__ */ new Set();
360
+ this.disposed = false;
361
+ this.operations = /* @__PURE__ */ new Map();
362
+ this.operationOverflow = false;
363
+ this.detectBranch = false;
364
+ this.disabled = false;
365
+ var _a, _b, _c, _d, _e, _f;
366
+ try {
367
+ if (options === false) {
368
+ this.disabled = true;
369
+ return;
370
+ }
371
+ const opts = options != null ? options : {};
372
+ const env = (_a = runtime.env) != null ? _a : environment();
373
+ const detectBranch = (_c = (_b = flag(opts.detectBranch)) != null ? _b : flag(env.RAINDROP_GIT_DETECT_BRANCH)) != null ? _c : false;
374
+ this.detectBranch = detectBranch;
375
+ const collectBranch = detectBranch || runtime.captureLegacyReplayBranch === true;
376
+ const autoDetect = runtime.allowDiscovery === false ? false : (_e = (_d = flag(opts.autoDetect)) != null ? _d : flag(env.RAINDROP_GIT_AUTO_DETECT)) != null ? _e : true;
377
+ const configuredSha = opts.commitSha;
378
+ const explicitSha = configuredSha === void 0 ? env.RAINDROP_COMMIT_SHA : configuredSha;
379
+ if (explicitSha === null) this.explicit[APP_COMMIT_SHA] = null;
380
+ else if (typeof explicitSha === "string" && validAppCommitSha(explicitSha))
381
+ this.explicit[APP_COMMIT_SHA] = explicitSha;
382
+ const configuredDirty = opts.commitDirty;
383
+ const explicitDirty = configuredDirty === void 0 ? flag(env.RAINDROP_COMMIT_DIRTY) : configuredDirty;
384
+ if (explicitDirty === null || typeof explicitDirty === "boolean")
385
+ this.explicit[APP_COMMIT_DIRTY] = explicitDirty;
386
+ const configuredBranch = opts.branch;
387
+ const explicitBranch = configuredBranch === void 0 ? env.RAINDROP_BRANCH : configuredBranch;
388
+ if (explicitBranch === null) this.explicit[APP_BRANCH] = null;
389
+ else if (typeof explicitBranch === "string" && explicitBranch.length <= 1024)
390
+ this.explicit[APP_BRANCH] = explicitBranch;
391
+ this.explicitKeys = appGitExplicitKeys(this.explicit);
392
+ this.defaults = { ...this.explicit };
393
+ if (!autoDetect || explicitSha !== void 0) return;
394
+ const sourceDirectory = (_f = shortString(opts.sourceDirectory)) != null ? _f : shortString(env.RAINDROP_GIT_SOURCE_DIRECTORY);
395
+ if (runtime.allowLocalGit === false && !sourceDirectory) return;
396
+ const deploy = sourceDirectory ? {} : detectedSource(env, DEPLOYMENTS, collectBranch);
397
+ if (deploy.commitSha) {
398
+ this.accept(deploy);
399
+ return;
400
+ }
401
+ const fallback = sourceDirectory ? {} : detectedSource(env, CI_SOURCES, collectBranch);
402
+ if (runtime.resolveLocal && (runtime.allowLocalGit !== false || sourceDirectory)) {
403
+ this.cancel = runtime.resolveLocal(sourceDirectory, collectBranch, (result) => {
404
+ try {
405
+ if (!this.disposed) this.accept(result.commitSha ? result : fallback);
406
+ } catch (e) {
407
+ }
408
+ });
409
+ } else this.accept(fallback);
410
+ } catch (e) {
411
+ }
412
+ }
413
+ accept(result) {
414
+ const sha = validAppCommitSha(result.commitSha);
415
+ if (!sha) return;
416
+ this.replayBranch = shortString(result.branch);
417
+ this.defaults = {
418
+ [APP_COMMIT_SHA]: sha,
419
+ ...typeof result.commitDirty === "boolean" ? { [APP_COMMIT_DIRTY]: result.commitDirty } : {},
420
+ ...this.detectBranch && this.replayBranch ? { [APP_BRANCH]: this.replayBranch } : {},
421
+ ...this.explicit
422
+ };
423
+ }
424
+ snapshot(properties) {
425
+ var _a;
426
+ try {
427
+ const binding = currentRoutingBinding();
428
+ const base = this.disabled && (binding == null ? void 0 : binding.appGitSource) !== "replay-override" ? {} : (_a = binding == null ? void 0 : binding.appGit) != null ? _a : this.defaults;
429
+ return this.mergeSnapshot(base, properties);
430
+ } catch (e) {
431
+ return Object.freeze({});
432
+ }
433
+ }
434
+ /** Safe defaults when no operation/span start was observed; never infer identity. */
435
+ snapshotExplicit(properties, eventId) {
436
+ try {
437
+ const base = { ...this.explicit };
438
+ const operation = eventId ? this.operations.get(eventId) : void 0;
439
+ if (operation) {
440
+ for (const key of operation.explicitKeys) base[key] = operation.snapshot[key];
441
+ }
442
+ return this.mergeSnapshot(base, properties, new Set(Object.keys(base)));
443
+ } catch (e) {
444
+ return mergeAppGitSnapshot({}, properties);
445
+ }
446
+ }
447
+ /** Existing replay branch reporting stays separate from opt-in event properties. */
448
+ snapshotForReplay() {
449
+ const snapshot = this.snapshot();
450
+ if (this.replayBranch && !own(snapshot, APP_BRANCH) && snapshot[APP_COMMIT_SHA] === this.defaults[APP_COMMIT_SHA]) {
451
+ return Object.freeze({ ...snapshot, [APP_BRANCH]: this.replayBranch });
452
+ }
453
+ return snapshot;
454
+ }
455
+ /** Merge a frozen span snapshot without losing client-authored provenance. */
456
+ mergeSnapshot(base, properties, explicitKeys = this.explicitKeys) {
457
+ return mergeAppGitSnapshot(base, properties, /* @__PURE__ */ new Set([...this.explicitKeys, ...explicitKeys]));
458
+ }
459
+ /** Shippers belonging to one client share this bounded operation registry. */
460
+ forOperation(eventId, properties, owner) {
461
+ if (!eventId) return this.snapshot(properties);
462
+ let operation = this.operations.get(eventId);
463
+ if (!operation) {
464
+ if (this.operations.size >= 1e4) this.operationOverflow = true;
465
+ if (this.operationOverflow) return this.mergeSnapshot({}, properties);
466
+ operation = {
467
+ snapshot: this.snapshot(properties),
468
+ owners: /* @__PURE__ */ new Set(),
469
+ unowned: owner === void 0,
470
+ explicitKeys: appGitExplicitKeys(properties)
471
+ };
472
+ this.operations.set(eventId, operation);
473
+ } else if (properties && APP_GIT_KEYS.some((key) => own(properties, key))) {
474
+ const explicitKeys = /* @__PURE__ */ new Set([...this.explicitKeys, ...operation.explicitKeys]);
475
+ operation.snapshot = this.mergeSnapshot(operation.snapshot, properties, explicitKeys);
476
+ for (const key of appGitExplicitKeys(properties)) operation.explicitKeys.add(key);
477
+ }
478
+ if (!owner) operation.unowned = true;
479
+ if (owner) operation.owners.add(owner);
480
+ return operation.snapshot;
481
+ }
482
+ releaseOperation(eventId, owner) {
483
+ const operation = this.operations.get(eventId);
484
+ if (!operation) return;
485
+ operation.owners.delete(owner);
486
+ if (operation.owners.size === 0 && !operation.unowned) this.operations.delete(eventId);
487
+ }
488
+ finishOperation(eventId) {
489
+ this.operations.delete(eventId);
490
+ }
491
+ dispose() {
492
+ var _a;
493
+ this.disposed = true;
494
+ try {
495
+ (_a = this.cancel) == null ? void 0 : _a.call(this);
496
+ } catch (e) {
497
+ }
498
+ }
499
+ };
500
+ var AppGitContext = AppGitContextImpl;
501
+ function createAppGitContext(options, runtime = {}) {
502
+ return new AppGitContext(options, runtime);
503
+ }
504
+ function withAppGitProperties(properties, snapshot) {
505
+ try {
506
+ const merged = { ...properties };
507
+ for (const key of APP_GIT_KEYS)
508
+ if (!own(merged, key) && own(snapshot, key)) merged[key] = snapshot[key];
509
+ return merged;
510
+ } catch (e) {
511
+ return properties != null ? properties : {};
512
+ }
513
+ }
514
+ function withAppGitAttributes(attributes, snapshot) {
515
+ try {
516
+ const present = new Set(attributes.flatMap((attr) => attr ? [attr.key] : []));
517
+ const added = [];
518
+ for (const key of APP_GIT_KEYS) {
519
+ if (present.has(key) || present.has(`ai.telemetry.metadata.${key}`) || present.has(`traceloop.association.properties.${key}`))
520
+ continue;
521
+ const value = snapshot[key];
522
+ if (typeof value === "string") added.push({ key, value: { stringValue: value } });
523
+ else if (typeof value === "boolean") added.push({ key, value: { boolValue: value } });
524
+ }
525
+ return added.length ? [...attributes, ...added] : attributes;
526
+ } catch (e) {
527
+ return attributes;
528
+ }
529
+ }
530
+ function appGitPropertiesFromAttributes(attributes) {
531
+ var _a, _b, _c;
532
+ const properties = {};
533
+ try {
534
+ for (const attr of attributes) {
535
+ if (!attr) continue;
536
+ for (const key of APP_GIT_KEYS) {
537
+ if (attr.key === key || attr.key === `ai.telemetry.metadata.${key}` || attr.key === `traceloop.association.properties.${key}`) {
538
+ properties[key] = (_c = (_b = (_a = attr.value.stringValue) != null ? _a : attr.value.boolValue) != null ? _b : attr.value.intValue) != null ? _c : null;
539
+ }
540
+ }
541
+ }
542
+ } catch (e) {
543
+ }
544
+ return properties;
545
+ }
32
546
  function getCrypto() {
33
547
  const c = globalThis.crypto;
34
548
  return c;
@@ -83,6 +597,39 @@ function base64Encode(bytes) {
83
597
  }
84
598
  return out;
85
599
  }
600
+ function base64ToHex(value) {
601
+ if (!value) return "";
602
+ const maybeBuffer = globalThis.Buffer;
603
+ if (maybeBuffer) {
604
+ return maybeBuffer.from(value, "base64").toString("hex");
605
+ }
606
+ const atobFn = globalThis.atob;
607
+ if (typeof atobFn !== "function") return "";
608
+ try {
609
+ const binary = atobFn(value);
610
+ let hex = "";
611
+ for (let i = 0; i < binary.length; i++) {
612
+ hex += (binary.charCodeAt(i) & 255).toString(16).padStart(2, "0");
613
+ }
614
+ return hex;
615
+ } catch (e) {
616
+ return "";
617
+ }
618
+ }
619
+ var HANDOFF_ATTRIBUTE_SUFFIXES = {
620
+ mode: "raindrop.handoff.mode",
621
+ childEventId: "raindrop.handoff.childEventId",
622
+ parentEventId: "raindrop.handoff.parentEventId",
623
+ parentSpanId: "raindrop.handoff.parentSpanId",
624
+ name: "raindrop.handoff.name",
625
+ terminal: "raindrop.handoff.terminal",
626
+ agentRole: "raindrop.agent.role"
627
+ };
628
+ var HANDOFF_TERMINAL_PROPERTY_KEY = HANDOFF_ATTRIBUTE_SUFFIXES.terminal;
629
+ var TRACEPARENT_HEADER = "traceparent";
630
+ var BAGGAGE_HEADER = "baggage";
631
+ var HANDOFF_HEADER = "x-raindrop-handoff";
632
+ 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.`;
86
633
  function runWithTracingSuppressed(fn) {
87
634
  const hook = globalThis.RAINDROP_SUPPRESS_TRACING;
88
635
  if (typeof hook !== "function") return fn();
@@ -100,7 +647,7 @@ function runWithTracingSuppressed(fn) {
100
647
  var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
101
648
  var MAX_RETRY_DELAY_MS = 3e4;
102
649
  function wait(ms) {
103
- return new Promise((resolve) => setTimeout(resolve, ms));
650
+ return new Promise((resolve2) => setTimeout(resolve2, ms));
104
651
  }
105
652
  function formatEndpoint(endpoint) {
106
653
  if (!endpoint) return void 0;
@@ -137,9 +684,9 @@ async function raceWithTimeout(promise, timeoutMs) {
137
684
  () => true,
138
685
  () => true
139
686
  ),
140
- new Promise((resolve) => {
687
+ new Promise((resolve2) => {
141
688
  var _a;
142
- timer = setTimeout(() => resolve(false), Math.max(0, timeoutMs));
689
+ timer = setTimeout(() => resolve2(false), Math.max(0, timeoutMs));
143
690
  (_a = timer.unref) == null ? void 0 : _a.call(timer);
144
691
  })
145
692
  ]);
@@ -210,6 +757,7 @@ async function postJson(url, body, headers, opts) {
210
757
  const resp = await runWithTracingSuppressed(
211
758
  () => fetch(url, {
212
759
  method: "POST",
760
+ redirect: headers["X-Raindrop-Replay-Id"] !== void 0 ? "error" : "follow",
213
761
  headers: {
214
762
  "Content-Type": "application/json",
215
763
  ...headers
@@ -373,26 +921,29 @@ function resolveLocalDebuggerBaseUrl(baseUrl) {
373
921
  if (shouldAutoEnableLocalWorkshop()) return DEFAULT_LOCAL_WORKSHOP_URL;
374
922
  return null;
375
923
  }
924
+ var LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS = 2e3;
376
925
  function mirrorTraceExportToLocalDebugger(body, options = {}) {
377
926
  var _a;
378
927
  const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
379
- if (!baseUrl) return;
380
- void postJson(`${baseUrl}traces`, body, {}, {
928
+ if (!baseUrl) return Promise.resolve();
929
+ return postJson(`${baseUrl}traces`, body, {}, {
381
930
  maxAttempts: 1,
382
931
  debug: (_a = options.debug) != null ? _a : false,
383
- sdkName: options.sdkName
932
+ sdkName: options.sdkName,
933
+ timeoutMs: LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS
384
934
  }).catch(() => {
385
935
  });
386
936
  }
387
937
  function mirrorPartialEventToLocalDebugger(event, options = {}) {
388
938
  var _a;
389
939
  const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
390
- if (!baseUrl) return;
940
+ if (!baseUrl) return Promise.resolve();
391
941
  const headers = options.writeKey ? { Authorization: `Bearer ${options.writeKey}` } : {};
392
- void postJson(`${baseUrl}events/track_partial`, event, headers, {
942
+ return postJson(`${baseUrl}events/track_partial`, event, headers, {
393
943
  maxAttempts: 1,
394
944
  debug: (_a = options.debug) != null ? _a : false,
395
- sdkName: options.sdkName
945
+ sdkName: options.sdkName,
946
+ timeoutMs: LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS
396
947
  }).catch(() => {
397
948
  });
398
949
  }
@@ -417,38 +968,81 @@ function projectIdHeaders(projectId) {
417
968
  }
418
969
  var SHUTDOWN_DEADLINE_MS = 1e4;
419
970
  var POST_SHUTDOWN_TIMEOUT_MS = 5e3;
971
+ function appGitOwnerId(prefix) {
972
+ try {
973
+ return `${prefix}:${randomUUID()}`;
974
+ } catch (e) {
975
+ return `${prefix}:${Date.now().toString(36)}:${Math.random().toString(36).slice(2)}`;
976
+ }
977
+ }
420
978
  function mergePatches(target, source) {
421
- var _a, _b, _c, _d, _e, _f;
979
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
422
980
  const out = { ...target, ...source };
423
981
  if (target.properties || source.properties) {
424
982
  out.properties = { ...(_a = target.properties) != null ? _a : {}, ...(_b = source.properties) != null ? _b : {} };
425
983
  }
984
+ if (target.usage || source.usage) {
985
+ out.usage = { ...(_c = target.usage) != null ? _c : {} };
986
+ if (((_d = source.usage) == null ? void 0 : _d.promptTokens) !== void 0) {
987
+ out.usage.promptTokens = source.usage.promptTokens;
988
+ }
989
+ if (((_e = source.usage) == null ? void 0 : _e.completionTokens) !== void 0) {
990
+ out.usage.completionTokens = source.usage.completionTokens;
991
+ }
992
+ }
993
+ if (source.error === void 0) {
994
+ out.error = target.error;
995
+ }
426
996
  if (target.featureFlags || source.featureFlags) {
427
- out.featureFlags = { ...(_c = target.featureFlags) != null ? _c : {}, ...(_d = source.featureFlags) != null ? _d : {} };
997
+ out.featureFlags = { ...(_f = target.featureFlags) != null ? _f : {}, ...(_g = source.featureFlags) != null ? _g : {} };
428
998
  }
429
999
  if (target.attachments || source.attachments) {
430
- out.attachments = [...(_e = target.attachments) != null ? _e : [], ...(_f = source.attachments) != null ? _f : []];
1000
+ out.attachments = [...(_h = target.attachments) != null ? _h : [], ...(_i = source.attachments) != null ? _i : []];
431
1001
  }
432
1002
  return out;
433
1003
  }
1004
+ function isErrorLike(value) {
1005
+ return value !== null && typeof value === "object";
1006
+ }
1007
+ function eventTelemetryProperties(patch) {
1008
+ var _a, _b;
1009
+ const properties = {};
1010
+ if (((_a = patch.usage) == null ? void 0 : _a.promptTokens) !== void 0 && Number.isFinite(patch.usage.promptTokens)) {
1011
+ properties["ai.usage.prompt_tokens"] = patch.usage.promptTokens;
1012
+ }
1013
+ if (((_b = patch.usage) == null ? void 0 : _b.completionTokens) !== void 0 && Number.isFinite(patch.usage.completionTokens)) {
1014
+ properties["ai.usage.completion_tokens"] = patch.usage.completionTokens;
1015
+ }
1016
+ if (patch.error !== void 0 && patch.error !== null) {
1017
+ const constructorName = patch.error instanceof Error && patch.error.constructor !== Error ? patch.error.constructor.name : void 0;
1018
+ 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";
1019
+ const errorMessage = patch.error instanceof Error ? patch.error.message : isErrorLike(patch.error) && typeof patch.error.message === "string" ? patch.error.message : String(patch.error);
1020
+ properties["error.type"] = errorType;
1021
+ properties["error.message"] = errorMessage;
1022
+ }
1023
+ return properties;
1024
+ }
434
1025
  var EventShipper = class {
435
1026
  constructor(opts) {
1027
+ this.appGitOwner = appGitOwnerId("event");
436
1028
  this.buffers = /* @__PURE__ */ new Map();
437
1029
  this.sticky = /* @__PURE__ */ new Map();
438
1030
  this.timers = /* @__PURE__ */ new Map();
439
1031
  this.inFlight = /* @__PURE__ */ new Set();
440
1032
  this.hasShutdown = false;
441
- var _a, _b, _c, _d, _e, _f, _g, _h;
442
- this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
443
- this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
1033
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1034
+ this.appGitContext = (_a = opts.appGitContext) != null ? _a : createAppGitContext(opts.appGit);
1035
+ this.ownsAppGitContext = opts.appGitContext === void 0;
1036
+ this.writeKey = (_b = opts.writeKey) == null ? void 0 : _b.trim();
1037
+ this.baseUrl = (_c = formatEndpoint(opts.endpoint)) != null ? _c : "https://api.raindrop.ai/v1/";
444
1038
  this.enabled = opts.enabled !== false;
445
1039
  this.debug = opts.debug;
446
- this.partialFlushMs = (_c = opts.partialFlushMs) != null ? _c : 1e3;
447
- this.sdkName = (_d = opts.sdkName) != null ? _d : "core";
1040
+ this.partialFlushMs = (_d = opts.partialFlushMs) != null ? _d : 1e3;
1041
+ this.sdkName = (_e = opts.sdkName) != null ? _e : "core";
448
1042
  this.prefix = `[raindrop-ai/${this.sdkName}]`;
449
- this.defaultEventName = (_e = opts.defaultEventName) != null ? _e : "ai_generation";
1043
+ this.defaultEventName = (_f = opts.defaultEventName) != null ? _f : "ai_generation";
450
1044
  this.maxTextFieldCharsOpt = opts.maxTextFieldChars;
451
- this.localDebuggerUrl = (_f = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _f : void 0;
1045
+ this.localDebuggerUrl = (_g = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _g : void 0;
452
1046
  if (this.debug && this.localDebuggerUrl) {
453
1047
  console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
454
1048
  }
@@ -459,8 +1053,8 @@ var EventShipper = class {
459
1053
  const isNode = typeof process !== "undefined" && typeof process.version === "string";
460
1054
  this.context = {
461
1055
  library: {
462
- name: (_g = opts.libraryName) != null ? _g : "@raindrop-ai/core",
463
- version: (_h = opts.libraryVersion) != null ? _h : "0.0.0"
1056
+ name: (_h = opts.libraryName) != null ? _h : "@raindrop-ai/core",
1057
+ version: (_i = opts.libraryVersion) != null ? _i : "0.0.0"
464
1058
  },
465
1059
  metadata: {
466
1060
  jsRuntime: isNode ? "node" : "web",
@@ -468,6 +1062,9 @@ var EventShipper = class {
468
1062
  }
469
1063
  };
470
1064
  }
1065
+ ownAppGitContextForShutdown() {
1066
+ this.ownsAppGitContext = true;
1067
+ }
471
1068
  isDebugEnabled() {
472
1069
  return this.debug;
473
1070
  }
@@ -516,6 +1113,15 @@ var EventShipper = class {
516
1113
  var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
517
1114
  if (!this.enabled) return;
518
1115
  if (!eventId || !eventId.trim()) return;
1116
+ const capturedSticky = this.sticky.get(eventId);
1117
+ const eventAlreadyKnown = capturedSticky !== void 0 || this.buffers.has(eventId);
1118
+ const destination = currentReplayTraceDestination();
1119
+ const cloudReplay = destination !== void 0 && destination.kind !== "workshop";
1120
+ if ((capturedSticky == null ? void 0 : capturedSticky.replayOnly) === true || !eventAlreadyKnown && cloudReplay) {
1121
+ if (patch.isPending === false) this.sticky.delete(eventId);
1122
+ else this.sticky.set(eventId, { ...capturedSticky, replayOnly: true });
1123
+ return;
1124
+ }
519
1125
  const maxChars = resolveMaxTextFieldChars(this.maxTextFieldCharsOpt);
520
1126
  if (typeof patch.input === "string" && patch.input.length > maxChars) {
521
1127
  patch = { ...patch, input: capText(patch.input, maxChars) };
@@ -537,6 +1143,13 @@ var EventShipper = class {
537
1143
  }
538
1144
  const sticky = (_c = this.sticky.get(eventId)) != null ? _c : {};
539
1145
  const existing = (_d = this.buffers.get(eventId)) != null ? _d : {};
1146
+ patch = {
1147
+ ...patch,
1148
+ properties: withAppGitProperties(
1149
+ patch.properties,
1150
+ this.appGitContext.forOperation(eventId, patch.properties, this.appGitOwner)
1151
+ )
1152
+ };
540
1153
  const merged = mergePatches(existing, patch);
541
1154
  merged.isPending = (_g = (_f = (_e = patch.isPending) != null ? _e : existing.isPending) != null ? _f : sticky.isPending) != null ? _g : true;
542
1155
  this.buffers.set(eventId, merged);
@@ -550,6 +1163,8 @@ var EventShipper = class {
550
1163
  if (t) clearTimeout(t);
551
1164
  if (merged.isPending === false) {
552
1165
  await this.flushOne(eventId);
1166
+ if (this.appGitContext.releaseOperation) this.appGitContext.releaseOperation(eventId, this.appGitOwner);
1167
+ else this.appGitContext.finishOperation(eventId);
553
1168
  return;
554
1169
  }
555
1170
  const timeout = setTimeout(() => {
@@ -574,15 +1189,21 @@ var EventShipper = class {
574
1189
  try {
575
1190
  for (const t of this.timers.values()) clearTimeout(t);
576
1191
  this.timers.clear();
1192
+ for (const [eventId, sticky] of this.sticky) {
1193
+ if (sticky.replayOnly) this.sticky.delete(eventId);
1194
+ }
577
1195
  const settled = await raceWithTimeout(this.flush(), SHUTDOWN_DEADLINE_MS);
578
1196
  if (!settled) this.warnShutdownDrop("in-flight request(s) at shutdown");
579
1197
  } finally {
580
1198
  this.shutdownDeadlineAt = void 0;
1199
+ if (this.ownsAppGitContext) this.appGitContext.dispose();
581
1200
  }
582
1201
  }
583
1202
  async trackSignal(signal) {
584
1203
  var _a, _b;
585
1204
  if (!this.enabled) return;
1205
+ const destination = currentReplayTraceDestination();
1206
+ if (destination && destination.kind !== "workshop") return;
586
1207
  const body = [
587
1208
  {
588
1209
  event_id: signal.eventId,
@@ -617,6 +1238,8 @@ var EventShipper = class {
617
1238
  }
618
1239
  async identify(users) {
619
1240
  if (!this.enabled) return;
1241
+ const destination = currentReplayTraceDestination();
1242
+ if (destination && destination.kind !== "workshop") return;
620
1243
  const list = Array.isArray(users) ? users : [users];
621
1244
  const body = list.filter((user) => {
622
1245
  if (!(user == null ? void 0 : user.userId) || !user.userId.trim()) {
@@ -669,8 +1292,9 @@ var EventShipper = class {
669
1292
  this.buffers.delete(eventId);
670
1293
  if (!accumulated) return;
671
1294
  const sticky = (_a = this.sticky.get(eventId)) != null ? _a : {};
672
- const eventName = (_c = (_b = accumulated.eventName) != null ? _b : sticky.eventName) != null ? _c : this.defaultEventName;
673
- const userId = (_d = accumulated.userId) != null ? _d : sticky.userId;
1295
+ const isPending = (_c = (_b = accumulated.isPending) != null ? _b : sticky.isPending) != null ? _c : true;
1296
+ const eventName = (_e = (_d = accumulated.eventName) != null ? _d : sticky.eventName) != null ? _e : this.defaultEventName;
1297
+ const userId = (_f = accumulated.userId) != null ? _f : sticky.userId;
674
1298
  if (!userId) {
675
1299
  if (this.debug) {
676
1300
  console.warn(`${this.prefix} skipping track_partial for ${eventId}: missing userId`);
@@ -678,9 +1302,13 @@ var EventShipper = class {
678
1302
  this.sticky.delete(eventId);
679
1303
  return;
680
1304
  }
681
- const { wizardSession, ...restProperties } = (_e = accumulated.properties) != null ? _e : {};
682
- const convoId = (_f = accumulated.convoId) != null ? _f : sticky.convoId;
683
- const isPending = (_h = (_g = accumulated.isPending) != null ? _g : sticky.isPending) != null ? _h : true;
1305
+ const { wizardSession, ...restProperties } = (_g = accumulated.properties) != null ? _g : {};
1306
+ let telemetryProperties = {};
1307
+ try {
1308
+ telemetryProperties = eventTelemetryProperties(accumulated);
1309
+ } catch (e) {
1310
+ }
1311
+ const convoId = (_h = accumulated.convoId) != null ? _h : sticky.convoId;
684
1312
  const payload = {
685
1313
  event_id: eventId,
686
1314
  user_id: userId,
@@ -688,12 +1316,13 @@ var EventShipper = class {
688
1316
  timestamp: (_i = accumulated.timestamp) != null ? _i : (/* @__PURE__ */ new Date()).toISOString(),
689
1317
  ai_data: {
690
1318
  input: accumulated.input,
691
- output: accumulated.output,
1319
+ output: accumulated.error !== void 0 && accumulated.error !== null ? void 0 : accumulated.output,
692
1320
  model: accumulated.model,
693
1321
  convo_id: convoId
694
1322
  },
695
1323
  properties: {
696
1324
  ...restProperties,
1325
+ ...telemetryProperties,
697
1326
  ...wizardSession ? { "raindrop.wizardSession": wizardSession } : {},
698
1327
  $context: this.context
699
1328
  },
@@ -721,29 +1350,30 @@ var EventShipper = class {
721
1350
  endpoint: url
722
1351
  });
723
1352
  }
724
- if (this.localDebuggerUrl) {
725
- mirrorPartialEventToLocalDebugger(payload, {
726
- baseUrl: this.localDebuggerUrl,
727
- writeKey: this.writeKey,
728
- debug: this.debug,
729
- sdkName: this.sdkName
730
- });
731
- }
1353
+ const mirror = this.localDebuggerUrl ? mirrorPartialEventToLocalDebugger(payload, {
1354
+ baseUrl: this.localDebuggerUrl,
1355
+ writeKey: this.writeKey,
1356
+ debug: this.debug,
1357
+ sdkName: this.sdkName
1358
+ }) : void 0;
732
1359
  if (!this.writeKey) {
733
1360
  if (!isPending) this.sticky.delete(eventId);
1361
+ if (mirror) await mirror;
734
1362
  return;
735
1363
  }
736
1364
  const opts = this.requestOpts();
737
1365
  if (!opts) {
738
1366
  this.warnShutdownDrop(`track_partial ${eventId}`);
739
1367
  if (!isPending) this.sticky.delete(eventId);
1368
+ if (mirror) await mirror;
740
1369
  return;
741
1370
  }
742
1371
  const p = postJson(url, payload, this.requestHeaders(), opts);
743
- this.inFlight.add(p);
1372
+ const combined = mirror ? Promise.all([mirror, p]).then(() => void 0) : p;
1373
+ this.inFlight.add(combined);
744
1374
  try {
745
1375
  try {
746
- await p;
1376
+ await combined;
747
1377
  if (this.debug) {
748
1378
  console.log(`${this.prefix} sent track_partial ${eventId} (${eventName})`);
749
1379
  }
@@ -755,13 +1385,156 @@ var EventShipper = class {
755
1385
  );
756
1386
  }
757
1387
  } finally {
758
- this.inFlight.delete(p);
1388
+ this.inFlight.delete(combined);
759
1389
  }
760
1390
  if (!isPending) {
761
1391
  this.sticky.delete(eventId);
762
1392
  }
763
1393
  }
764
1394
  };
1395
+ var MODEL_USAGE_ATTRIBUTES = {
1396
+ usageSource: "raindrop.usage.source",
1397
+ providerName: "gen_ai.provider.name",
1398
+ requestModel: "gen_ai.request.model",
1399
+ responseModel: "gen_ai.response.model",
1400
+ inputTokens: "gen_ai.usage.input_tokens",
1401
+ outputTokens: "gen_ai.usage.output_tokens",
1402
+ reasoningTokens: "gen_ai.usage.reasoning_tokens",
1403
+ cacheReadInputTokens: "gen_ai.usage.cache_read_input_tokens",
1404
+ cacheWriteInputTokens: "gen_ai.usage.cache_write_input_tokens",
1405
+ providerReportedCost: "gen_ai.usage.provider_reported_cost",
1406
+ nonCachedInputTokens: "raindrop.usage.input_tokens.non_cached",
1407
+ nonReasoningOutputTokens: "raindrop.usage.output_tokens.non_reasoning",
1408
+ totalOutputTokens: "raindrop.usage.output_tokens.total",
1409
+ reasoningOutputTokens: "raindrop.usage.output_tokens.reasoning",
1410
+ cacheReadTokens: "raindrop.usage.input_tokens.cache_read",
1411
+ cacheWriteTokens: "raindrop.usage.input_tokens.cache_write"
1412
+ };
1413
+ var MODEL_PROVIDER_NAMES = [
1414
+ ["google.vertex.anthropic", "google-vertex"],
1415
+ ["google.vertex_ai", "google-vertex"],
1416
+ ["google.vertex", "google-vertex"],
1417
+ ["gcp.vertex_ai", "google-vertex"],
1418
+ ["gcp.gemini", "google"],
1419
+ ["google_vertexai", "google-vertex"],
1420
+ ["vertex.anthropic", "google-vertex"],
1421
+ ["amazon-bedrock", "amazon-bedrock"],
1422
+ ["aws.bedrock", "amazon-bedrock"],
1423
+ ["bedrock", "amazon-bedrock"],
1424
+ ["anthropic", "anthropic"],
1425
+ ["openai", "openai"],
1426
+ ["google", "google"],
1427
+ ["az.ai.openai", "azure"],
1428
+ ["azure", "azure"],
1429
+ ["openrouter", "openrouter"]
1430
+ ];
1431
+ function canonicalModelProvider(provider) {
1432
+ var _a;
1433
+ const normalizedProvider = provider.trim().toLowerCase();
1434
+ if (normalizedProvider === "gateway") return "vercel";
1435
+ const match = MODEL_PROVIDER_NAMES.find(
1436
+ ([family]) => normalizedProvider === family || normalizedProvider.startsWith(`${family}.`)
1437
+ );
1438
+ return (_a = match == null ? void 0 : match[1]) != null ? _a : normalizedProvider;
1439
+ }
1440
+ var STRING_ALIASES = {
1441
+ [MODEL_USAGE_ATTRIBUTES.requestModel]: ["ai.model.id", "ai.model"]
1442
+ };
1443
+ var NUMBER_ALIASES = {
1444
+ [MODEL_USAGE_ATTRIBUTES.inputTokens]: [
1445
+ "gen_ai.usage.prompt_tokens",
1446
+ "ai.usage.prompt_tokens",
1447
+ "ai.usage.promptTokens",
1448
+ "ai.usage.input_tokens",
1449
+ "ai.usage.inputTokens"
1450
+ ],
1451
+ [MODEL_USAGE_ATTRIBUTES.outputTokens]: [
1452
+ "gen_ai.usage.completion_tokens",
1453
+ "ai.usage.completion_tokens",
1454
+ "ai.usage.completionTokens",
1455
+ "ai.usage.output_tokens",
1456
+ "ai.usage.outputTokens"
1457
+ ],
1458
+ [MODEL_USAGE_ATTRIBUTES.reasoningTokens]: [
1459
+ "gen_ai.usage.reasoning.output_tokens",
1460
+ "ai.usage.reasoningTokens",
1461
+ "ai.usage.thoughts_tokens"
1462
+ ],
1463
+ [MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens]: [
1464
+ "gen_ai.usage.cache_read_tokens",
1465
+ "gen_ai.usage.cache_read.input_tokens",
1466
+ "ai.usage.cachedInputTokens",
1467
+ "ai.usage.cached_tokens",
1468
+ "ai.usage.cache_read_tokens",
1469
+ "ai.usage.cache_read_input_tokens",
1470
+ "ai.usage.cacheReadInputTokens"
1471
+ ],
1472
+ [MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens]: [
1473
+ "gen_ai.usage.cache_creation_input_tokens",
1474
+ "gen_ai.usage.cache_creation.input_tokens",
1475
+ "ai.usage.cacheWriteInputTokens",
1476
+ "ai.usage.cache_creation_input_tokens",
1477
+ "ai.usage.cacheCreationInputTokens"
1478
+ ]
1479
+ };
1480
+ function hasAttribute(attributes, key) {
1481
+ return attributes.some((attribute) => attribute.key === key);
1482
+ }
1483
+ function findStringAttribute(attributes, keys) {
1484
+ return attributes.find(
1485
+ (attribute) => keys.includes(attribute.key) && typeof attribute.value.stringValue === "string" && attribute.value.stringValue.length > 0
1486
+ );
1487
+ }
1488
+ function findNumberAttribute(attributes, keys) {
1489
+ return attributes.find((attribute) => {
1490
+ if (!keys.includes(attribute.key)) return false;
1491
+ if (typeof attribute.value.doubleValue === "number" && Number.isSafeInteger(attribute.value.doubleValue) && attribute.value.doubleValue >= 0) {
1492
+ return true;
1493
+ }
1494
+ const intValue = attribute.value.intValue;
1495
+ return integerValue(intValue) !== void 0;
1496
+ });
1497
+ }
1498
+ function integerValue(value) {
1499
+ if (typeof value === "number") {
1500
+ return Number.isSafeInteger(value) && value >= 0 ? value : void 0;
1501
+ }
1502
+ if (typeof value !== "string") return void 0;
1503
+ const parsed = Number(value);
1504
+ return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : void 0;
1505
+ }
1506
+ function appendAlias(attributes, target, source) {
1507
+ if (!source || hasAttribute(attributes, target)) return attributes;
1508
+ return [...attributes, { key: target, value: { ...source.value } }];
1509
+ }
1510
+ function appendProviderAlias(attributes) {
1511
+ if (hasAttribute(attributes, MODEL_USAGE_ATTRIBUTES.providerName)) return attributes;
1512
+ const source = findStringAttribute(attributes, ["gen_ai.system", "ai.model.provider"]);
1513
+ if (!(source == null ? void 0 : source.value.stringValue)) return attributes;
1514
+ const attribute = attrString(
1515
+ MODEL_USAGE_ATTRIBUTES.providerName,
1516
+ canonicalModelProvider(source.value.stringValue)
1517
+ );
1518
+ return attribute ? [...attributes, attribute] : attributes;
1519
+ }
1520
+ function normalizeModelUsageSpan(span) {
1521
+ const original = span.attributes;
1522
+ if (!original || original.length === 0) return span;
1523
+ const responseModel = findStringAttribute(original, [
1524
+ MODEL_USAGE_ATTRIBUTES.responseModel,
1525
+ "ai.response.model"
1526
+ ]);
1527
+ if (!responseModel) return span;
1528
+ let attributes = appendAlias(original, MODEL_USAGE_ATTRIBUTES.responseModel, responseModel);
1529
+ attributes = appendProviderAlias(attributes);
1530
+ for (const [target, aliases] of Object.entries(STRING_ALIASES)) {
1531
+ attributes = appendAlias(attributes, target, findStringAttribute(attributes, aliases));
1532
+ }
1533
+ for (const [target, aliases] of Object.entries(NUMBER_ALIASES)) {
1534
+ attributes = appendAlias(attributes, target, findNumberAttribute(attributes, aliases));
1535
+ }
1536
+ return attributes === original ? span : { ...span, attributes };
1537
+ }
765
1538
  var DEFAULT_SECRET_KEY_NAMES = [
766
1539
  "apikey",
767
1540
  "apisecret",
@@ -851,6 +1624,20 @@ function redactJsonAttributeValue(key, value) {
851
1624
  if (scrubbedJson === json) return void 0;
852
1625
  return { stringValue: scrubbedJson };
853
1626
  }
1627
+ function appGitOwnerId2(prefix) {
1628
+ try {
1629
+ return `${prefix}:${randomUUID()}`;
1630
+ } catch (e) {
1631
+ return `${prefix}:${Date.now().toString(36)}:${Math.random().toString(36).slice(2)}`;
1632
+ }
1633
+ }
1634
+ function identityAttrs(args) {
1635
+ return [
1636
+ attrString("ai.telemetry.metadata.raindrop.ai.userId", args.userId),
1637
+ attrString("ai.telemetry.metadata.raindrop.convoId", args.convoId),
1638
+ attrString("ai.telemetry.metadata.raindrop.eventName", args.eventName)
1639
+ ];
1640
+ }
854
1641
  function applyOtelSpanAttributeLimit(limit) {
855
1642
  var _a, _b;
856
1643
  try {
@@ -866,23 +1653,30 @@ function applyOtelSpanAttributeLimit(limit) {
866
1653
  }
867
1654
  var TraceShipper = class {
868
1655
  constructor(opts) {
1656
+ this.appGitOwner = appGitOwnerId2("trace");
1657
+ this.appGitEventIds = /* @__PURE__ */ new WeakMap();
1658
+ this.appGitActiveSpans = /* @__PURE__ */ new Map();
1659
+ this.appGitCaptured = /* @__PURE__ */ new WeakSet();
1660
+ this.appGitAdded = /* @__PURE__ */ new WeakMap();
869
1661
  this.queue = [];
870
1662
  this.inFlight = /* @__PURE__ */ new Set();
871
1663
  this.hasShutdown = false;
872
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
873
- this.writeKey = (_a = opts.writeKey) == null ? void 0 : _a.trim();
874
- this.baseUrl = (_b = formatEndpoint(opts.endpoint)) != null ? _b : "https://api.raindrop.ai/v1/";
1664
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
1665
+ this.appGitContext = (_a = opts.appGitContext) != null ? _a : createAppGitContext(opts.appGit);
1666
+ this.ownsAppGitContext = opts.appGitContext === void 0;
1667
+ this.writeKey = (_b = opts.writeKey) == null ? void 0 : _b.trim();
1668
+ this.baseUrl = (_c = formatEndpoint(opts.endpoint)) != null ? _c : "https://api.raindrop.ai/v1/";
875
1669
  this.enabled = opts.enabled !== false;
876
1670
  this.debug = opts.debug;
877
1671
  this.debugSpans = opts.debugSpans === true;
878
- this.flushIntervalMs = (_c = opts.flushIntervalMs) != null ? _c : 1e3;
879
- this.maxBatchSize = (_d = opts.maxBatchSize) != null ? _d : 50;
880
- this.maxQueueSize = (_e = opts.maxQueueSize) != null ? _e : 5e3;
881
- this.sdkName = (_f = opts.sdkName) != null ? _f : "core";
1672
+ this.flushIntervalMs = (_d = opts.flushIntervalMs) != null ? _d : 1e3;
1673
+ this.maxBatchSize = (_e = opts.maxBatchSize) != null ? _e : 50;
1674
+ this.maxQueueSize = (_f = opts.maxQueueSize) != null ? _f : 5e3;
1675
+ this.sdkName = (_g = opts.sdkName) != null ? _g : "core";
882
1676
  this.prefix = `[raindrop-ai/${this.sdkName}]`;
883
- this.serviceName = (_g = opts.serviceName) != null ? _g : "raindrop.core";
884
- this.serviceVersion = (_h = opts.serviceVersion) != null ? _h : "0.0.0";
885
- this.localDebuggerUrl = (_i = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _i : void 0;
1677
+ this.serviceName = (_h = opts.serviceName) != null ? _h : "raindrop.core";
1678
+ this.serviceVersion = (_i = opts.serviceVersion) != null ? _i : "0.0.0";
1679
+ this.localDebuggerUrl = (_j = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _j : void 0;
886
1680
  if (this.debug && this.localDebuggerUrl) {
887
1681
  console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
888
1682
  }
@@ -946,7 +1740,10 @@ var TraceShipper = class {
946
1740
  try {
947
1741
  const result = this.transformSpanHook(current);
948
1742
  if (result === null) return null;
949
- if (result !== void 0) current = result;
1743
+ if (result !== void 0) {
1744
+ copyReplayTraceDestination(current, result);
1745
+ current = result;
1746
+ }
950
1747
  } catch (err) {
951
1748
  if (this.debug) {
952
1749
  const msg = err instanceof Error ? err.message : String(err);
@@ -955,10 +1752,20 @@ var TraceShipper = class {
955
1752
  return null;
956
1753
  }
957
1754
  }
1755
+ try {
1756
+ const normalized = normalizeModelUsageSpan(current);
1757
+ copyReplayTraceDestination(current, normalized);
1758
+ current = normalized;
1759
+ } catch (e) {
1760
+ }
958
1761
  if (!this.disableDefaultRedaction) {
959
- current = defaultTransformSpan(current);
1762
+ const redacted = defaultTransformSpan(current);
1763
+ copyReplayTraceDestination(current, redacted);
1764
+ current = redacted;
960
1765
  }
961
- return this.capSpanAttributes(current);
1766
+ const capped = this.capSpanAttributes(current);
1767
+ copyReplayTraceDestination(current, capped);
1768
+ return capped;
962
1769
  }
963
1770
  isDebugEnabled() {
964
1771
  return this.debug;
@@ -970,45 +1777,84 @@ var TraceShipper = class {
970
1777
  return { ...this.authHeaders(), ...projectIdHeaders(this.projectId) };
971
1778
  }
972
1779
  startSpan(args) {
973
- var _a, _b;
1780
+ var _a, _b, _c;
974
1781
  const ids = createSpanIds(args.parent);
975
1782
  const started = (_a = args.startTimeUnixNano) != null ? _a : nowUnixNanoString();
976
1783
  const attrs = [
977
1784
  attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId),
978
- attrString("ai.operationId", args.operationId)
1785
+ ...identityAttrs(args),
1786
+ attrString("ai.operationId", args.operationId),
1787
+ ...Object.entries(evalScopeAttributes()).map(([key, value]) => attrString(key, value))
979
1788
  ];
980
1789
  if ((_b = args.attributes) == null ? void 0 : _b.length) attrs.push(...args.attributes);
981
- const span = { ids, name: args.name, startTimeUnixNano: started, attributes: attrs };
982
- this.mirrorToLocalDebugger(
983
- buildOtlpSpan({
984
- ids: span.ids,
985
- name: span.name,
986
- startTimeUnixNano: span.startTimeUnixNano,
987
- endTimeUnixNano: span.startTimeUnixNano,
988
- // placeholder — will be updated on endSpan
989
- attributes: span.attributes,
990
- status: { code: SpanStatusCode.UNSET }
991
- })
992
- );
1790
+ const tracksAppGit = this.appGitActiveSpans.has(args.eventId) || this.appGitActiveSpans.size < 1e4;
1791
+ const appGitOverrides = appGitPropertiesFromAttributes(attrs);
1792
+ const span = {
1793
+ ids,
1794
+ name: args.name,
1795
+ startTimeUnixNano: started,
1796
+ attributes: withAppGitAttributes(
1797
+ attrs,
1798
+ this.appGitContext.forOperation(args.eventId, appGitOverrides, this.appGitOwner)
1799
+ )
1800
+ };
1801
+ rememberReplayTraceDestination(span);
1802
+ this.appGitCaptured.add(span);
1803
+ this.appGitEventIds.set(span, args.eventId);
1804
+ if (tracksAppGit) {
1805
+ this.appGitActiveSpans.set(args.eventId, ((_c = this.appGitActiveSpans.get(args.eventId)) != null ? _c : 0) + 1);
1806
+ }
1807
+ this.appGitAdded.set(span, new Set(span.attributes.filter((attr) => !attrs.includes(attr))));
1808
+ const openSpan = buildOtlpSpan({
1809
+ ids: span.ids,
1810
+ name: span.name,
1811
+ startTimeUnixNano: span.startTimeUnixNano,
1812
+ endTimeUnixNano: span.startTimeUnixNano,
1813
+ // placeholder — will be updated on endSpan
1814
+ attributes: span.attributes,
1815
+ status: { code: SpanStatusCode.UNSET }
1816
+ });
1817
+ copyReplayTraceDestination(span, openSpan);
1818
+ this.mirrorToLocalDebugger(openSpan);
993
1819
  return span;
994
1820
  }
995
- mirrorToLocalDebugger(span) {
996
- if (!this.localDebuggerUrl) return;
1821
+ mirrorToLocalDebugger(span, completed = false) {
1822
+ const destination = replayTraceDestinationFor(span);
1823
+ if (destination && destination.kind !== "workshop") return;
1824
+ const localDebuggerUrl = (destination == null ? void 0 : destination.kind) === "workshop" ? destination.url : this.localDebuggerUrl;
1825
+ if (!localDebuggerUrl) return;
997
1826
  const redacted = this.redactSpan(span);
998
1827
  if (redacted === null) return;
1828
+ if (completed && (destination == null ? void 0 : destination.kind) === "workshop") {
1829
+ recordReplayExportedSpan(
1830
+ destination,
1831
+ base64ToHex(redacted.spanId),
1832
+ base64ToHex(redacted.traceId)
1833
+ );
1834
+ }
999
1835
  const body = buildExportTraceServiceRequest([redacted], this.serviceName, this.serviceVersion);
1000
- mirrorTraceExportToLocalDebugger(body, {
1001
- baseUrl: this.localDebuggerUrl,
1836
+ const p = mirrorTraceExportToLocalDebugger(body, {
1837
+ baseUrl: localDebuggerUrl,
1002
1838
  debug: false,
1003
1839
  sdkName: this.sdkName
1004
1840
  });
1841
+ this.inFlight.add(p);
1842
+ void p.finally(() => {
1843
+ this.inFlight.delete(p);
1844
+ });
1005
1845
  }
1006
1846
  endSpan(span, extra) {
1007
- var _a, _b;
1847
+ var _a, _b, _c;
1008
1848
  if (span.endTimeUnixNano) return;
1009
1849
  span.endTimeUnixNano = (_a = extra == null ? void 0 : extra.endTimeUnixNano) != null ? _a : nowUnixNanoString();
1010
1850
  if ((_b = extra == null ? void 0 : extra.attributes) == null ? void 0 : _b.length) {
1851
+ const overrides = appGitPropertiesFromAttributes(extra.attributes);
1852
+ const eventId2 = this.appGitEventIds.get(span);
1853
+ const snapshot = eventId2 ? this.appGitContext.forOperation(eventId2, overrides, this.appGitOwner) : overrides;
1854
+ const added = this.appGitAdded.get(span);
1855
+ 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));
1011
1856
  span.attributes.push(...extra.attributes);
1857
+ span.attributes = withAppGitAttributes(span.attributes, snapshot);
1012
1858
  }
1013
1859
  let status = extra == null ? void 0 : extra.status;
1014
1860
  if (!status && (extra == null ? void 0 : extra.error) !== void 0) {
@@ -1023,29 +1869,65 @@ var TraceShipper = class {
1023
1869
  attributes: span.attributes,
1024
1870
  status
1025
1871
  });
1872
+ copyReplayTraceDestination(span, otlp);
1873
+ this.appGitCaptured.add(otlp);
1026
1874
  this.enqueue(otlp);
1027
- this.mirrorToLocalDebugger(otlp);
1875
+ this.mirrorToLocalDebugger(otlp, true);
1876
+ const eventId = this.appGitEventIds.get(span);
1877
+ if (eventId && this.appGitActiveSpans.has(eventId)) {
1878
+ const remaining = ((_c = this.appGitActiveSpans.get(eventId)) != null ? _c : 1) - 1;
1879
+ if (remaining > 0) this.appGitActiveSpans.set(eventId, remaining);
1880
+ else {
1881
+ this.appGitActiveSpans.delete(eventId);
1882
+ if (this.appGitContext.releaseOperation) this.appGitContext.releaseOperation(eventId, this.appGitOwner);
1883
+ else if (this.ownsAppGitContext) this.appGitContext.finishOperation(eventId);
1884
+ }
1885
+ }
1028
1886
  }
1029
1887
  createSpan(args) {
1030
1888
  var _a;
1031
1889
  const ids = createSpanIds(args.parent);
1032
1890
  const attrs = [
1033
- attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId)
1891
+ attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId),
1892
+ ...identityAttrs(args),
1893
+ ...Object.entries(evalScopeAttributes()).map(([key, value]) => attrString(key, value))
1034
1894
  ];
1035
1895
  if ((_a = args.attributes) == null ? void 0 : _a.length) attrs.push(...args.attributes);
1896
+ const tracksAppGit = !this.appGitActiveSpans.has(args.eventId);
1036
1897
  const otlp = buildOtlpSpan({
1037
1898
  ids,
1038
1899
  name: args.name,
1039
1900
  startTimeUnixNano: args.startTimeUnixNano,
1040
1901
  endTimeUnixNano: args.endTimeUnixNano,
1041
- attributes: attrs,
1902
+ attributes: withAppGitAttributes(
1903
+ attrs,
1904
+ this.appGitContext.forOperation(
1905
+ args.eventId,
1906
+ appGitPropertiesFromAttributes(attrs),
1907
+ this.appGitOwner
1908
+ )
1909
+ ),
1042
1910
  status: args.status
1043
1911
  });
1912
+ rememberReplayTraceDestination(otlp);
1913
+ this.appGitCaptured.add(otlp);
1914
+ if (tracksAppGit) {
1915
+ if (this.appGitContext.releaseOperation) this.appGitContext.releaseOperation(args.eventId, this.appGitOwner);
1916
+ else if (this.ownsAppGitContext) this.appGitContext.finishOperation(args.eventId);
1917
+ }
1044
1918
  this.enqueue(otlp);
1045
- this.mirrorToLocalDebugger(otlp);
1919
+ this.mirrorToLocalDebugger(otlp, true);
1046
1920
  }
1047
1921
  enqueue(span) {
1922
+ var _a;
1048
1923
  if (!this.enabled) return;
1924
+ const attributes = (_a = span.attributes) != null ? _a : [];
1925
+ const enriched = this.appGitCaptured.has(span) ? attributes : withAppGitAttributes(attributes, this.appGitContext.snapshot(appGitPropertiesFromAttributes(attributes)));
1926
+ if (enriched !== attributes) {
1927
+ const original = span;
1928
+ span = { ...span, attributes: enriched.filter((attr) => attr !== void 0) };
1929
+ copyReplayTraceDestination(original, span);
1930
+ }
1049
1931
  if (this.debugSpans) {
1050
1932
  const short = (s) => s ? s.slice(-8) : "none";
1051
1933
  console.log(
@@ -1056,6 +1938,13 @@ var TraceShipper = class {
1056
1938
  }
1057
1939
  const redacted = this.redactSpan(span);
1058
1940
  if (redacted === null) return;
1941
+ const destination = replayTraceDestinationFor(redacted);
1942
+ recordReplayExportedSpan(
1943
+ destination,
1944
+ base64ToHex(redacted.spanId),
1945
+ base64ToHex(redacted.traceId)
1946
+ );
1947
+ if ((destination == null ? void 0 : destination.kind) === "workshop") return;
1059
1948
  if (this.queue.length >= this.maxQueueSize) {
1060
1949
  this.queue.shift();
1061
1950
  }
@@ -1074,47 +1963,67 @@ var TraceShipper = class {
1074
1963
  }
1075
1964
  }
1076
1965
  async flush() {
1077
- if (!this.enabled) return;
1966
+ var _a;
1967
+ if (!this.enabled) {
1968
+ await Promise.all([...this.inFlight].map((p) => p.catch(() => {
1969
+ })));
1970
+ return;
1971
+ }
1078
1972
  if (this.timer) {
1079
1973
  clearTimeout(this.timer);
1080
1974
  this.timer = void 0;
1081
1975
  }
1082
1976
  while (this.queue.length > 0) {
1083
1977
  const batch = this.queue.splice(0, this.maxBatchSize);
1084
- if (!this.writeKey) continue;
1085
- const opts = this.requestOpts();
1086
- if (!opts) {
1087
- rateLimitedLog(
1088
- `${this.prefix}.shutdown_deadline`,
1089
- () => console.warn(
1090
- `${this.prefix} shutdown flush deadline exceeded; dropping ${batch.length} spans`
1091
- )
1092
- );
1093
- continue;
1094
- }
1095
- const body = buildExportTraceServiceRequest(batch, this.serviceName, this.serviceVersion);
1096
- const url = `${this.baseUrl}traces`;
1097
- if (this.debug) {
1098
- console.log(`${this.prefix} sending traces batch`, {
1099
- spans: batch.length,
1100
- endpoint: url
1101
- });
1978
+ const groups = /* @__PURE__ */ new Map();
1979
+ for (const span of batch) {
1980
+ const destination = replayTraceDestinationFor(span);
1981
+ const spans = groups.get(destination);
1982
+ if (spans) spans.push(span);
1983
+ else groups.set(destination, [span]);
1102
1984
  }
1103
- const p = postJson(url, body, this.requestHeaders(), opts);
1104
- this.inFlight.add(p);
1105
- try {
1106
- try {
1107
- await p;
1108
- if (this.debug) console.log(`${this.prefix} sent ${batch.length} spans`);
1109
- } catch (err) {
1110
- const msg = err instanceof Error ? err.message : String(err);
1985
+ for (const [destination, spans] of groups) {
1986
+ if (!destination && !this.writeKey) continue;
1987
+ if ((destination == null ? void 0 : destination.kind) === "workshop") continue;
1988
+ const opts = this.requestOpts();
1989
+ if (!opts) {
1111
1990
  rateLimitedLog(
1112
- `${this.prefix}.send_spans_failed`,
1113
- () => console.warn(`${this.prefix} failed to send ${batch.length} spans: ${msg}`)
1991
+ `${this.prefix}.shutdown_deadline`,
1992
+ () => console.warn(
1993
+ `${this.prefix} shutdown flush deadline exceeded; dropping ${spans.length} spans`
1994
+ )
1114
1995
  );
1996
+ continue;
1997
+ }
1998
+ const body = buildExportTraceServiceRequest(spans, this.serviceName, this.serviceVersion);
1999
+ const url = destination ? replayTraceUrl(destination.url) : `${this.baseUrl}traces`;
2000
+ const headers = destination ? {
2001
+ Authorization: `Bearer ${destination.apiKey}`,
2002
+ "X-Raindrop-Replay-Id": destination.replayId,
2003
+ "X-Raindrop-Project-Id": (_a = destination.projectId) != null ? _a : "default"
2004
+ } : this.requestHeaders();
2005
+ if (this.debug) {
2006
+ console.log(`${this.prefix} sending traces batch`, {
2007
+ spans: spans.length,
2008
+ endpoint: url
2009
+ });
2010
+ }
2011
+ const p = postJson(url, body, headers, opts);
2012
+ this.inFlight.add(p);
2013
+ try {
2014
+ try {
2015
+ await p;
2016
+ if (this.debug) console.log(`${this.prefix} sent ${spans.length} spans`);
2017
+ } catch (err) {
2018
+ const msg = err instanceof Error ? err.message : String(err);
2019
+ rateLimitedLog(
2020
+ `${this.prefix}.send_spans_failed`,
2021
+ () => console.warn(`${this.prefix} failed to send ${spans.length} spans: ${msg}`)
2022
+ );
2023
+ }
2024
+ } finally {
2025
+ this.inFlight.delete(p);
1115
2026
  }
1116
- } finally {
1117
- this.inFlight.delete(p);
1118
2027
  }
1119
2028
  }
1120
2029
  }
@@ -1157,17 +2066,165 @@ var TraceShipper = class {
1157
2066
  if (!settled) {
1158
2067
  rateLimitedLog(
1159
2068
  `${this.prefix}.shutdown_deadline`,
1160
- () => console.warn(`${this.prefix} shutdown flush deadline exceeded; abandoning in-flight spans`)
2069
+ () => console.warn(
2070
+ `${this.prefix} shutdown flush deadline exceeded; abandoning in-flight spans`
2071
+ )
1161
2072
  );
1162
2073
  }
1163
2074
  } finally {
1164
2075
  this.shutdownDeadlineAt = void 0;
2076
+ if (this.ownsAppGitContext) this.appGitContext.dispose();
1165
2077
  }
1166
2078
  }
1167
2079
  };
1168
2080
 
1169
2081
  // ../core/dist/index.node.js
1170
2082
  var import_async_hooks = require("async_hooks");
2083
+ var import_child_process = require("child_process");
2084
+ var import_path = require("path");
2085
+ var resolveLocal = (sourceDirectory, detectBranch, completed) => {
2086
+ const cwd = sourceDirectory ? (0, import_path.resolve)(sourceDirectory) : process.cwd();
2087
+ let cancelled = false;
2088
+ let active;
2089
+ let deadlineTimer;
2090
+ const deadline = Date.now() + 1e3;
2091
+ const run = (args, done) => {
2092
+ if (cancelled) return;
2093
+ const remaining = deadline - Date.now();
2094
+ if (remaining <= 0) {
2095
+ done(void 0);
2096
+ return;
2097
+ }
2098
+ try {
2099
+ active = (0, import_child_process.execFile)(
2100
+ "git",
2101
+ args,
2102
+ {
2103
+ cwd,
2104
+ encoding: "utf8",
2105
+ maxBuffer: 4096,
2106
+ windowsHide: true,
2107
+ env: {
2108
+ ...process.env,
2109
+ // The selected application cwd, not the invoking shell's Git plumbing, owns identity.
2110
+ GIT_DIR: void 0,
2111
+ GIT_WORK_TREE: void 0,
2112
+ GIT_COMMON_DIR: void 0,
2113
+ GIT_NAMESPACE: void 0,
2114
+ GIT_INDEX_FILE: void 0,
2115
+ GIT_OBJECT_DIRECTORY: void 0,
2116
+ GIT_ALTERNATE_OBJECT_DIRECTORIES: void 0,
2117
+ GIT_CONFIG_PARAMETERS: void 0,
2118
+ GIT_CONFIG_COUNT: "0",
2119
+ GIT_TERMINAL_PROMPT: "0",
2120
+ GIT_OPTIONAL_LOCKS: "0"
2121
+ }
2122
+ },
2123
+ (error, stdout) => {
2124
+ clearTimeout(deadlineTimer);
2125
+ deadlineTimer = void 0;
2126
+ active = void 0;
2127
+ if (!cancelled) {
2128
+ try {
2129
+ done(error ? void 0 : stdout.trim());
2130
+ } catch (e) {
2131
+ }
2132
+ }
2133
+ }
2134
+ );
2135
+ active.unref();
2136
+ if (active.stdout && "unref" in active.stdout && typeof active.stdout.unref === "function")
2137
+ active.stdout.unref();
2138
+ if (active.stderr && "unref" in active.stderr && typeof active.stderr.unref === "function")
2139
+ active.stderr.unref();
2140
+ deadlineTimer = setTimeout(() => {
2141
+ try {
2142
+ active == null ? void 0 : active.kill("SIGKILL");
2143
+ } catch (e) {
2144
+ }
2145
+ }, remaining);
2146
+ deadlineTimer.unref();
2147
+ } catch (e) {
2148
+ try {
2149
+ done(void 0);
2150
+ } catch (e2) {
2151
+ }
2152
+ }
2153
+ };
2154
+ const scheduled = setTimeout(() => {
2155
+ try {
2156
+ run(["rev-parse", "HEAD"], (rawSha) => {
2157
+ const commitSha = validAppCommitSha(rawSha);
2158
+ if (!commitSha) {
2159
+ completed({});
2160
+ return;
2161
+ }
2162
+ run(["-c", "core.fsmonitor=false", "status", "--porcelain"], (status) => {
2163
+ const finish = (branch) => {
2164
+ run(["rev-parse", "HEAD"], (finalSha) => {
2165
+ const coherent = validAppCommitSha(finalSha) === commitSha;
2166
+ completed({
2167
+ commitSha,
2168
+ ...coherent && status !== void 0 ? { commitDirty: status !== "" } : {},
2169
+ ...coherent && branch && branch !== "HEAD" ? { branch } : {}
2170
+ });
2171
+ });
2172
+ };
2173
+ if (detectBranch) run(["symbolic-ref", "--quiet", "--short", "HEAD"], finish);
2174
+ else finish();
2175
+ });
2176
+ });
2177
+ } catch (e) {
2178
+ completed({});
2179
+ }
2180
+ }, 0);
2181
+ scheduled.unref();
2182
+ return () => {
2183
+ cancelled = true;
2184
+ clearTimeout(scheduled);
2185
+ clearTimeout(deadlineTimer);
2186
+ try {
2187
+ active == null ? void 0 : active.kill("SIGKILL");
2188
+ } catch (e) {
2189
+ }
2190
+ };
2191
+ };
2192
+ function createAppGitContext2(options, runtime = {}) {
2193
+ return new AppGitContext(options, { ...runtime, resolveLocal });
2194
+ }
2195
+ function hasDestination(options) {
2196
+ var _a;
2197
+ if (options.enabled === false) return false;
2198
+ return Boolean(((_a = options.writeKey) == null ? void 0 : _a.trim()) || resolveLocalDebuggerBaseUrl(options.localDebuggerUrl));
2199
+ }
2200
+ var EventShipper2 = class extends EventShipper {
2201
+ constructor(options) {
2202
+ var _a;
2203
+ const ownsAppGitContext = options.appGitContext === void 0;
2204
+ const appGitContext = (_a = options.appGitContext) != null ? _a : createAppGitContext2(options.appGit, { allowDiscovery: hasDestination(options) });
2205
+ try {
2206
+ super({ ...options, appGitContext });
2207
+ } catch (error) {
2208
+ if (ownsAppGitContext) appGitContext.dispose();
2209
+ throw error;
2210
+ }
2211
+ if (ownsAppGitContext) this.ownAppGitContextForShutdown();
2212
+ }
2213
+ };
2214
+ var TraceShipper2 = class extends TraceShipper {
2215
+ constructor(options) {
2216
+ var _a;
2217
+ const ownsAppGitContext = options.appGitContext === void 0;
2218
+ const appGitContext = (_a = options.appGitContext) != null ? _a : createAppGitContext2(options.appGit, { allowDiscovery: hasDestination(options) });
2219
+ try {
2220
+ super({ ...options, appGitContext });
2221
+ } catch (error) {
2222
+ if (ownsAppGitContext) appGitContext.dispose();
2223
+ throw error;
2224
+ }
2225
+ this.ownsAppGitContext = ownsAppGitContext;
2226
+ }
2227
+ };
1171
2228
  globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = import_async_hooks.AsyncLocalStorage;
1172
2229
  var SUPPRESS_TRACING_KEY = /* @__PURE__ */ Symbol.for(
1173
2230
  "OpenTelemetry SDK Context Key SUPPRESS_TRACING"
@@ -1309,6 +2366,10 @@ var RaindropDeepAgentsHandler = class extends import_base.BaseCallbackHandler {
1309
2366
  });
1310
2367
  }
1311
2368
  }
2369
+ rootErrorPatch(runId, error) {
2370
+ const rootId = this.rootRunIds.get(runId) ?? runId;
2371
+ return rootId === runId ? { error } : void 0;
2372
+ }
1312
2373
  // ---------------------------------------------------------------------------
1313
2374
  // LLM events
1314
2375
  // ---------------------------------------------------------------------------
@@ -1404,8 +2465,6 @@ var RaindropDeepAgentsHandler = class extends import_base.BaseCallbackHandler {
1404
2465
  ]
1405
2466
  });
1406
2467
  const properties = {};
1407
- if (promptTokens != null) properties["ai.usage.prompt_tokens"] = promptTokens;
1408
- if (completionTokens != null) properties["ai.usage.completion_tokens"] = completionTokens;
1409
2468
  if (cachedTokens != null) properties["ai.usage.cached_tokens"] = cachedTokens;
1410
2469
  if (reasoningTokens != null) properties["ai.usage.thoughts_tokens"] = reasoningTokens;
1411
2470
  if (finishReason != null) properties["ai.finish_reason"] = finishReason;
@@ -1413,6 +2472,7 @@ var RaindropDeepAgentsHandler = class extends import_base.BaseCallbackHandler {
1413
2472
  await this.finalizeEventIfRoot(runId, {
1414
2473
  output: cappedOutput,
1415
2474
  model,
2475
+ usage: { promptTokens, completionTokens },
1416
2476
  properties: Object.keys(properties).length > 0 ? properties : void 0
1417
2477
  });
1418
2478
  } catch {
@@ -1430,14 +2490,7 @@ var RaindropDeepAgentsHandler = class extends import_base.BaseCallbackHandler {
1430
2490
  if (span) {
1431
2491
  this.traceShipper.endSpan(span, { error: err });
1432
2492
  }
1433
- const errorInfo = extractErrorInfo(err);
1434
- await this.finalizeEventIfRoot(runId, {
1435
- output: `[Error] ${errorInfo.type}: ${errorInfo.message}`,
1436
- properties: {
1437
- "error.type": errorInfo.type,
1438
- "error.message": errorInfo.message
1439
- }
1440
- });
2493
+ await this.finalizeEventIfRoot(runId, this.rootErrorPatch(runId, err));
1441
2494
  } catch {
1442
2495
  } finally {
1443
2496
  this.cleanup(runId);
@@ -1499,14 +2552,7 @@ var RaindropDeepAgentsHandler = class extends import_base.BaseCallbackHandler {
1499
2552
  const span = this.spans.get(runId);
1500
2553
  if (span) this.traceShipper.endSpan(span, { error: err });
1501
2554
  }
1502
- const errorInfo = extractErrorInfo(err);
1503
- await this.finalizeEventIfRoot(runId, {
1504
- output: `[Error] ${errorInfo.type}: ${errorInfo.message}`,
1505
- properties: {
1506
- "error.type": errorInfo.type,
1507
- "error.message": errorInfo.message
1508
- }
1509
- });
2555
+ await this.finalizeEventIfRoot(runId, this.rootErrorPatch(runId, err));
1510
2556
  } catch {
1511
2557
  } finally {
1512
2558
  this.cleanup(runId);
@@ -1561,14 +2607,7 @@ var RaindropDeepAgentsHandler = class extends import_base.BaseCallbackHandler {
1561
2607
  try {
1562
2608
  const span = this.spans.get(runId);
1563
2609
  if (span) this.traceShipper.endSpan(span, { error: err });
1564
- const errorInfo = extractErrorInfo(err);
1565
- await this.finalizeEventIfRoot(runId, {
1566
- output: `[Error] ${errorInfo.type}: ${errorInfo.message}`,
1567
- properties: {
1568
- "error.type": errorInfo.type,
1569
- "error.message": errorInfo.message
1570
- }
1571
- });
2610
+ await this.finalizeEventIfRoot(runId, this.rootErrorPatch(runId, err));
1572
2611
  } catch {
1573
2612
  } finally {
1574
2613
  this.cleanup(runId);
@@ -1733,22 +2772,78 @@ function asNumber(val) {
1733
2772
  const n = typeof val === "number" ? val : Number(val);
1734
2773
  return Number.isFinite(n) ? n : void 0;
1735
2774
  }
1736
- function extractErrorInfo(err) {
1737
- if (err instanceof Error) {
1738
- return { type: err.name || err.constructor.name, message: err.message };
1739
- }
1740
- if (typeof err === "object" && err !== null) {
1741
- const e = err;
1742
- const type = e.name ?? e.constructor?.name ?? "Error";
1743
- const message = e.message ?? safeStringify(err);
1744
- return { type, message };
2775
+
2776
+ // package.json
2777
+ var package_default = {
2778
+ name: "@raindrop-ai/deep-agents",
2779
+ version: "0.1.2",
2780
+ description: "Raindrop integration for LangChain Deep Agents",
2781
+ main: "dist/index.js",
2782
+ module: "dist/index.mjs",
2783
+ types: "dist/index.d.ts",
2784
+ license: "MIT",
2785
+ homepage: "https://www.raindrop.ai/docs/integrations/deepagents/",
2786
+ bugs: {
2787
+ url: "https://www.raindrop.ai/docs/support/"
2788
+ },
2789
+ exports: {
2790
+ ".": {
2791
+ types: "./dist/index.d.ts",
2792
+ import: "./dist/index.mjs",
2793
+ require: "./dist/index.js"
2794
+ }
2795
+ },
2796
+ sideEffects: false,
2797
+ files: [
2798
+ "dist/**"
2799
+ ],
2800
+ scripts: {
2801
+ build: "tsup",
2802
+ dev: "tsup --watch",
2803
+ clean: "rm -rf dist",
2804
+ test: "vitest run"
2805
+ },
2806
+ peerDependencies: {
2807
+ "@langchain/core": ">=0.3.0",
2808
+ deepagents: ">=0.5.0"
2809
+ },
2810
+ devDependencies: {
2811
+ "@langchain/anthropic": "~0.3.34",
2812
+ "@langchain/core": ">=0.3.0",
2813
+ "@langchain/openai": "~0.3.17",
2814
+ "@raindrop-ai/core": "workspace:*",
2815
+ "@types/node": "^20.11.17",
2816
+ deepagents: "1.0.0",
2817
+ msw: "^2.12.7",
2818
+ tsup: "^8.4.0",
2819
+ typescript: "^5.3.3",
2820
+ vitest: "^2.1.9",
2821
+ zod: "^3.23.0"
2822
+ },
2823
+ tsup: {
2824
+ entry: [
2825
+ "src/index.ts"
2826
+ ],
2827
+ format: [
2828
+ "cjs",
2829
+ "esm"
2830
+ ],
2831
+ dts: {
2832
+ resolve: true
2833
+ },
2834
+ clean: true,
2835
+ noExternal: [
2836
+ "@raindrop-ai/core"
2837
+ ]
2838
+ },
2839
+ publishConfig: {
2840
+ access: "public"
1745
2841
  }
1746
- return { type: "Error", message: String(err) };
1747
- }
2842
+ };
1748
2843
 
1749
2844
  // src/version.ts
1750
- var libraryName = "@raindrop-ai/deep-agents";
1751
- var libraryVersion = "0.0.1";
2845
+ var libraryName = package_default.name;
2846
+ var libraryVersion = package_default.version;
1752
2847
 
1753
2848
  // src/index.ts
1754
2849
  function createRaindropDeepAgents(opts) {
@@ -1759,7 +2854,8 @@ function createRaindropDeepAgents(opts) {
1759
2854
  "[raindrop-ai/deep-agents] writeKey not provided; telemetry shipping is disabled"
1760
2855
  );
1761
2856
  }
1762
- const eventShipper = new EventShipper({
2857
+ const appGitContext = createAppGitContext2(writeKey?.trim() ? opts.appGit : false, { allowLocalGit: true });
2858
+ const eventShipper = new EventShipper2({
1763
2859
  writeKey,
1764
2860
  endpoint: opts.endpoint,
1765
2861
  enabled,
@@ -1767,9 +2863,10 @@ function createRaindropDeepAgents(opts) {
1767
2863
  projectId: opts.projectId,
1768
2864
  sdkName: "deep-agents",
1769
2865
  libraryName,
1770
- libraryVersion
2866
+ libraryVersion,
2867
+ appGitContext
1771
2868
  });
1772
- const traceShipper = new TraceShipper({
2869
+ const traceShipper = new TraceShipper2({
1773
2870
  writeKey,
1774
2871
  endpoint: opts.endpoint,
1775
2872
  enabled,
@@ -1777,7 +2874,8 @@ function createRaindropDeepAgents(opts) {
1777
2874
  projectId: opts.projectId,
1778
2875
  sdkName: "deep-agents",
1779
2876
  serviceName: "raindrop.deep-agents",
1780
- serviceVersion: libraryVersion
2877
+ serviceVersion: libraryVersion,
2878
+ appGitContext
1781
2879
  });
1782
2880
  const handler = new RaindropDeepAgentsHandler({
1783
2881
  eventShipper,
@@ -1797,7 +2895,14 @@ function createRaindropDeepAgents(opts) {
1797
2895
  await Promise.all([eventShipper.flush(), traceShipper.flush()]);
1798
2896
  },
1799
2897
  async shutdown() {
1800
- await Promise.all([eventShipper.shutdown(), traceShipper.shutdown()]);
2898
+ try {
2899
+ await Promise.all([eventShipper.shutdown(), traceShipper.shutdown()]);
2900
+ } finally {
2901
+ try {
2902
+ appGitContext.dispose();
2903
+ } catch {
2904
+ }
2905
+ }
1801
2906
  },
1802
2907
  events: {
1803
2908
  async patch(eventId, patch) {