@raindrop-ai/opencode-plugin 0.1.4 → 0.2.0

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
@@ -1,2545 +1,22 @@
1
- // ../core/dist/chunk-BYBMRLZM.js
2
- var EVAL_CORRELATION_ID_ATTRIBUTE = "raindrop.eval_correlation_id";
3
- var PROBE_SCOPE = { correlationId: "" };
4
- var EvalScopeStorage = class {
5
- constructor() {
6
- this._als = null;
7
- this._probed = false;
8
- }
9
- maybeAdoptAsyncLocalStorage() {
10
- if (this._probed) return;
11
- this._probed = true;
12
- try {
13
- const Ctor = globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
14
- if (!Ctor) return;
15
- const als = new Ctor();
16
- als.run(PROBE_SCOPE, () => {
17
- });
18
- this._als = als;
19
- } catch (e) {
20
- this._als = null;
21
- }
22
- }
23
- run(scope, callback) {
24
- this.maybeAdoptAsyncLocalStorage();
25
- if (this._als) return this._als.run(scope, callback);
26
- const previous = this._syncScope;
27
- this._syncScope = scope;
28
- try {
29
- return callback();
30
- } finally {
31
- this._syncScope = previous;
32
- }
33
- }
34
- current() {
35
- this.maybeAdoptAsyncLocalStorage();
36
- if (this._als) return this._als.getStore();
37
- return this._syncScope;
38
- }
39
- };
40
- var EVAL_SCOPE_STORAGE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.evalScopeStorage");
41
- function evalScopeStorage() {
42
- const holder = globalThis;
43
- let storage = holder[EVAL_SCOPE_STORAGE_KEY];
44
- if (!storage) {
45
- storage = new EvalScopeStorage();
46
- holder[EVAL_SCOPE_STORAGE_KEY] = storage;
47
- }
48
- return storage;
49
- }
50
- function currentEvalScope() {
51
- try {
52
- return evalScopeStorage().current();
53
- } catch (e) {
54
- return void 0;
55
- }
56
- }
57
- function evalScopeAttributes() {
58
- const scope = currentEvalScope();
59
- if (!scope) return {};
60
- return { [EVAL_CORRELATION_ID_ATTRIBUTE]: scope.correlationId };
61
- }
62
-
63
- // ../core/dist/chunk-WJOR6M7H.js
64
- var STATE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.replayTraceRoutingState");
65
- function state() {
66
- const holder = globalThis;
67
- let current = holder[STATE_KEY];
68
- if (!current) {
69
- let storage = null;
70
- try {
71
- const Ctor = globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
72
- if (Ctor) storage = new Ctor();
73
- } catch (e) {
74
- storage = null;
75
- }
76
- current = {
77
- storage,
78
- syncDestination: void 0,
79
- spanDestinations: /* @__PURE__ */ new WeakMap()
80
- };
81
- holder[STATE_KEY] = current;
82
- }
83
- return current;
84
- }
85
- function currentReplayTraceDestination() {
86
- var _a, _b;
87
- const routing = state();
88
- return (_b = (_a = routing.storage) == null ? void 0 : _a.getStore()) != null ? _b : routing.syncDestination;
89
- }
90
- function rememberReplayTraceDestination(span) {
91
- const destination = currentReplayTraceDestination();
92
- if (destination) state().spanDestinations.set(span, destination);
93
- }
94
- function copyReplayTraceDestination(source, target) {
95
- const destination = state().spanDestinations.get(source);
96
- if (destination) state().spanDestinations.set(target, destination);
97
- }
98
- function replayTraceDestinationFor(value) {
99
- if (typeof value !== "object" && typeof value !== "function" || value === null) {
100
- return void 0;
101
- }
102
- return state().spanDestinations.get(value);
103
- }
104
- function recordReplayExportedSpan(destination, spanId, traceId) {
105
- var _a, _b;
106
- if (!destination || !spanId || !traceId) return;
107
- (_a = destination.exportedSpanIds) == null ? void 0 : _a.add(spanId);
108
- (_b = destination.exportedTraceIds) == null ? void 0 : _b.add(traceId);
109
- }
110
- function replayTraceUrl(baseUrl) {
111
- return `${baseUrl.replace(/\/+$/, "")}/v1/traces`;
112
- }
113
- function getAsyncLocalStorageCtor() {
114
- return globalThis.RAINDROP_ASYNC_LOCAL_STORAGE;
115
- }
116
- var MAX_BINDING_STACK = 128;
117
- var EMPTY_STACK = [];
118
- var ContextStackStorage = class {
119
- /** Emitted once when this runtime cannot support an ambient push. */
120
- constructor(noAmbientBindWarning) {
121
- this.noAmbientBindWarning = noAmbientBindWarning;
122
- this._als = null;
123
- this._enterWithUsable = false;
124
- this._syncStack = EMPTY_STACK;
125
- this._adoptionChecked = false;
126
- this._warnedNoAmbientBind = false;
127
- }
128
- maybeAdoptAsyncLocalStorage() {
129
- if (this._adoptionChecked) return;
130
- this._adoptionChecked = true;
131
- const Ctor = getAsyncLocalStorageCtor();
132
- if (!Ctor) return;
133
- const als = new Ctor();
134
- try {
135
- als.run(EMPTY_STACK, () => {
136
- });
137
- } catch (e) {
138
- return;
139
- }
140
- this._als = als;
141
- if (typeof als.enterWith === "function") {
142
- try {
143
- als.enterWith(EMPTY_STACK);
144
- this._enterWithUsable = true;
145
- } catch (e) {
146
- this._enterWithUsable = false;
147
- }
148
- }
149
- }
150
- getStack() {
151
- var _a;
152
- this.maybeAdoptAsyncLocalStorage();
153
- if (this._als) return (_a = this._als.getStore()) != null ? _a : this._syncStack;
154
- return this._syncStack;
155
- }
156
- /**
157
- * Persist an ambient stack mutation. Returns false when an ALS is adopted but
158
- * `enterWith` is unusable (workerd): callers must NOT fall back to the
159
- * process-shared sync stack, since concurrent isolates would cross-stamp.
160
- */
161
- setAmbientStack(stack) {
162
- if (this._als) {
163
- if (!this._enterWithUsable) return false;
164
- this._als.enterWith(stack);
165
- return true;
166
- }
167
- this._syncStack = stack;
168
- return true;
169
- }
170
- push(binding) {
171
- this.maybeAdoptAsyncLocalStorage();
172
- if (this._als && !this._enterWithUsable) {
173
- this.warnNoAmbientBindOnce();
174
- return;
175
- }
176
- let stack = this.getStack();
177
- if (stack.length >= MAX_BINDING_STACK) {
178
- stack = stack.filter((b) => b.isLive());
179
- if (stack.length >= MAX_BINDING_STACK) {
180
- stack = stack.slice(stack.length - (MAX_BINDING_STACK - 1));
181
- }
182
- }
183
- this.setAmbientStack([...stack, binding]);
184
- }
185
- remove(binding) {
186
- binding.markDead();
187
- const stack = this.getStack();
188
- const pruned = stack.filter((b) => b !== binding && b.isLive());
189
- if (pruned.length !== stack.length) {
190
- this.setAmbientStack(pruned);
191
- }
192
- }
193
- runWith(binding, callback) {
194
- this.maybeAdoptAsyncLocalStorage();
195
- if (this._als) {
196
- return this._als.run([...this.getStack(), binding], callback);
197
- }
198
- const previous = this._syncStack;
199
- this._syncStack = [...previous, binding];
200
- try {
201
- return callback();
202
- } finally {
203
- this._syncStack = previous;
204
- }
205
- }
206
- current() {
207
- const stack = this.getStack();
208
- if (stack.length === 0) return void 0;
209
- const top = stack[stack.length - 1];
210
- if (top.isLive()) return top;
211
- const pruned = stack.filter((b) => b.isLive());
212
- this.setAmbientStack(pruned);
213
- return pruned.length > 0 ? pruned[pruned.length - 1] : void 0;
214
- }
215
- warnNoAmbientBindOnce() {
216
- if (this._warnedNoAmbientBind) return;
217
- this._warnedNoAmbientBind = true;
218
- console.warn(this.noAmbientBindWarning);
219
- }
220
- };
221
- 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.";
222
- var ROUTING_STORAGE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.routingContextStorage");
223
- function routingStorage() {
224
- const holder = globalThis;
225
- let storage = holder[ROUTING_STORAGE_KEY];
226
- if (!storage) {
227
- storage = new ContextStackStorage(NO_AMBIENT_ROUTING_BIND_WARNING);
228
- holder[ROUTING_STORAGE_KEY] = storage;
229
- }
230
- return storage;
231
- }
232
- function currentRoutingBinding() {
233
- const bound = routingStorage().current();
234
- if (!bound) return void 0;
235
- return {
236
- projectId: bound.projectId,
237
- authHint: bound.authHint,
238
- ...bound.appGit ? { appGit: bound.appGit } : {},
239
- ...bound.appGitSource ? { appGitSource: bound.appGitSource } : {}
240
- };
241
- }
242
- var APP_COMMIT_SHA = "raindrop.app.commit_sha";
243
- var APP_COMMIT_DIRTY = "raindrop.app.commit_dirty";
244
- var APP_BRANCH = "raindrop.app.branch";
245
- var APP_GIT_KEYS = [APP_COMMIT_SHA, APP_COMMIT_DIRTY, APP_BRANCH];
246
- var own = (value, key) => Object.prototype.hasOwnProperty.call(value, key);
247
- function appGitExplicitKeys(properties) {
248
- const keys = /* @__PURE__ */ new Set();
249
- if (!properties) return keys;
250
- for (const key of APP_GIT_KEYS) {
251
- if (own(properties, key)) keys.add(key);
252
- }
253
- return keys;
254
- }
255
- function mergeAppGitSnapshot(base, properties, explicitKeys = /* @__PURE__ */ new Set()) {
256
- try {
257
- const result = { ...base };
258
- if (properties && own(properties, APP_COMMIT_SHA) && properties[APP_COMMIT_SHA] !== result[APP_COMMIT_SHA]) {
259
- if (!explicitKeys.has(APP_COMMIT_DIRTY) && !own(properties, APP_COMMIT_DIRTY)) {
260
- delete result[APP_COMMIT_DIRTY];
261
- }
262
- if (!explicitKeys.has(APP_BRANCH) && !own(properties, APP_BRANCH)) {
263
- delete result[APP_BRANCH];
264
- }
265
- }
266
- for (const key of APP_GIT_KEYS) {
267
- if (properties && own(properties, key)) result[key] = properties[key];
268
- }
269
- return Object.freeze(result);
270
- } catch (e) {
271
- return Object.freeze({});
272
- }
273
- }
274
- function validAppCommitSha(value) {
275
- if (typeof value !== "string" || value.length > 128) return void 0;
276
- const cleaned = value.trim();
277
- return /^(?:[a-fA-F0-9]{40}|[a-fA-F0-9]{64})$/.test(cleaned) ? cleaned.toLowerCase() : void 0;
278
- }
279
- function shortString(value) {
280
- if (typeof value !== "string" || value.length > 1024) return void 0;
281
- const cleaned = value.trim();
282
- return cleaned.length > 0 ? cleaned : void 0;
283
- }
284
- function flag(value) {
285
- if (value === true || value === "true" || value === "1") return true;
286
- if (value === false || value === "false" || value === "0") return false;
287
- return void 0;
288
- }
289
- function environment() {
290
- try {
291
- return typeof process === "undefined" ? {} : process.env;
292
- } catch (e) {
293
- return {};
294
- }
295
- }
296
- var DEPLOYMENTS = [
297
- ["VERCEL", "VERCEL_GIT_COMMIT_SHA", "VERCEL_GIT_COMMIT_REF"],
298
- ["NETLIFY", "COMMIT_REF", "BRANCH"],
299
- ["RAILWAY_ENVIRONMENT_NAME", "RAILWAY_GIT_COMMIT_SHA", "RAILWAY_GIT_BRANCH"],
300
- ["RAILWAY_ENVIRONMENT", "RAILWAY_GIT_COMMIT_SHA", "RAILWAY_GIT_BRANCH"],
301
- ["RENDER", "RENDER_GIT_COMMIT", "RENDER_GIT_BRANCH"],
302
- ["DYNO", "HEROKU_BUILD_COMMIT", ""],
303
- ["DYNO", "HEROKU_SLUG_COMMIT", ""],
304
- ["AWS_APP_ID", "AWS_COMMIT_ID", "AWS_BRANCH"],
305
- ["WORKERS_CI", "WORKERS_CI_COMMIT_SHA", "WORKERS_CI_BRANCH"]
306
- ];
307
- var CI_SOURCES = [
308
- ["GITHUB_ACTIONS", "GITHUB_SHA", "GITHUB_REF_NAME"],
309
- ["GITLAB_CI", "CI_COMMIT_SHA", "CI_COMMIT_REF_NAME"],
310
- ["CIRCLECI", "CIRCLE_SHA1", "CIRCLE_BRANCH"]
311
- ];
312
- function detectedSource(env, table, detectBranch) {
313
- for (const row of table) {
314
- const [marker, shaKey, branchKey] = row;
315
- if (!marker || !shaKey || !shortString(env[marker]) || flag(env[marker]) === false) continue;
316
- const commitSha = validAppCommitSha(env[shaKey]);
317
- if (commitSha)
318
- return {
319
- commitSha,
320
- ...detectBranch && branchKey ? { branch: shortString(env[branchKey]) } : {}
321
- };
322
- }
323
- return {};
324
- }
325
- var AppGitContextImpl = class {
326
- constructor(options, runtime = {}) {
327
- this.defaults = {};
328
- this.explicit = {};
329
- this.explicitKeys = /* @__PURE__ */ new Set();
330
- this.disposed = false;
331
- this.operations = /* @__PURE__ */ new Map();
332
- this.operationOverflow = false;
333
- this.detectBranch = false;
334
- this.disabled = false;
335
- var _a, _b, _c, _d, _e, _f;
336
- try {
337
- if (options === false) {
338
- this.disabled = true;
339
- return;
340
- }
341
- const opts = options != null ? options : {};
342
- const env = (_a = runtime.env) != null ? _a : environment();
343
- const detectBranch = (_c = (_b = flag(opts.detectBranch)) != null ? _b : flag(env.RAINDROP_GIT_DETECT_BRANCH)) != null ? _c : false;
344
- this.detectBranch = detectBranch;
345
- const collectBranch = detectBranch || runtime.captureLegacyReplayBranch === true;
346
- const autoDetect = runtime.allowDiscovery === false ? false : (_e = (_d = flag(opts.autoDetect)) != null ? _d : flag(env.RAINDROP_GIT_AUTO_DETECT)) != null ? _e : true;
347
- const configuredSha = opts.commitSha;
348
- const explicitSha = configuredSha === void 0 ? env.RAINDROP_COMMIT_SHA : configuredSha;
349
- if (explicitSha === null) this.explicit[APP_COMMIT_SHA] = null;
350
- else if (typeof explicitSha === "string" && validAppCommitSha(explicitSha))
351
- this.explicit[APP_COMMIT_SHA] = explicitSha;
352
- const configuredDirty = opts.commitDirty;
353
- const explicitDirty = configuredDirty === void 0 ? flag(env.RAINDROP_COMMIT_DIRTY) : configuredDirty;
354
- if (explicitDirty === null || typeof explicitDirty === "boolean")
355
- this.explicit[APP_COMMIT_DIRTY] = explicitDirty;
356
- const configuredBranch = opts.branch;
357
- const explicitBranch = configuredBranch === void 0 ? env.RAINDROP_BRANCH : configuredBranch;
358
- if (explicitBranch === null) this.explicit[APP_BRANCH] = null;
359
- else if (typeof explicitBranch === "string" && explicitBranch.length <= 1024)
360
- this.explicit[APP_BRANCH] = explicitBranch;
361
- this.explicitKeys = appGitExplicitKeys(this.explicit);
362
- this.defaults = { ...this.explicit };
363
- if (!autoDetect || explicitSha !== void 0) return;
364
- const sourceDirectory = (_f = shortString(opts.sourceDirectory)) != null ? _f : shortString(env.RAINDROP_GIT_SOURCE_DIRECTORY);
365
- if (runtime.allowLocalGit === false && !sourceDirectory) return;
366
- const deploy = sourceDirectory ? {} : detectedSource(env, DEPLOYMENTS, collectBranch);
367
- if (deploy.commitSha) {
368
- this.accept(deploy);
369
- return;
370
- }
371
- const fallback = sourceDirectory ? {} : detectedSource(env, CI_SOURCES, collectBranch);
372
- if (runtime.resolveLocal && (runtime.allowLocalGit !== false || sourceDirectory)) {
373
- this.cancel = runtime.resolveLocal(sourceDirectory, collectBranch, (result) => {
374
- try {
375
- if (!this.disposed) this.accept(result.commitSha ? result : fallback);
376
- } catch (e) {
377
- }
378
- });
379
- } else this.accept(fallback);
380
- } catch (e) {
381
- }
382
- }
383
- accept(result) {
384
- const sha = validAppCommitSha(result.commitSha);
385
- if (!sha) return;
386
- this.replayBranch = shortString(result.branch);
387
- this.defaults = {
388
- [APP_COMMIT_SHA]: sha,
389
- ...typeof result.commitDirty === "boolean" ? { [APP_COMMIT_DIRTY]: result.commitDirty } : {},
390
- ...this.detectBranch && this.replayBranch ? { [APP_BRANCH]: this.replayBranch } : {},
391
- ...this.explicit
392
- };
393
- }
394
- snapshot(properties) {
395
- var _a;
396
- try {
397
- const binding = currentRoutingBinding();
398
- const base = this.disabled && (binding == null ? void 0 : binding.appGitSource) !== "replay-override" ? {} : (_a = binding == null ? void 0 : binding.appGit) != null ? _a : this.defaults;
399
- return this.mergeSnapshot(base, properties);
400
- } catch (e) {
401
- return Object.freeze({});
402
- }
403
- }
404
- /** Safe defaults when no operation/span start was observed; never infer identity. */
405
- snapshotExplicit(properties, eventId) {
406
- try {
407
- const base = { ...this.explicit };
408
- const operation = eventId ? this.operations.get(eventId) : void 0;
409
- if (operation) {
410
- for (const key of operation.explicitKeys) base[key] = operation.snapshot[key];
411
- }
412
- return this.mergeSnapshot(base, properties, new Set(Object.keys(base)));
413
- } catch (e) {
414
- return mergeAppGitSnapshot({}, properties);
415
- }
416
- }
417
- /** Existing replay branch reporting stays separate from opt-in event properties. */
418
- snapshotForReplay() {
419
- const snapshot = this.snapshot();
420
- if (this.replayBranch && !own(snapshot, APP_BRANCH) && snapshot[APP_COMMIT_SHA] === this.defaults[APP_COMMIT_SHA]) {
421
- return Object.freeze({ ...snapshot, [APP_BRANCH]: this.replayBranch });
422
- }
423
- return snapshot;
424
- }
425
- /** Merge a frozen span snapshot without losing client-authored provenance. */
426
- mergeSnapshot(base, properties, explicitKeys = this.explicitKeys) {
427
- return mergeAppGitSnapshot(base, properties, /* @__PURE__ */ new Set([...this.explicitKeys, ...explicitKeys]));
428
- }
429
- /** Shippers belonging to one client share this bounded operation registry. */
430
- forOperation(eventId, properties, owner) {
431
- if (!eventId) return this.snapshot(properties);
432
- let operation = this.operations.get(eventId);
433
- if (!operation) {
434
- if (this.operations.size >= 1e4) this.operationOverflow = true;
435
- if (this.operationOverflow) return this.mergeSnapshot({}, properties);
436
- operation = {
437
- snapshot: this.snapshot(properties),
438
- owners: /* @__PURE__ */ new Set(),
439
- unowned: owner === void 0,
440
- explicitKeys: appGitExplicitKeys(properties)
441
- };
442
- this.operations.set(eventId, operation);
443
- } else if (properties && APP_GIT_KEYS.some((key) => own(properties, key))) {
444
- const explicitKeys = /* @__PURE__ */ new Set([...this.explicitKeys, ...operation.explicitKeys]);
445
- operation.snapshot = this.mergeSnapshot(operation.snapshot, properties, explicitKeys);
446
- for (const key of appGitExplicitKeys(properties)) operation.explicitKeys.add(key);
447
- }
448
- if (!owner) operation.unowned = true;
449
- if (owner) operation.owners.add(owner);
450
- return operation.snapshot;
451
- }
452
- releaseOperation(eventId, owner) {
453
- const operation = this.operations.get(eventId);
454
- if (!operation) return;
455
- operation.owners.delete(owner);
456
- if (operation.owners.size === 0 && !operation.unowned) this.operations.delete(eventId);
457
- }
458
- finishOperation(eventId) {
459
- this.operations.delete(eventId);
460
- }
461
- dispose() {
462
- var _a;
463
- this.disposed = true;
464
- try {
465
- (_a = this.cancel) == null ? void 0 : _a.call(this);
466
- } catch (e) {
467
- }
468
- }
469
- };
470
- var AppGitContext = AppGitContextImpl;
471
- function createAppGitContext(options, runtime = {}) {
472
- return new AppGitContext(options, runtime);
473
- }
474
- function withAppGitProperties(properties, snapshot) {
475
- try {
476
- const merged = { ...properties };
477
- for (const key of APP_GIT_KEYS)
478
- if (!own(merged, key) && own(snapshot, key)) merged[key] = snapshot[key];
479
- return merged;
480
- } catch (e) {
481
- return properties != null ? properties : {};
482
- }
483
- }
484
- function withAppGitAttributes(attributes, snapshot) {
485
- try {
486
- const present = new Set(attributes.flatMap((attr) => attr ? [attr.key] : []));
487
- const added = [];
488
- for (const key of APP_GIT_KEYS) {
489
- if (present.has(key) || present.has(`ai.telemetry.metadata.${key}`) || present.has(`traceloop.association.properties.${key}`))
490
- continue;
491
- const value = snapshot[key];
492
- if (typeof value === "string") added.push({ key, value: { stringValue: value } });
493
- else if (typeof value === "boolean") added.push({ key, value: { boolValue: value } });
494
- }
495
- return added.length ? [...attributes, ...added] : attributes;
496
- } catch (e) {
497
- return attributes;
498
- }
499
- }
500
- function appGitPropertiesFromAttributes(attributes) {
501
- var _a, _b, _c;
502
- const properties = {};
503
- try {
504
- for (const attr of attributes) {
505
- if (!attr) continue;
506
- for (const key of APP_GIT_KEYS) {
507
- if (attr.key === key || attr.key === `ai.telemetry.metadata.${key}` || attr.key === `traceloop.association.properties.${key}`) {
508
- properties[key] = (_c = (_b = (_a = attr.value.stringValue) != null ? _a : attr.value.boolValue) != null ? _b : attr.value.intValue) != null ? _c : null;
509
- }
510
- }
511
- }
512
- } catch (e) {
513
- }
514
- return properties;
515
- }
516
- function getCrypto() {
517
- const c = globalThis.crypto;
518
- return c;
519
- }
520
- function randomBytes(length) {
521
- const cryptoObj = getCrypto();
522
- const out = new Uint8Array(length);
523
- if (cryptoObj && typeof cryptoObj.getRandomValues === "function") {
524
- cryptoObj.getRandomValues(out);
525
- return out;
526
- }
527
- for (let i = 0; i < out.length; i++) out[i] = Math.floor(Math.random() * 256);
528
- return out;
529
- }
530
- function randomUUID() {
531
- const cryptoObj = getCrypto();
532
- if (cryptoObj && typeof cryptoObj.randomUUID === "function") {
533
- return cryptoObj.randomUUID();
534
- }
535
- const b = randomBytes(16);
536
- b[6] = b[6] & 15 | 64;
537
- b[8] = b[8] & 63 | 128;
538
- const hex = [...b].map((x) => x.toString(16).padStart(2, "0")).join("");
539
- return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
540
- }
541
- function base64Encode(bytes) {
542
- const maybeBuffer = globalThis.Buffer;
543
- if (maybeBuffer) {
544
- return maybeBuffer.from(bytes).toString("base64");
545
- }
546
- let binary = "";
547
- for (let i2 = 0; i2 < bytes.length; i2++) {
548
- binary += String.fromCharCode(bytes[i2]);
549
- }
550
- const btoaFn = globalThis.btoa;
551
- if (typeof btoaFn === "function") return btoaFn(binary);
552
- const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
553
- let out = "";
554
- let i = 0;
555
- while (i < binary.length) {
556
- const c1 = binary.charCodeAt(i++) & 255;
557
- const c2 = i < binary.length ? binary.charCodeAt(i++) & 255 : NaN;
558
- const c3 = i < binary.length ? binary.charCodeAt(i++) & 255 : NaN;
559
- const e1 = c1 >> 2;
560
- const e2 = (c1 & 3) << 4 | (Number.isNaN(c2) ? 0 : c2 >> 4);
561
- const e3 = Number.isNaN(c2) ? 64 : (c2 & 15) << 2 | (Number.isNaN(c3) ? 0 : c3 >> 6);
562
- const e4 = Number.isNaN(c3) ? 64 : c3 & 63;
563
- out += alphabet.charAt(e1);
564
- out += alphabet.charAt(e2);
565
- out += e3 === 64 ? "=" : alphabet.charAt(e3);
566
- out += e4 === 64 ? "=" : alphabet.charAt(e4);
567
- }
568
- return out;
569
- }
570
- function base64ToHex(value) {
571
- if (!value) return "";
572
- const maybeBuffer = globalThis.Buffer;
573
- if (maybeBuffer) {
574
- return maybeBuffer.from(value, "base64").toString("hex");
575
- }
576
- const atobFn = globalThis.atob;
577
- if (typeof atobFn !== "function") return "";
578
- try {
579
- const binary = atobFn(value);
580
- let hex = "";
581
- for (let i = 0; i < binary.length; i++) {
582
- hex += (binary.charCodeAt(i) & 255).toString(16).padStart(2, "0");
583
- }
584
- return hex;
585
- } catch (e) {
586
- return "";
587
- }
588
- }
589
- function generateId() {
590
- return randomUUID();
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.`;
606
- function runWithTracingSuppressed(fn) {
607
- const hook = globalThis.RAINDROP_SUPPRESS_TRACING;
608
- if (typeof hook !== "function") return fn();
609
- let started = false;
610
- try {
611
- return hook(() => {
612
- started = true;
613
- return fn();
614
- });
615
- } catch (err) {
616
- if (started) throw err;
617
- return fn();
618
- }
619
- }
620
- var DEFAULT_REQUEST_TIMEOUT_MS = 3e4;
621
- var MAX_RETRY_DELAY_MS = 3e4;
622
- function wait(ms) {
623
- return new Promise((resolve2) => setTimeout(resolve2, ms));
624
- }
625
- function formatEndpoint(endpoint) {
626
- if (!endpoint) return void 0;
627
- return endpoint.endsWith("/") ? endpoint : `${endpoint}/`;
628
- }
629
- function redactUrlForLog(url) {
630
- try {
631
- const parsed = new URL(url);
632
- parsed.username = "";
633
- parsed.password = "";
634
- parsed.search = "";
635
- parsed.hash = "";
636
- return parsed.toString();
637
- } catch (e) {
638
- return "<unparseable-url>";
639
- }
640
- }
641
- var RATE_LIMITED_LOG_INTERVAL_MS = 3e4;
642
- var rateLimitedLogLast = /* @__PURE__ */ new Map();
643
- function rateLimitedLog(key, log) {
644
- const now = Date.now();
645
- const last = rateLimitedLogLast.get(key);
646
- if (last !== void 0 && now - last < RATE_LIMITED_LOG_INTERVAL_MS) {
647
- return false;
648
- }
649
- rateLimitedLogLast.set(key, now);
650
- log();
651
- return true;
652
- }
653
- async function raceWithTimeout(promise, timeoutMs) {
654
- let timer;
655
- const settledInTime = await Promise.race([
656
- promise.then(
657
- () => true,
658
- () => true
659
- ),
660
- new Promise((resolve2) => {
661
- var _a;
662
- timer = setTimeout(() => resolve2(false), Math.max(0, timeoutMs));
663
- (_a = timer.unref) == null ? void 0 : _a.call(timer);
664
- })
665
- ]);
666
- if (timer) clearTimeout(timer);
667
- return settledInTime;
668
- }
669
- function parseRetryAfter(headers) {
670
- var _a;
671
- const value = (_a = headers.get("Retry-After")) != null ? _a : headers.get("retry-after");
672
- if (!value) return void 0;
673
- const asNumber = Number(value);
674
- if (value.trim() !== "" && !Number.isNaN(asNumber)) return asNumber * 1e3;
675
- const asDate = new Date(value).getTime();
676
- if (!Number.isNaN(asDate)) {
677
- const delta = asDate - Date.now();
678
- return delta > 0 ? delta : 0;
679
- }
680
- return void 0;
681
- }
682
- function getRetryDelayMs(attemptNumber, previousError) {
683
- if (previousError && typeof previousError === "object" && previousError !== null && "retryAfterMs" in previousError) {
684
- const v = previousError.retryAfterMs;
685
- if (typeof v === "number") return Math.min(Math.max(0, v), MAX_RETRY_DELAY_MS);
686
- }
687
- if (attemptNumber <= 1) return 0;
688
- const base = 500;
689
- const factor = Math.pow(2, attemptNumber - 2);
690
- return Math.min(base * factor, MAX_RETRY_DELAY_MS);
691
- }
692
- async function withRetry(operation, opName, opts) {
693
- const prefix = opts.sdkName ? `[raindrop-ai/${opts.sdkName}]` : "[raindrop-ai/core]";
694
- let lastError = void 0;
695
- for (let attemptNumber = 1; attemptNumber <= opts.maxAttempts; attemptNumber++) {
696
- if (attemptNumber > 1) {
697
- const delay = getRetryDelayMs(attemptNumber, lastError);
698
- if (opts.debug) {
699
- console.warn(
700
- `${prefix} ${opName} retry ${attemptNumber}/${opts.maxAttempts} in ${delay}ms`
701
- );
702
- }
703
- if (delay > 0) await wait(delay);
704
- } else if (opts.debug) {
705
- console.log(`${prefix} ${opName} attempt ${attemptNumber}/${opts.maxAttempts}`);
706
- }
707
- try {
708
- return await operation();
709
- } catch (err) {
710
- lastError = err;
711
- if (opts.debug) {
712
- const msg = err instanceof Error ? err.message : String(err);
713
- console.warn(
714
- `${prefix} ${opName} attempt ${attemptNumber} failed: ${msg}${attemptNumber === opts.maxAttempts ? " (no more retries)" : ""}`
715
- );
716
- }
717
- if (lastError && typeof lastError === "object" && "retryable" in lastError && !lastError.retryable)
718
- break;
719
- if (attemptNumber === opts.maxAttempts) break;
720
- }
721
- }
722
- throw lastError instanceof Error ? lastError : new Error(String(lastError));
723
- }
724
- async function postJson(url, body, headers, opts) {
725
- var _a;
726
- const opName = `POST ${redactUrlForLog(url)}`;
727
- const timeoutMs = (_a = opts.timeoutMs) != null ? _a : DEFAULT_REQUEST_TIMEOUT_MS;
728
- await withRetry(
729
- async () => {
730
- const resp = await runWithTracingSuppressed(
731
- () => fetch(url, {
732
- method: "POST",
733
- redirect: headers["X-Raindrop-Replay-Id"] !== void 0 ? "error" : "follow",
734
- headers: {
735
- "Content-Type": "application/json",
736
- ...headers
737
- },
738
- body: JSON.stringify(body),
739
- signal: AbortSignal.timeout(timeoutMs)
740
- })
741
- );
742
- if (!resp.ok) {
743
- const text = await resp.text().catch(() => "");
744
- const err = new Error(
745
- `HTTP ${resp.status} ${resp.statusText}${text ? `: ${text}` : ""}`
746
- );
747
- const retryAfterMs = parseRetryAfter(resp.headers);
748
- if (typeof retryAfterMs === "number") err.retryAfterMs = retryAfterMs;
749
- err.retryable = resp.status === 429 || resp.status >= 500;
750
- throw err;
751
- }
752
- },
753
- opName,
754
- opts
755
- );
756
- }
757
- var DEFAULT_MAX_TEXT_FIELD_CHARS = 1e6;
758
- var TRUNCATION_MARKER = "...[truncated by raindrop]";
759
- var currentDefaultMaxTextFieldChars = DEFAULT_MAX_TEXT_FIELD_CHARS;
760
- function resolveMaxTextFieldChars(value) {
761
- if (typeof value === "number" && Number.isFinite(value) && value > 0) {
762
- return Math.floor(value);
763
- }
764
- return currentDefaultMaxTextFieldChars;
765
- }
766
- function truncateToLimit(text, limit) {
767
- if (limit > TRUNCATION_MARKER.length) {
768
- return text.slice(0, limit - TRUNCATION_MARKER.length) + TRUNCATION_MARKER;
769
- }
770
- return text.slice(0, Math.max(0, limit));
771
- }
772
- function capText(value, limit) {
773
- if (typeof value !== "string") return value;
774
- const max = limit != null ? limit : currentDefaultMaxTextFieldChars;
775
- if (value.length <= max) return value;
776
- return truncateToLimit(value, max);
777
- }
778
- var SpanStatusCode = {
779
- UNSET: 0,
780
- OK: 1,
781
- ERROR: 2
782
- };
783
- function createSpanIds(parent) {
784
- const traceId = parent ? parent.traceIdB64 : base64Encode(randomBytes(16));
785
- const spanId = base64Encode(randomBytes(8));
786
- return {
787
- traceIdB64: traceId,
788
- spanIdB64: spanId,
789
- parentSpanIdB64: parent ? parent.spanIdB64 : void 0
790
- };
791
- }
792
- function nowUnixNanoString() {
793
- return Date.now().toString() + "000000";
794
- }
795
- function attrString(key, value) {
796
- if (value === void 0) return void 0;
797
- return { key, value: { stringValue: value } };
798
- }
799
- function attrInt(key, value) {
800
- if (value === void 0) return void 0;
801
- if (!Number.isFinite(value)) return void 0;
802
- return { key, value: { intValue: String(Math.trunc(value)) } };
803
- }
804
- function attrDouble(key, value) {
805
- if (value === void 0) return void 0;
806
- if (!Number.isFinite(value)) return void 0;
807
- return { key, value: { doubleValue: value } };
808
- }
809
- function buildOtlpSpan(args) {
810
- const attrs = args.attributes.filter((x) => x !== void 0);
811
- const span = {
812
- traceId: args.ids.traceIdB64,
813
- spanId: args.ids.spanIdB64,
814
- name: args.name,
815
- startTimeUnixNano: args.startTimeUnixNano,
816
- endTimeUnixNano: args.endTimeUnixNano
817
- };
818
- if (args.ids.parentSpanIdB64) span.parentSpanId = args.ids.parentSpanIdB64;
819
- if (attrs.length) span.attributes = attrs;
820
- if (args.status) span.status = args.status;
821
- return span;
822
- }
823
- function buildExportTraceServiceRequest(spans, serviceName = "raindrop.core", serviceVersion = "0.0.0") {
824
- return {
825
- resourceSpans: [
826
- {
827
- resource: {
828
- attributes: [{ key: "service.name", value: { stringValue: serviceName } }]
829
- },
830
- scopeSpans: [
831
- {
832
- scope: { name: serviceName, version: serviceVersion },
833
- spans
834
- }
835
- ]
836
- }
837
- ]
838
- };
839
- }
840
- var LOCAL_DEBUGGER_ENV_VAR = "RAINDROP_LOCAL_DEBUGGER";
841
- var WORKSHOP_ENV_VAR = "RAINDROP_WORKSHOP";
842
- var DEFAULT_LOCAL_WORKSHOP_URL = "http://localhost:5899/v1/";
843
- function readEnvVar(name) {
844
- var _a;
845
- try {
846
- const env = (_a = globalThis == null ? void 0 : globalThis.process) == null ? void 0 : _a.env;
847
- if (env && typeof env[name] === "string" && env[name].length > 0) {
848
- return env[name];
849
- }
850
- } catch (e) {
851
- }
852
- return void 0;
853
- }
854
- function readWorkshopEnv() {
855
- const raw = readEnvVar(WORKSHOP_ENV_VAR);
856
- if (raw === void 0) return void 0;
857
- const trimmed = raw.trim();
858
- if (trimmed.length === 0) return void 0;
859
- if (/^https?:\/\//i.test(trimmed)) return { url: trimmed };
860
- if (/^(1|true|yes|on)$/i.test(trimmed)) return "enable";
861
- if (/^(0|false|no|off)$/i.test(trimmed)) return "disable";
862
- return void 0;
863
- }
864
- function isLocalDevHost(hostname) {
865
- if (!hostname) return false;
866
- if (hostname === "localhost" || hostname === "127.0.0.1" || hostname === "0.0.0.0" || hostname === "::1") {
867
- return true;
868
- }
869
- if (hostname.endsWith(".localhost")) return true;
870
- return false;
871
- }
872
- function readRuntimeHostname() {
873
- try {
874
- const loc = globalThis == null ? void 0 : globalThis.location;
875
- if (loc && typeof loc.hostname === "string" && loc.hostname.length > 0) {
876
- return loc.hostname;
877
- }
878
- } catch (e) {
879
- }
880
- return void 0;
881
- }
882
- function shouldAutoEnableLocalWorkshop() {
883
- if (isLocalDevHost(readRuntimeHostname())) return true;
884
- if (readEnvVar("NODE_ENV") === "development") return true;
885
- return false;
886
- }
887
- function resolveLocalDebuggerBaseUrl(baseUrl) {
888
- var _a, _b, _c;
889
- if (baseUrl === null) return null;
890
- if (typeof baseUrl === "string" && baseUrl.length > 0) {
891
- return (_a = formatEndpoint(baseUrl)) != null ? _a : null;
892
- }
893
- const explicitUrlEnv = readEnvVar(LOCAL_DEBUGGER_ENV_VAR);
894
- if (explicitUrlEnv) return (_b = formatEndpoint(explicitUrlEnv)) != null ? _b : null;
895
- const workshopEnv = readWorkshopEnv();
896
- if (workshopEnv === "disable") return null;
897
- if (workshopEnv === "enable") return DEFAULT_LOCAL_WORKSHOP_URL;
898
- if (workshopEnv && "url" in workshopEnv) return (_c = formatEndpoint(workshopEnv.url)) != null ? _c : null;
899
- if (shouldAutoEnableLocalWorkshop()) return DEFAULT_LOCAL_WORKSHOP_URL;
900
- return null;
901
- }
902
- var LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS = 2e3;
903
- function mirrorTraceExportToLocalDebugger(body, options = {}) {
904
- var _a;
905
- const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
906
- if (!baseUrl) return Promise.resolve();
907
- return postJson(`${baseUrl}traces`, body, {}, {
908
- maxAttempts: 1,
909
- debug: (_a = options.debug) != null ? _a : false,
910
- sdkName: options.sdkName,
911
- timeoutMs: LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS
912
- }).catch(() => {
913
- });
914
- }
915
- function mirrorPartialEventToLocalDebugger(event, options = {}) {
916
- var _a;
917
- const baseUrl = resolveLocalDebuggerBaseUrl(options.baseUrl);
918
- if (!baseUrl) return Promise.resolve();
919
- const headers = options.writeKey ? { Authorization: `Bearer ${options.writeKey}` } : {};
920
- return postJson(`${baseUrl}events/track_partial`, event, headers, {
921
- maxAttempts: 1,
922
- debug: (_a = options.debug) != null ? _a : false,
923
- sdkName: options.sdkName,
924
- timeoutMs: LOCAL_DEBUGGER_MIRROR_TIMEOUT_MS
925
- }).catch(() => {
926
- });
927
- }
928
- var PROJECT_ID_HEADER = "X-Raindrop-Project-Id";
929
- var PROJECT_ID_SLUG_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;
930
- function isValidProjectIdSlug(value) {
931
- return PROJECT_ID_SLUG_PATTERN.test(value);
932
- }
933
- function normalizeProjectId(raw, opts) {
934
- if (typeof raw !== "string") return void 0;
935
- const trimmed = raw.trim();
936
- if (!trimmed) return void 0;
937
- if (!isValidProjectIdSlug(trimmed) && opts.debug) {
938
- console.warn(
939
- `${opts.prefix} projectId "${trimmed}" does not match slug ${PROJECT_ID_SLUG_PATTERN.source}; sending anyway \u2014 backend may reject with HTTP 400`
940
- );
941
- }
942
- return trimmed;
943
- }
944
- function projectIdHeaders(projectId) {
945
- return projectId ? { [PROJECT_ID_HEADER]: projectId } : {};
946
- }
947
- var SHUTDOWN_DEADLINE_MS = 1e4;
948
- var POST_SHUTDOWN_TIMEOUT_MS = 5e3;
949
- function appGitOwnerId(prefix) {
950
- try {
951
- return `${prefix}:${randomUUID()}`;
952
- } catch (e) {
953
- return `${prefix}:${Date.now().toString(36)}:${Math.random().toString(36).slice(2)}`;
954
- }
955
- }
956
- function mergePatches(target, source) {
957
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
958
- const out = { ...target, ...source };
959
- if (target.properties || source.properties) {
960
- out.properties = { ...(_a = target.properties) != null ? _a : {}, ...(_b = source.properties) != null ? _b : {} };
961
- }
962
- if (target.usage || source.usage) {
963
- out.usage = { ...(_c = target.usage) != null ? _c : {} };
964
- if (((_d = source.usage) == null ? void 0 : _d.promptTokens) !== void 0) {
965
- out.usage.promptTokens = source.usage.promptTokens;
966
- }
967
- if (((_e = source.usage) == null ? void 0 : _e.completionTokens) !== void 0) {
968
- out.usage.completionTokens = source.usage.completionTokens;
969
- }
970
- }
971
- if (source.error === void 0) {
972
- out.error = target.error;
973
- }
974
- if (target.featureFlags || source.featureFlags) {
975
- out.featureFlags = { ...(_f = target.featureFlags) != null ? _f : {}, ...(_g = source.featureFlags) != null ? _g : {} };
976
- }
977
- if (target.attachments || source.attachments) {
978
- out.attachments = [...(_h = target.attachments) != null ? _h : [], ...(_i = source.attachments) != null ? _i : []];
979
- }
980
- return out;
981
- }
982
- function isErrorLike(value) {
983
- return value !== null && typeof value === "object";
984
- }
985
- function eventTelemetryProperties(patch) {
986
- var _a, _b;
987
- const properties = {};
988
- if (((_a = patch.usage) == null ? void 0 : _a.promptTokens) !== void 0 && Number.isFinite(patch.usage.promptTokens)) {
989
- properties["ai.usage.prompt_tokens"] = patch.usage.promptTokens;
990
- }
991
- if (((_b = patch.usage) == null ? void 0 : _b.completionTokens) !== void 0 && Number.isFinite(patch.usage.completionTokens)) {
992
- properties["ai.usage.completion_tokens"] = patch.usage.completionTokens;
993
- }
994
- if (patch.error !== void 0 && patch.error !== null) {
995
- const constructorName = patch.error instanceof Error && patch.error.constructor !== Error ? patch.error.constructor.name : void 0;
996
- 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";
997
- const errorMessage = patch.error instanceof Error ? patch.error.message : isErrorLike(patch.error) && typeof patch.error.message === "string" ? patch.error.message : String(patch.error);
998
- properties["error.type"] = errorType;
999
- properties["error.message"] = errorMessage;
1000
- }
1001
- return properties;
1002
- }
1003
- var EventShipper = class {
1004
- constructor(opts) {
1005
- this.appGitOwner = appGitOwnerId("event");
1006
- this.buffers = /* @__PURE__ */ new Map();
1007
- this.sticky = /* @__PURE__ */ new Map();
1008
- this.timers = /* @__PURE__ */ new Map();
1009
- this.inFlight = /* @__PURE__ */ new Set();
1010
- this.hasShutdown = false;
1011
- var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1012
- this.appGitContext = (_a = opts.appGitContext) != null ? _a : createAppGitContext(opts.appGit);
1013
- this.ownsAppGitContext = opts.appGitContext === void 0;
1014
- this.writeKey = (_b = opts.writeKey) == null ? void 0 : _b.trim();
1015
- this.baseUrl = (_c = formatEndpoint(opts.endpoint)) != null ? _c : "https://api.raindrop.ai/v1/";
1016
- this.enabled = opts.enabled !== false;
1017
- this.debug = opts.debug;
1018
- this.partialFlushMs = (_d = opts.partialFlushMs) != null ? _d : 1e3;
1019
- this.sdkName = (_e = opts.sdkName) != null ? _e : "core";
1020
- this.prefix = `[raindrop-ai/${this.sdkName}]`;
1021
- this.defaultEventName = (_f = opts.defaultEventName) != null ? _f : "ai_generation";
1022
- this.maxTextFieldCharsOpt = opts.maxTextFieldChars;
1023
- this.localDebuggerUrl = (_g = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _g : void 0;
1024
- if (this.debug && this.localDebuggerUrl) {
1025
- console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
1026
- }
1027
- this.projectId = normalizeProjectId(opts.projectId, {
1028
- debug: this.debug,
1029
- prefix: this.prefix
1030
- });
1031
- const isNode = typeof process !== "undefined" && typeof process.version === "string";
1032
- this.context = {
1033
- library: {
1034
- name: (_h = opts.libraryName) != null ? _h : "@raindrop-ai/core",
1035
- version: (_i = opts.libraryVersion) != null ? _i : "0.0.0"
1036
- },
1037
- metadata: {
1038
- jsRuntime: isNode ? "node" : "web",
1039
- ...isNode ? { nodeVersion: process.version } : {}
1040
- }
1041
- };
1042
- }
1043
- ownAppGitContextForShutdown() {
1044
- this.ownsAppGitContext = true;
1045
- }
1046
- isDebugEnabled() {
1047
- return this.debug;
1048
- }
1049
- authHeaders() {
1050
- return this.writeKey ? { Authorization: `Bearer ${this.writeKey}` } : {};
1051
- }
1052
- requestHeaders() {
1053
- return { ...this.authHeaders(), ...projectIdHeaders(this.projectId) };
1054
- }
1055
- /**
1056
- * Build the retry/timeout options for one POST, honoring the shutdown
1057
- * deadline. Returns `null` when the shutdown drain window is exhausted —
1058
- * the caller must drop the payload (with a rate-limited warning) instead
1059
- * of issuing a request that could outlive process exit.
1060
- *
1061
- * Checked fresh on EVERY send, so a shutdown that begins while the flush
1062
- * path is mid-drain takes effect immediately: no further retries, and the
1063
- * per-attempt timeout is clamped to the remaining window. After
1064
- * `shutdown()` returns (deadline cleared, `hasShutdown` still set),
1065
- * sends — late callers, or flush work the deadline abandoned mid-drain —
1066
- * run as a single short attempt rather than regaining the full retry
1067
- * schedule.
1068
- */
1069
- requestOpts() {
1070
- if (this.shutdownDeadlineAt !== void 0) {
1071
- const remainingMs = this.shutdownDeadlineAt - Date.now();
1072
- if (remainingMs <= 0) return null;
1073
- return {
1074
- maxAttempts: 1,
1075
- debug: this.debug,
1076
- sdkName: this.sdkName,
1077
- timeoutMs: Math.min(DEFAULT_REQUEST_TIMEOUT_MS, remainingMs)
1078
- };
1079
- }
1080
- if (this.hasShutdown) {
1081
- return {
1082
- maxAttempts: 1,
1083
- debug: this.debug,
1084
- sdkName: this.sdkName,
1085
- timeoutMs: POST_SHUTDOWN_TIMEOUT_MS
1086
- };
1087
- }
1088
- return { maxAttempts: 3, debug: this.debug, sdkName: this.sdkName };
1089
- }
1090
- async patch(eventId, patch) {
1091
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
1092
- if (!this.enabled) return;
1093
- if (!eventId || !eventId.trim()) return;
1094
- const capturedSticky = this.sticky.get(eventId);
1095
- const eventAlreadyKnown = capturedSticky !== void 0 || this.buffers.has(eventId);
1096
- const destination = currentReplayTraceDestination();
1097
- const cloudReplay = destination !== void 0 && destination.kind !== "workshop";
1098
- if ((capturedSticky == null ? void 0 : capturedSticky.replayOnly) === true || !eventAlreadyKnown && cloudReplay) {
1099
- if (patch.isPending === false) this.sticky.delete(eventId);
1100
- else this.sticky.set(eventId, { ...capturedSticky, replayOnly: true });
1101
- return;
1102
- }
1103
- const maxChars = resolveMaxTextFieldChars(this.maxTextFieldCharsOpt);
1104
- if (typeof patch.input === "string" && patch.input.length > maxChars) {
1105
- patch = { ...patch, input: capText(patch.input, maxChars) };
1106
- }
1107
- if (typeof patch.output === "string" && patch.output.length > maxChars) {
1108
- patch = { ...patch, output: capText(patch.output, maxChars) };
1109
- }
1110
- if (this.debug) {
1111
- console.log(`${this.prefix} queue patch`, {
1112
- eventId,
1113
- userId: patch.userId,
1114
- convoId: patch.convoId,
1115
- eventName: patch.eventName,
1116
- hasInput: typeof patch.input === "string" && patch.input.length > 0,
1117
- hasOutput: typeof patch.output === "string" && patch.output.length > 0,
1118
- attachments: (_b = (_a = patch.attachments) == null ? void 0 : _a.length) != null ? _b : 0,
1119
- isPending: patch.isPending
1120
- });
1121
- }
1122
- const sticky = (_c = this.sticky.get(eventId)) != null ? _c : {};
1123
- const existing = (_d = this.buffers.get(eventId)) != null ? _d : {};
1124
- patch = {
1125
- ...patch,
1126
- properties: withAppGitProperties(
1127
- patch.properties,
1128
- this.appGitContext.forOperation(eventId, patch.properties, this.appGitOwner)
1129
- )
1130
- };
1131
- const merged = mergePatches(existing, patch);
1132
- merged.isPending = (_g = (_f = (_e = patch.isPending) != null ? _e : existing.isPending) != null ? _f : sticky.isPending) != null ? _g : true;
1133
- this.buffers.set(eventId, merged);
1134
- this.sticky.set(eventId, {
1135
- userId: (_h = merged.userId) != null ? _h : sticky.userId,
1136
- convoId: (_i = merged.convoId) != null ? _i : sticky.convoId,
1137
- eventName: (_j = merged.eventName) != null ? _j : sticky.eventName,
1138
- isPending: (_k = merged.isPending) != null ? _k : sticky.isPending
1139
- });
1140
- const t = this.timers.get(eventId);
1141
- if (t) clearTimeout(t);
1142
- if (merged.isPending === false) {
1143
- await this.flushOne(eventId);
1144
- if (this.appGitContext.releaseOperation) this.appGitContext.releaseOperation(eventId, this.appGitOwner);
1145
- else this.appGitContext.finishOperation(eventId);
1146
- return;
1147
- }
1148
- const timeout = setTimeout(() => {
1149
- void this.flushOne(eventId).catch(() => {
1150
- });
1151
- }, this.partialFlushMs);
1152
- this.timers.set(eventId, timeout);
1153
- }
1154
- async finish(eventId, patch) {
1155
- await this.patch(eventId, { ...patch, isPending: false });
1156
- }
1157
- async flush() {
1158
- if (!this.enabled) return;
1159
- const ids = [...this.buffers.keys()];
1160
- await Promise.all(ids.map((id) => this.flushOne(id)));
1161
- await Promise.all([...this.inFlight].map((p) => p.catch(() => {
1162
- })));
1163
- }
1164
- async shutdown() {
1165
- this.hasShutdown = true;
1166
- this.shutdownDeadlineAt = Date.now() + SHUTDOWN_DEADLINE_MS;
1167
- try {
1168
- for (const t of this.timers.values()) clearTimeout(t);
1169
- this.timers.clear();
1170
- for (const [eventId, sticky] of this.sticky) {
1171
- if (sticky.replayOnly) this.sticky.delete(eventId);
1172
- }
1173
- const settled = await raceWithTimeout(this.flush(), SHUTDOWN_DEADLINE_MS);
1174
- if (!settled) this.warnShutdownDrop("in-flight request(s) at shutdown");
1175
- } finally {
1176
- this.shutdownDeadlineAt = void 0;
1177
- if (this.ownsAppGitContext) this.appGitContext.dispose();
1178
- }
1179
- }
1180
- async trackSignal(signal) {
1181
- var _a, _b;
1182
- if (!this.enabled) return;
1183
- const destination = currentReplayTraceDestination();
1184
- if (destination && destination.kind !== "workshop") return;
1185
- const body = [
1186
- {
1187
- event_id: signal.eventId,
1188
- signal_name: signal.name,
1189
- signal_type: (_a = signal.type) != null ? _a : "default",
1190
- timestamp: signal.timestamp,
1191
- sentiment: signal.sentiment,
1192
- attachment_id: signal.attachmentId,
1193
- properties: {
1194
- ...(_b = signal.properties) != null ? _b : {},
1195
- ...signal.comment ? { comment: signal.comment } : {},
1196
- ...signal.after ? { after: signal.after } : {}
1197
- }
1198
- }
1199
- ];
1200
- if (!this.writeKey) return;
1201
- const url = `${this.baseUrl}signals/track`;
1202
- const opts = this.requestOpts();
1203
- if (!opts) {
1204
- this.warnShutdownDrop("signal");
1205
- return;
1206
- }
1207
- try {
1208
- await postJson(url, body, this.requestHeaders(), opts);
1209
- } catch (err) {
1210
- const msg = err instanceof Error ? err.message : String(err);
1211
- rateLimitedLog(
1212
- `${this.prefix}.send_signal_failed`,
1213
- () => console.warn(`${this.prefix} failed to send signal (dropping): ${msg}`)
1214
- );
1215
- }
1216
- }
1217
- async identify(users) {
1218
- if (!this.enabled) return;
1219
- const destination = currentReplayTraceDestination();
1220
- if (destination && destination.kind !== "workshop") return;
1221
- const list = Array.isArray(users) ? users : [users];
1222
- const body = list.filter((user) => {
1223
- if (!(user == null ? void 0 : user.userId) || !user.userId.trim()) {
1224
- if (this.debug) {
1225
- console.warn(`${this.prefix} skipping identify: missing userId`);
1226
- }
1227
- return false;
1228
- }
1229
- return true;
1230
- }).map((user) => {
1231
- var _a;
1232
- return {
1233
- user_id: user.userId,
1234
- traits: (_a = user.traits) != null ? _a : {}
1235
- };
1236
- });
1237
- if (!this.writeKey) return;
1238
- if (body.length === 0) return;
1239
- const url = `${this.baseUrl}users/identify`;
1240
- const opts = this.requestOpts();
1241
- if (!opts) {
1242
- this.warnShutdownDrop("identify");
1243
- return;
1244
- }
1245
- try {
1246
- await postJson(url, body, this.requestHeaders(), opts);
1247
- } catch (err) {
1248
- const msg = err instanceof Error ? err.message : String(err);
1249
- rateLimitedLog(
1250
- `${this.prefix}.send_identify_failed`,
1251
- () => console.warn(`${this.prefix} failed to send identify (dropping): ${msg}`)
1252
- );
1253
- }
1254
- }
1255
- warnShutdownDrop(what) {
1256
- rateLimitedLog(
1257
- `${this.prefix}.shutdown_deadline`,
1258
- () => console.warn(`${this.prefix} shutdown flush deadline exceeded; dropping ${what}`)
1259
- );
1260
- }
1261
- async flushOne(eventId) {
1262
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m;
1263
- if (!this.enabled) return;
1264
- const timer = this.timers.get(eventId);
1265
- if (timer) {
1266
- clearTimeout(timer);
1267
- this.timers.delete(eventId);
1268
- }
1269
- const accumulated = this.buffers.get(eventId);
1270
- this.buffers.delete(eventId);
1271
- if (!accumulated) return;
1272
- const sticky = (_a = this.sticky.get(eventId)) != null ? _a : {};
1273
- const isPending = (_c = (_b = accumulated.isPending) != null ? _b : sticky.isPending) != null ? _c : true;
1274
- const eventName = (_e = (_d = accumulated.eventName) != null ? _d : sticky.eventName) != null ? _e : this.defaultEventName;
1275
- const userId = (_f = accumulated.userId) != null ? _f : sticky.userId;
1276
- if (!userId) {
1277
- if (this.debug) {
1278
- console.warn(`${this.prefix} skipping track_partial for ${eventId}: missing userId`);
1279
- }
1280
- this.sticky.delete(eventId);
1281
- return;
1282
- }
1283
- const { wizardSession, ...restProperties } = (_g = accumulated.properties) != null ? _g : {};
1284
- let telemetryProperties = {};
1285
- try {
1286
- telemetryProperties = eventTelemetryProperties(accumulated);
1287
- } catch (e) {
1288
- }
1289
- const convoId = (_h = accumulated.convoId) != null ? _h : sticky.convoId;
1290
- const payload = {
1291
- event_id: eventId,
1292
- user_id: userId,
1293
- event: eventName,
1294
- timestamp: (_i = accumulated.timestamp) != null ? _i : (/* @__PURE__ */ new Date()).toISOString(),
1295
- ai_data: {
1296
- input: accumulated.input,
1297
- output: accumulated.error !== void 0 && accumulated.error !== null ? void 0 : accumulated.output,
1298
- model: accumulated.model,
1299
- convo_id: convoId
1300
- },
1301
- properties: {
1302
- ...restProperties,
1303
- ...telemetryProperties,
1304
- ...wizardSession ? { "raindrop.wizardSession": wizardSession } : {},
1305
- $context: this.context
1306
- },
1307
- ...accumulated.featureFlags && Object.keys(accumulated.featureFlags).length > 0 ? { feature_flags: accumulated.featureFlags } : {},
1308
- attachments: accumulated.attachments,
1309
- is_pending: isPending
1310
- };
1311
- const url = `${this.baseUrl}events/track_partial`;
1312
- if (this.debug) {
1313
- console.log(`${this.prefix} sending track_partial`, {
1314
- eventId,
1315
- eventName,
1316
- userId,
1317
- convoId,
1318
- isPending,
1319
- inputPreview: typeof accumulated.input === "string" ? accumulated.input.slice(0, 120) : void 0,
1320
- outputPreview: typeof accumulated.output === "string" ? accumulated.output.slice(0, 120) : void 0,
1321
- attachments: (_k = (_j = accumulated.attachments) == null ? void 0 : _j.length) != null ? _k : 0,
1322
- attachmentKinds: (_m = (_l = accumulated.attachments) == null ? void 0 : _l.map((a) => ({
1323
- type: a.type,
1324
- role: a.role,
1325
- name: a.name,
1326
- valuePreview: a.value.slice(0, 60)
1327
- }))) != null ? _m : [],
1328
- endpoint: url
1329
- });
1330
- }
1331
- const mirror = this.localDebuggerUrl ? mirrorPartialEventToLocalDebugger(payload, {
1332
- baseUrl: this.localDebuggerUrl,
1333
- writeKey: this.writeKey,
1334
- debug: this.debug,
1335
- sdkName: this.sdkName
1336
- }) : void 0;
1337
- if (!this.writeKey) {
1338
- if (!isPending) this.sticky.delete(eventId);
1339
- if (mirror) await mirror;
1340
- return;
1341
- }
1342
- const opts = this.requestOpts();
1343
- if (!opts) {
1344
- this.warnShutdownDrop(`track_partial ${eventId}`);
1345
- if (!isPending) this.sticky.delete(eventId);
1346
- if (mirror) await mirror;
1347
- return;
1348
- }
1349
- const p = postJson(url, payload, this.requestHeaders(), opts);
1350
- const combined = mirror ? Promise.all([mirror, p]).then(() => void 0) : p;
1351
- this.inFlight.add(combined);
1352
- try {
1353
- try {
1354
- await combined;
1355
- if (this.debug) {
1356
- console.log(`${this.prefix} sent track_partial ${eventId} (${eventName})`);
1357
- }
1358
- } catch (err) {
1359
- const msg = err instanceof Error ? err.message : String(err);
1360
- rateLimitedLog(
1361
- `${this.prefix}.send_track_partial_failed`,
1362
- () => console.warn(`${this.prefix} failed to send track_partial (dropping): ${msg}`)
1363
- );
1364
- }
1365
- } finally {
1366
- this.inFlight.delete(combined);
1367
- }
1368
- if (!isPending) {
1369
- this.sticky.delete(eventId);
1370
- }
1371
- }
1372
- };
1373
- var MODEL_USAGE_ATTRIBUTES = {
1374
- usageSource: "raindrop.usage.source",
1375
- providerName: "gen_ai.provider.name",
1376
- requestModel: "gen_ai.request.model",
1377
- responseModel: "gen_ai.response.model",
1378
- inputTokens: "gen_ai.usage.input_tokens",
1379
- outputTokens: "gen_ai.usage.output_tokens",
1380
- reasoningTokens: "gen_ai.usage.reasoning_tokens",
1381
- cacheReadInputTokens: "gen_ai.usage.cache_read_input_tokens",
1382
- cacheWriteInputTokens: "gen_ai.usage.cache_write_input_tokens",
1383
- providerReportedCost: "gen_ai.usage.provider_reported_cost",
1384
- nonCachedInputTokens: "raindrop.usage.input_tokens.non_cached",
1385
- nonReasoningOutputTokens: "raindrop.usage.output_tokens.non_reasoning",
1386
- totalOutputTokens: "raindrop.usage.output_tokens.total",
1387
- reasoningOutputTokens: "raindrop.usage.output_tokens.reasoning",
1388
- cacheReadTokens: "raindrop.usage.input_tokens.cache_read",
1389
- cacheWriteTokens: "raindrop.usage.input_tokens.cache_write"
1390
- };
1391
- var MODEL_PROVIDER_NAMES = [
1392
- ["google.vertex.anthropic", "google-vertex"],
1393
- ["google.vertex_ai", "google-vertex"],
1394
- ["google.vertex", "google-vertex"],
1395
- ["gcp.vertex_ai", "google-vertex"],
1396
- ["gcp.gemini", "google"],
1397
- ["google_vertexai", "google-vertex"],
1398
- ["vertex.anthropic", "google-vertex"],
1399
- ["amazon-bedrock", "amazon-bedrock"],
1400
- ["aws.bedrock", "amazon-bedrock"],
1401
- ["bedrock", "amazon-bedrock"],
1402
- ["anthropic", "anthropic"],
1403
- ["openai", "openai"],
1404
- ["google", "google"],
1405
- ["az.ai.openai", "azure"],
1406
- ["azure", "azure"],
1407
- ["openrouter", "openrouter"]
1408
- ];
1409
- function canonicalModelProvider(provider) {
1410
- var _a;
1411
- const normalizedProvider = provider.trim().toLowerCase();
1412
- if (normalizedProvider === "gateway") return "vercel";
1413
- const match = MODEL_PROVIDER_NAMES.find(
1414
- ([family]) => normalizedProvider === family || normalizedProvider.startsWith(`${family}.`)
1415
- );
1416
- return (_a = match == null ? void 0 : match[1]) != null ? _a : normalizedProvider;
1417
- }
1418
- function tokenCount(value) {
1419
- return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
1420
- }
1421
- function buildRawModelUsageAttributes(usage) {
1422
- const providerReportedCost = typeof usage.providerReportedCost === "number" && Number.isFinite(usage.providerReportedCost) && usage.providerReportedCost >= 0 ? usage.providerReportedCost : void 0;
1423
- return [
1424
- attrInt(MODEL_USAGE_ATTRIBUTES.inputTokens, tokenCount(usage.inputTokens)),
1425
- attrInt(MODEL_USAGE_ATTRIBUTES.outputTokens, tokenCount(usage.outputTokens)),
1426
- attrInt(MODEL_USAGE_ATTRIBUTES.reasoningTokens, tokenCount(usage.reasoningTokens)),
1427
- attrInt(MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens, tokenCount(usage.cacheReadInputTokens)),
1428
- attrInt(MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens, tokenCount(usage.cacheWriteInputTokens)),
1429
- attrDouble(MODEL_USAGE_ATTRIBUTES.providerReportedCost, providerReportedCost)
1430
- ].filter((attribute) => attribute !== void 0);
1431
- }
1432
- var STRING_ALIASES = {
1433
- [MODEL_USAGE_ATTRIBUTES.requestModel]: ["ai.model.id", "ai.model"]
1434
- };
1435
- var NUMBER_ALIASES = {
1436
- [MODEL_USAGE_ATTRIBUTES.inputTokens]: [
1437
- "gen_ai.usage.prompt_tokens",
1438
- "ai.usage.prompt_tokens",
1439
- "ai.usage.promptTokens",
1440
- "ai.usage.input_tokens",
1441
- "ai.usage.inputTokens"
1442
- ],
1443
- [MODEL_USAGE_ATTRIBUTES.outputTokens]: [
1444
- "gen_ai.usage.completion_tokens",
1445
- "ai.usage.completion_tokens",
1446
- "ai.usage.completionTokens",
1447
- "ai.usage.output_tokens",
1448
- "ai.usage.outputTokens"
1449
- ],
1450
- [MODEL_USAGE_ATTRIBUTES.reasoningTokens]: [
1451
- "gen_ai.usage.reasoning.output_tokens",
1452
- "ai.usage.reasoningTokens",
1453
- "ai.usage.thoughts_tokens"
1454
- ],
1455
- [MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens]: [
1456
- "gen_ai.usage.cache_read_tokens",
1457
- "gen_ai.usage.cache_read.input_tokens",
1458
- "ai.usage.cachedInputTokens",
1459
- "ai.usage.cached_tokens",
1460
- "ai.usage.cache_read_tokens",
1461
- "ai.usage.cache_read_input_tokens",
1462
- "ai.usage.cacheReadInputTokens"
1463
- ],
1464
- [MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens]: [
1465
- "gen_ai.usage.cache_creation_input_tokens",
1466
- "gen_ai.usage.cache_creation.input_tokens",
1467
- "ai.usage.cacheWriteInputTokens",
1468
- "ai.usage.cache_creation_input_tokens",
1469
- "ai.usage.cacheCreationInputTokens"
1470
- ]
1471
- };
1472
- function hasAttribute(attributes, key) {
1473
- return attributes.some((attribute) => attribute.key === key);
1474
- }
1475
- function findStringAttribute(attributes, keys) {
1476
- return attributes.find(
1477
- (attribute) => keys.includes(attribute.key) && typeof attribute.value.stringValue === "string" && attribute.value.stringValue.length > 0
1478
- );
1479
- }
1480
- function findNumberAttribute(attributes, keys) {
1481
- return attributes.find((attribute) => {
1482
- if (!keys.includes(attribute.key)) return false;
1483
- if (typeof attribute.value.doubleValue === "number" && Number.isSafeInteger(attribute.value.doubleValue) && attribute.value.doubleValue >= 0) {
1484
- return true;
1485
- }
1486
- const intValue = attribute.value.intValue;
1487
- return integerValue(intValue) !== void 0;
1488
- });
1489
- }
1490
- function integerValue(value) {
1491
- if (typeof value === "number") {
1492
- return Number.isSafeInteger(value) && value >= 0 ? value : void 0;
1493
- }
1494
- if (typeof value !== "string") return void 0;
1495
- const parsed = Number(value);
1496
- return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : void 0;
1497
- }
1498
- function appendAlias(attributes, target, source) {
1499
- if (!source || hasAttribute(attributes, target)) return attributes;
1500
- return [...attributes, { key: target, value: { ...source.value } }];
1501
- }
1502
- function appendProviderAlias(attributes) {
1503
- if (hasAttribute(attributes, MODEL_USAGE_ATTRIBUTES.providerName)) return attributes;
1504
- const source = findStringAttribute(attributes, ["gen_ai.system", "ai.model.provider"]);
1505
- if (!(source == null ? void 0 : source.value.stringValue)) return attributes;
1506
- const attribute = attrString(
1507
- MODEL_USAGE_ATTRIBUTES.providerName,
1508
- canonicalModelProvider(source.value.stringValue)
1509
- );
1510
- return attribute ? [...attributes, attribute] : attributes;
1511
- }
1512
- function normalizeModelUsageSpan(span) {
1513
- const original = span.attributes;
1514
- if (!original || original.length === 0) return span;
1515
- const responseModel = findStringAttribute(original, [
1516
- MODEL_USAGE_ATTRIBUTES.responseModel,
1517
- "ai.response.model"
1518
- ]);
1519
- if (!responseModel) return span;
1520
- let attributes = appendAlias(original, MODEL_USAGE_ATTRIBUTES.responseModel, responseModel);
1521
- attributes = appendProviderAlias(attributes);
1522
- for (const [target, aliases] of Object.entries(STRING_ALIASES)) {
1523
- attributes = appendAlias(attributes, target, findStringAttribute(attributes, aliases));
1524
- }
1525
- for (const [target, aliases] of Object.entries(NUMBER_ALIASES)) {
1526
- attributes = appendAlias(attributes, target, findNumberAttribute(attributes, aliases));
1527
- }
1528
- return attributes === original ? span : { ...span, attributes };
1529
- }
1530
- var DEFAULT_SECRET_KEY_NAMES = [
1531
- "apikey",
1532
- "apisecret",
1533
- "apitoken",
1534
- "secretaccesskey",
1535
- "sessiontoken",
1536
- "privatekey",
1537
- "privatekeyid",
1538
- "clientsecret",
1539
- "accesstoken",
1540
- "refreshtoken",
1541
- "oauthtoken",
1542
- "bearertoken",
1543
- "authorization",
1544
- "password",
1545
- "passphrase"
1546
- ];
1547
- var REDACTED_PLACEHOLDER = "[REDACTED]";
1548
- function normalizeKeyName(name) {
1549
- return name.toLowerCase().replace(/[-_.]/g, "");
1550
- }
1551
- function redactSecretsInObject(value, options) {
1552
- var _a, _b;
1553
- const normalizedSecretSet = buildSecretSet((_a = options == null ? void 0 : options.secretKeyNames) != null ? _a : DEFAULT_SECRET_KEY_NAMES);
1554
- const placeholder = (_b = options == null ? void 0 : options.placeholder) != null ? _b : REDACTED_PLACEHOLDER;
1555
- const seen = /* @__PURE__ */ new WeakSet();
1556
- const walk = (node) => {
1557
- if (node === null || typeof node !== "object") return node;
1558
- if (seen.has(node)) return "[CIRCULAR]";
1559
- seen.add(node);
1560
- if (Array.isArray(node)) {
1561
- return node.map((item) => walk(item));
1562
- }
1563
- const out = {};
1564
- for (const [k, v] of Object.entries(node)) {
1565
- if (normalizedSecretSet.has(normalizeKeyName(k))) {
1566
- out[k] = placeholder;
1567
- } else {
1568
- out[k] = walk(v);
1569
- }
1570
- }
1571
- return out;
1572
- };
1573
- return walk(value);
1574
- }
1575
- function buildSecretSet(names) {
1576
- const set = /* @__PURE__ */ new Set();
1577
- for (const name of names) set.add(normalizeKeyName(name));
1578
- return set;
1579
- }
1580
- var DEFAULT_REDACT_ATTRIBUTE_KEYS = [
1581
- "ai.request.providerOptions",
1582
- "ai.response.providerMetadata"
1583
- ];
1584
- function defaultTransformSpan(span) {
1585
- const attrs = span.attributes;
1586
- if (!attrs || attrs.length === 0) return span;
1587
- let nextAttrs;
1588
- for (let i = 0; i < attrs.length; i++) {
1589
- const attr = attrs[i];
1590
- const redacted = redactJsonAttributeValue(attr.key, attr.value);
1591
- if (redacted === void 0) continue;
1592
- if (!nextAttrs) nextAttrs = attrs.slice();
1593
- nextAttrs[i] = { key: attr.key, value: redacted };
1594
- }
1595
- if (!nextAttrs) return span;
1596
- return { ...span, attributes: nextAttrs };
1597
- }
1598
- var REDACT_JSON_ATTRIBUTE_KEYS = new Set(DEFAULT_REDACT_ATTRIBUTE_KEYS);
1599
- function redactJsonAttributeValue(key, value) {
1600
- if (!REDACT_JSON_ATTRIBUTE_KEYS.has(key)) return void 0;
1601
- const json = value.stringValue;
1602
- if (typeof json !== "string" || json.length === 0) return void 0;
1603
- let parsed;
1604
- try {
1605
- parsed = JSON.parse(json);
1606
- } catch (e) {
1607
- return void 0;
1608
- }
1609
- const scrubbed = redactSecretsInObject(parsed);
1610
- let scrubbedJson;
1611
- try {
1612
- scrubbedJson = JSON.stringify(scrubbed);
1613
- } catch (e) {
1614
- return void 0;
1615
- }
1616
- if (scrubbedJson === json) return void 0;
1617
- return { stringValue: scrubbedJson };
1618
- }
1619
- function appGitOwnerId2(prefix) {
1620
- try {
1621
- return `${prefix}:${randomUUID()}`;
1622
- } catch (e) {
1623
- return `${prefix}:${Date.now().toString(36)}:${Math.random().toString(36).slice(2)}`;
1624
- }
1625
- }
1626
- function identityAttrs(args) {
1627
- return [
1628
- attrString("ai.telemetry.metadata.raindrop.ai.userId", args.userId),
1629
- attrString("ai.telemetry.metadata.raindrop.convoId", args.convoId),
1630
- attrString("ai.telemetry.metadata.raindrop.eventName", args.eventName)
1631
- ];
1632
- }
1633
- function applyOtelSpanAttributeLimit(limit) {
1634
- var _a, _b;
1635
- try {
1636
- const raw = (_b = (_a = globalThis == null ? void 0 : globalThis.process) == null ? void 0 : _a.env) == null ? void 0 : _b.OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT;
1637
- if (!raw) return limit;
1638
- const parsed = Number.parseInt(raw, 10);
1639
- if (Number.isFinite(parsed) && parsed > 0) {
1640
- return Math.min(limit, parsed);
1641
- }
1642
- } catch (e) {
1643
- }
1644
- return limit;
1645
- }
1646
- var TraceShipper = class {
1647
- constructor(opts) {
1648
- this.appGitOwner = appGitOwnerId2("trace");
1649
- this.appGitEventIds = /* @__PURE__ */ new WeakMap();
1650
- this.appGitActiveSpans = /* @__PURE__ */ new Map();
1651
- this.appGitCaptured = /* @__PURE__ */ new WeakSet();
1652
- this.appGitAdded = /* @__PURE__ */ new WeakMap();
1653
- this.queue = [];
1654
- this.inFlight = /* @__PURE__ */ new Set();
1655
- this.hasShutdown = false;
1656
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
1657
- this.appGitContext = (_a = opts.appGitContext) != null ? _a : createAppGitContext(opts.appGit);
1658
- this.ownsAppGitContext = opts.appGitContext === void 0;
1659
- this.writeKey = (_b = opts.writeKey) == null ? void 0 : _b.trim();
1660
- this.baseUrl = (_c = formatEndpoint(opts.endpoint)) != null ? _c : "https://api.raindrop.ai/v1/";
1661
- this.enabled = opts.enabled !== false;
1662
- this.debug = opts.debug;
1663
- this.debugSpans = opts.debugSpans === true;
1664
- this.flushIntervalMs = (_d = opts.flushIntervalMs) != null ? _d : 1e3;
1665
- this.maxBatchSize = (_e = opts.maxBatchSize) != null ? _e : 50;
1666
- this.maxQueueSize = (_f = opts.maxQueueSize) != null ? _f : 5e3;
1667
- this.sdkName = (_g = opts.sdkName) != null ? _g : "core";
1668
- this.prefix = `[raindrop-ai/${this.sdkName}]`;
1669
- this.serviceName = (_h = opts.serviceName) != null ? _h : "raindrop.core";
1670
- this.serviceVersion = (_i = opts.serviceVersion) != null ? _i : "0.0.0";
1671
- this.localDebuggerUrl = (_j = resolveLocalDebuggerBaseUrl(opts.localDebuggerUrl)) != null ? _j : void 0;
1672
- if (this.debug && this.localDebuggerUrl) {
1673
- console.log(`${this.prefix} Local debugger mirroring: ${this.localDebuggerUrl}`);
1674
- }
1675
- this.projectId = normalizeProjectId(opts.projectId, {
1676
- debug: this.debug,
1677
- prefix: this.prefix
1678
- });
1679
- this.transformSpanHook = opts.transformSpan;
1680
- this.disableDefaultRedaction = opts.disableDefaultRedaction === true;
1681
- this.maxTextFieldCharsOpt = opts.maxTextFieldChars;
1682
- }
1683
- /**
1684
- * Cap every string attribute value on the span. O(#attributes) length
1685
- * checks; only oversized values pay a slice. Runs AFTER the redaction
1686
- * pipeline so the default secret-scrub still sees parseable JSON in
1687
- * `ai.request.providerOptions` / `ai.response.providerMetadata` (capping
1688
- * first could cut a JSON blob mid-way, fail the parse, and ship secrets
1689
- * in the surviving prefix).
1690
- *
1691
- * A stricter `OTEL_SPAN_ATTRIBUTE_VALUE_LENGTH_LIMIT` env var is honored
1692
- * for span content, matching the Python SDK and the OTel SDK convention.
1693
- */
1694
- capSpanAttributes(span) {
1695
- var _a;
1696
- const maxChars = applyOtelSpanAttributeLimit(
1697
- resolveMaxTextFieldChars(this.maxTextFieldCharsOpt)
1698
- );
1699
- const attrs = span.attributes;
1700
- if (!attrs || attrs.length === 0) return span;
1701
- let nextAttrs;
1702
- for (let i = 0; i < attrs.length; i++) {
1703
- const attr = attrs[i];
1704
- const value = (_a = attr.value) == null ? void 0 : _a.stringValue;
1705
- if (typeof value !== "string" || value.length <= maxChars) continue;
1706
- if (!nextAttrs) nextAttrs = attrs.slice();
1707
- nextAttrs[i] = {
1708
- key: attr.key,
1709
- value: { ...attr.value, stringValue: capText(value, maxChars) }
1710
- };
1711
- }
1712
- if (!nextAttrs) return span;
1713
- return { ...span, attributes: nextAttrs };
1714
- }
1715
- /**
1716
- * Apply the user `transformSpan` hook (if any) followed by the default
1717
- * redactor (unless disabled). Returns either the (possibly new) span to
1718
- * ship, or `null` to drop the span entirely.
1719
- *
1720
- * Ordering: user hook runs first so callers can rewrite the span freely
1721
- * (rename attrs, add new ones, scrub things the default doesn't know
1722
- * about). The default redactor then runs on whatever the user produced,
1723
- * acting as the always-on floor for documented BYOK secrets. If the user
1724
- * sets `disableDefaultRedaction: true`, the floor is skipped.
1725
- *
1726
- * Fail-closed: if the user hook throws, the span is dropped — a buggy
1727
- * hook can never accidentally ship raw, un-redacted spans.
1728
- */
1729
- redactSpan(span) {
1730
- let current = span;
1731
- if (this.transformSpanHook) {
1732
- try {
1733
- const result = this.transformSpanHook(current);
1734
- if (result === null) return null;
1735
- if (result !== void 0) {
1736
- copyReplayTraceDestination(current, result);
1737
- current = result;
1738
- }
1739
- } catch (err) {
1740
- if (this.debug) {
1741
- const msg = err instanceof Error ? err.message : String(err);
1742
- console.warn(`${this.prefix} transformSpan hook threw: ${msg}`);
1743
- }
1744
- return null;
1745
- }
1746
- }
1747
- try {
1748
- const normalized = normalizeModelUsageSpan(current);
1749
- copyReplayTraceDestination(current, normalized);
1750
- current = normalized;
1751
- } catch (e) {
1752
- }
1753
- if (!this.disableDefaultRedaction) {
1754
- const redacted = defaultTransformSpan(current);
1755
- copyReplayTraceDestination(current, redacted);
1756
- current = redacted;
1757
- }
1758
- const capped = this.capSpanAttributes(current);
1759
- copyReplayTraceDestination(current, capped);
1760
- return capped;
1761
- }
1762
- isDebugEnabled() {
1763
- return this.debug;
1764
- }
1765
- authHeaders() {
1766
- return this.writeKey ? { Authorization: `Bearer ${this.writeKey}` } : {};
1767
- }
1768
- requestHeaders() {
1769
- return { ...this.authHeaders(), ...projectIdHeaders(this.projectId) };
1770
- }
1771
- startSpan(args) {
1772
- var _a, _b, _c;
1773
- const ids = createSpanIds(args.parent);
1774
- const started = (_a = args.startTimeUnixNano) != null ? _a : nowUnixNanoString();
1775
- const attrs = [
1776
- attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId),
1777
- ...identityAttrs(args),
1778
- attrString("ai.operationId", args.operationId),
1779
- ...Object.entries(evalScopeAttributes()).map(([key, value]) => attrString(key, value))
1780
- ];
1781
- if ((_b = args.attributes) == null ? void 0 : _b.length) attrs.push(...args.attributes);
1782
- const tracksAppGit = this.appGitActiveSpans.has(args.eventId) || this.appGitActiveSpans.size < 1e4;
1783
- const appGitOverrides = appGitPropertiesFromAttributes(attrs);
1784
- const span = {
1785
- ids,
1786
- name: args.name,
1787
- startTimeUnixNano: started,
1788
- attributes: withAppGitAttributes(
1789
- attrs,
1790
- this.appGitContext.forOperation(args.eventId, appGitOverrides, this.appGitOwner)
1791
- )
1792
- };
1793
- rememberReplayTraceDestination(span);
1794
- this.appGitCaptured.add(span);
1795
- this.appGitEventIds.set(span, args.eventId);
1796
- if (tracksAppGit) {
1797
- this.appGitActiveSpans.set(args.eventId, ((_c = this.appGitActiveSpans.get(args.eventId)) != null ? _c : 0) + 1);
1798
- }
1799
- this.appGitAdded.set(span, new Set(span.attributes.filter((attr) => !attrs.includes(attr))));
1800
- const openSpan = buildOtlpSpan({
1801
- ids: span.ids,
1802
- name: span.name,
1803
- startTimeUnixNano: span.startTimeUnixNano,
1804
- endTimeUnixNano: span.startTimeUnixNano,
1805
- // placeholder — will be updated on endSpan
1806
- attributes: span.attributes,
1807
- status: { code: SpanStatusCode.UNSET }
1808
- });
1809
- copyReplayTraceDestination(span, openSpan);
1810
- this.mirrorToLocalDebugger(openSpan);
1811
- return span;
1812
- }
1813
- mirrorToLocalDebugger(span, completed = false) {
1814
- const destination = replayTraceDestinationFor(span);
1815
- if (destination && destination.kind !== "workshop") return;
1816
- const localDebuggerUrl = (destination == null ? void 0 : destination.kind) === "workshop" ? destination.url : this.localDebuggerUrl;
1817
- if (!localDebuggerUrl) return;
1818
- const redacted = this.redactSpan(span);
1819
- if (redacted === null) return;
1820
- if (completed && (destination == null ? void 0 : destination.kind) === "workshop") {
1821
- recordReplayExportedSpan(
1822
- destination,
1823
- base64ToHex(redacted.spanId),
1824
- base64ToHex(redacted.traceId)
1825
- );
1826
- }
1827
- const body = buildExportTraceServiceRequest([redacted], this.serviceName, this.serviceVersion);
1828
- const p = mirrorTraceExportToLocalDebugger(body, {
1829
- baseUrl: localDebuggerUrl,
1830
- debug: false,
1831
- sdkName: this.sdkName
1832
- });
1833
- this.inFlight.add(p);
1834
- void p.finally(() => {
1835
- this.inFlight.delete(p);
1836
- });
1837
- }
1838
- endSpan(span, extra) {
1839
- var _a, _b, _c;
1840
- if (span.endTimeUnixNano) return;
1841
- span.endTimeUnixNano = (_a = extra == null ? void 0 : extra.endTimeUnixNano) != null ? _a : nowUnixNanoString();
1842
- if ((_b = extra == null ? void 0 : extra.attributes) == null ? void 0 : _b.length) {
1843
- const overrides = appGitPropertiesFromAttributes(extra.attributes);
1844
- const eventId2 = this.appGitEventIds.get(span);
1845
- const snapshot = eventId2 ? this.appGitContext.forOperation(eventId2, overrides, this.appGitOwner) : overrides;
1846
- const added = this.appGitAdded.get(span);
1847
- 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));
1848
- span.attributes.push(...extra.attributes);
1849
- span.attributes = withAppGitAttributes(span.attributes, snapshot);
1850
- }
1851
- let status = extra == null ? void 0 : extra.status;
1852
- if (!status && (extra == null ? void 0 : extra.error) !== void 0) {
1853
- const message = extra.error instanceof Error ? extra.error.message : String(extra.error);
1854
- status = { code: SpanStatusCode.ERROR, message };
1855
- }
1856
- const otlp = buildOtlpSpan({
1857
- ids: span.ids,
1858
- name: span.name,
1859
- startTimeUnixNano: span.startTimeUnixNano,
1860
- endTimeUnixNano: span.endTimeUnixNano,
1861
- attributes: span.attributes,
1862
- status
1863
- });
1864
- copyReplayTraceDestination(span, otlp);
1865
- this.appGitCaptured.add(otlp);
1866
- this.enqueue(otlp);
1867
- this.mirrorToLocalDebugger(otlp, true);
1868
- const eventId = this.appGitEventIds.get(span);
1869
- if (eventId && this.appGitActiveSpans.has(eventId)) {
1870
- const remaining = ((_c = this.appGitActiveSpans.get(eventId)) != null ? _c : 1) - 1;
1871
- if (remaining > 0) this.appGitActiveSpans.set(eventId, remaining);
1872
- else {
1873
- this.appGitActiveSpans.delete(eventId);
1874
- if (this.appGitContext.releaseOperation) this.appGitContext.releaseOperation(eventId, this.appGitOwner);
1875
- else if (this.ownsAppGitContext) this.appGitContext.finishOperation(eventId);
1876
- }
1877
- }
1878
- }
1879
- createSpan(args) {
1880
- var _a;
1881
- const ids = createSpanIds(args.parent);
1882
- const attrs = [
1883
- attrString("ai.telemetry.metadata.raindrop.eventId", args.eventId),
1884
- ...identityAttrs(args),
1885
- ...Object.entries(evalScopeAttributes()).map(([key, value]) => attrString(key, value))
1886
- ];
1887
- if ((_a = args.attributes) == null ? void 0 : _a.length) attrs.push(...args.attributes);
1888
- const tracksAppGit = !this.appGitActiveSpans.has(args.eventId);
1889
- const otlp = buildOtlpSpan({
1890
- ids,
1891
- name: args.name,
1892
- startTimeUnixNano: args.startTimeUnixNano,
1893
- endTimeUnixNano: args.endTimeUnixNano,
1894
- attributes: withAppGitAttributes(
1895
- attrs,
1896
- this.appGitContext.forOperation(
1897
- args.eventId,
1898
- appGitPropertiesFromAttributes(attrs),
1899
- this.appGitOwner
1900
- )
1901
- ),
1902
- status: args.status
1903
- });
1904
- rememberReplayTraceDestination(otlp);
1905
- this.appGitCaptured.add(otlp);
1906
- if (tracksAppGit) {
1907
- if (this.appGitContext.releaseOperation) this.appGitContext.releaseOperation(args.eventId, this.appGitOwner);
1908
- else if (this.ownsAppGitContext) this.appGitContext.finishOperation(args.eventId);
1909
- }
1910
- this.enqueue(otlp);
1911
- this.mirrorToLocalDebugger(otlp, true);
1912
- }
1913
- enqueue(span) {
1914
- var _a;
1915
- if (!this.enabled) return;
1916
- const attributes = (_a = span.attributes) != null ? _a : [];
1917
- const enriched = this.appGitCaptured.has(span) ? attributes : withAppGitAttributes(attributes, this.appGitContext.snapshot(appGitPropertiesFromAttributes(attributes)));
1918
- if (enriched !== attributes) {
1919
- const original = span;
1920
- span = { ...span, attributes: enriched.filter((attr) => attr !== void 0) };
1921
- copyReplayTraceDestination(original, span);
1922
- }
1923
- if (this.debugSpans) {
1924
- const short = (s) => s ? s.slice(-8) : "none";
1925
- console.log(
1926
- `${this.prefix}[span] name=${span.name} trace=${short(span.traceId)} span=${short(span.spanId)} parent=${short(
1927
- span.parentSpanId
1928
- )}`
1929
- );
1930
- }
1931
- const redacted = this.redactSpan(span);
1932
- if (redacted === null) return;
1933
- const destination = replayTraceDestinationFor(redacted);
1934
- recordReplayExportedSpan(
1935
- destination,
1936
- base64ToHex(redacted.spanId),
1937
- base64ToHex(redacted.traceId)
1938
- );
1939
- if ((destination == null ? void 0 : destination.kind) === "workshop") return;
1940
- if (this.queue.length >= this.maxQueueSize) {
1941
- this.queue.shift();
1942
- }
1943
- this.queue.push(redacted);
1944
- if (this.queue.length >= this.maxBatchSize) {
1945
- void this.flush().catch(() => {
1946
- });
1947
- return;
1948
- }
1949
- if (!this.timer) {
1950
- this.timer = setTimeout(() => {
1951
- this.timer = void 0;
1952
- void this.flush().catch(() => {
1953
- });
1954
- }, this.flushIntervalMs);
1955
- }
1956
- }
1957
- async flush() {
1958
- var _a;
1959
- if (!this.enabled) {
1960
- await Promise.all([...this.inFlight].map((p) => p.catch(() => {
1961
- })));
1962
- return;
1963
- }
1964
- if (this.timer) {
1965
- clearTimeout(this.timer);
1966
- this.timer = void 0;
1967
- }
1968
- while (this.queue.length > 0) {
1969
- const batch = this.queue.splice(0, this.maxBatchSize);
1970
- const groups = /* @__PURE__ */ new Map();
1971
- for (const span of batch) {
1972
- const destination = replayTraceDestinationFor(span);
1973
- const spans = groups.get(destination);
1974
- if (spans) spans.push(span);
1975
- else groups.set(destination, [span]);
1976
- }
1977
- for (const [destination, spans] of groups) {
1978
- if (!destination && !this.writeKey) continue;
1979
- if ((destination == null ? void 0 : destination.kind) === "workshop") continue;
1980
- const opts = this.requestOpts();
1981
- if (!opts) {
1982
- rateLimitedLog(
1983
- `${this.prefix}.shutdown_deadline`,
1984
- () => console.warn(
1985
- `${this.prefix} shutdown flush deadline exceeded; dropping ${spans.length} spans`
1986
- )
1987
- );
1988
- continue;
1989
- }
1990
- const body = buildExportTraceServiceRequest(spans, this.serviceName, this.serviceVersion);
1991
- const url = destination ? replayTraceUrl(destination.url) : `${this.baseUrl}traces`;
1992
- const headers = destination ? {
1993
- Authorization: `Bearer ${destination.apiKey}`,
1994
- "X-Raindrop-Replay-Id": destination.replayId,
1995
- "X-Raindrop-Project-Id": (_a = destination.projectId) != null ? _a : "default"
1996
- } : this.requestHeaders();
1997
- if (this.debug) {
1998
- console.log(`${this.prefix} sending traces batch`, {
1999
- spans: spans.length,
2000
- endpoint: url
2001
- });
2002
- }
2003
- const p = postJson(url, body, headers, opts);
2004
- this.inFlight.add(p);
2005
- try {
2006
- try {
2007
- await p;
2008
- if (this.debug) console.log(`${this.prefix} sent ${spans.length} spans`);
2009
- } catch (err) {
2010
- const msg = err instanceof Error ? err.message : String(err);
2011
- rateLimitedLog(
2012
- `${this.prefix}.send_spans_failed`,
2013
- () => console.warn(`${this.prefix} failed to send ${spans.length} spans: ${msg}`)
2014
- );
2015
- }
2016
- } finally {
2017
- this.inFlight.delete(p);
2018
- }
2019
- }
2020
- }
2021
- }
2022
- /** See EventShipper.requestOpts — same shutdown-budget semantics. */
2023
- requestOpts() {
2024
- if (this.shutdownDeadlineAt !== void 0) {
2025
- const remainingMs = this.shutdownDeadlineAt - Date.now();
2026
- if (remainingMs <= 0) return null;
2027
- return {
2028
- maxAttempts: 1,
2029
- debug: this.debug,
2030
- sdkName: this.sdkName,
2031
- timeoutMs: Math.min(DEFAULT_REQUEST_TIMEOUT_MS, remainingMs)
2032
- };
2033
- }
2034
- if (this.hasShutdown) {
2035
- return {
2036
- maxAttempts: 1,
2037
- debug: this.debug,
2038
- sdkName: this.sdkName,
2039
- timeoutMs: POST_SHUTDOWN_TIMEOUT_MS
2040
- };
2041
- }
2042
- return { maxAttempts: 3, debug: this.debug, sdkName: this.sdkName };
2043
- }
2044
- async shutdown() {
2045
- this.hasShutdown = true;
2046
- this.shutdownDeadlineAt = Date.now() + SHUTDOWN_DEADLINE_MS;
2047
- try {
2048
- if (this.timer) {
2049
- clearTimeout(this.timer);
2050
- this.timer = void 0;
2051
- }
2052
- const drain = async () => {
2053
- await this.flush();
2054
- await Promise.all([...this.inFlight].map((p) => p.catch(() => {
2055
- })));
2056
- };
2057
- const settled = await raceWithTimeout(drain(), SHUTDOWN_DEADLINE_MS);
2058
- if (!settled) {
2059
- rateLimitedLog(
2060
- `${this.prefix}.shutdown_deadline`,
2061
- () => console.warn(
2062
- `${this.prefix} shutdown flush deadline exceeded; abandoning in-flight spans`
2063
- )
2064
- );
2065
- }
2066
- } finally {
2067
- this.shutdownDeadlineAt = void 0;
2068
- if (this.ownsAppGitContext) this.appGitContext.dispose();
2069
- }
2070
- }
2071
- };
2072
-
2073
- // ../core/dist/index.node.js
2074
- import { AsyncLocalStorage } from "async_hooks";
2075
- import { execFile } from "child_process";
2076
- import { resolve } from "path";
2077
- var resolveLocal = (sourceDirectory, detectBranch, completed) => {
2078
- const cwd = sourceDirectory ? resolve(sourceDirectory) : process.cwd();
2079
- let cancelled = false;
2080
- let active;
2081
- let deadlineTimer;
2082
- const deadline = Date.now() + 1e3;
2083
- const run = (args, done) => {
2084
- if (cancelled) return;
2085
- const remaining = deadline - Date.now();
2086
- if (remaining <= 0) {
2087
- done(void 0);
2088
- return;
2089
- }
2090
- try {
2091
- active = execFile(
2092
- "git",
2093
- args,
2094
- {
2095
- cwd,
2096
- encoding: "utf8",
2097
- maxBuffer: 4096,
2098
- windowsHide: true,
2099
- env: {
2100
- ...process.env,
2101
- // The selected application cwd, not the invoking shell's Git plumbing, owns identity.
2102
- GIT_DIR: void 0,
2103
- GIT_WORK_TREE: void 0,
2104
- GIT_COMMON_DIR: void 0,
2105
- GIT_NAMESPACE: void 0,
2106
- GIT_INDEX_FILE: void 0,
2107
- GIT_OBJECT_DIRECTORY: void 0,
2108
- GIT_ALTERNATE_OBJECT_DIRECTORIES: void 0,
2109
- GIT_CONFIG_PARAMETERS: void 0,
2110
- GIT_CONFIG_COUNT: "0",
2111
- GIT_TERMINAL_PROMPT: "0",
2112
- GIT_OPTIONAL_LOCKS: "0"
2113
- }
2114
- },
2115
- (error, stdout) => {
2116
- clearTimeout(deadlineTimer);
2117
- deadlineTimer = void 0;
2118
- active = void 0;
2119
- if (!cancelled) {
2120
- try {
2121
- done(error ? void 0 : stdout.trim());
2122
- } catch (e) {
2123
- }
2124
- }
2125
- }
2126
- );
2127
- active.unref();
2128
- if (active.stdout && "unref" in active.stdout && typeof active.stdout.unref === "function")
2129
- active.stdout.unref();
2130
- if (active.stderr && "unref" in active.stderr && typeof active.stderr.unref === "function")
2131
- active.stderr.unref();
2132
- deadlineTimer = setTimeout(() => {
2133
- try {
2134
- active == null ? void 0 : active.kill("SIGKILL");
2135
- } catch (e) {
2136
- }
2137
- }, remaining);
2138
- deadlineTimer.unref();
2139
- } catch (e) {
2140
- try {
2141
- done(void 0);
2142
- } catch (e2) {
2143
- }
2144
- }
2145
- };
2146
- const scheduled = setTimeout(() => {
2147
- try {
2148
- run(["rev-parse", "HEAD"], (rawSha) => {
2149
- const commitSha = validAppCommitSha(rawSha);
2150
- if (!commitSha) {
2151
- completed({});
2152
- return;
2153
- }
2154
- run(["-c", "core.fsmonitor=false", "status", "--porcelain"], (status) => {
2155
- const finish = (branch) => {
2156
- run(["rev-parse", "HEAD"], (finalSha) => {
2157
- const coherent = validAppCommitSha(finalSha) === commitSha;
2158
- completed({
2159
- commitSha,
2160
- ...coherent && status !== void 0 ? { commitDirty: status !== "" } : {},
2161
- ...coherent && branch && branch !== "HEAD" ? { branch } : {}
2162
- });
2163
- });
2164
- };
2165
- if (detectBranch) run(["symbolic-ref", "--quiet", "--short", "HEAD"], finish);
2166
- else finish();
2167
- });
2168
- });
2169
- } catch (e) {
2170
- completed({});
2171
- }
2172
- }, 0);
2173
- scheduled.unref();
2174
- return () => {
2175
- cancelled = true;
2176
- clearTimeout(scheduled);
2177
- clearTimeout(deadlineTimer);
2178
- try {
2179
- active == null ? void 0 : active.kill("SIGKILL");
2180
- } catch (e) {
2181
- }
2182
- };
2183
- };
2184
- function createAppGitContext2(options, runtime = {}) {
2185
- return new AppGitContext(options, { ...runtime, resolveLocal });
2186
- }
2187
- function hasDestination(options) {
2188
- var _a;
2189
- if (options.enabled === false) return false;
2190
- return Boolean(((_a = options.writeKey) == null ? void 0 : _a.trim()) || resolveLocalDebuggerBaseUrl(options.localDebuggerUrl));
2191
- }
2192
- var EventShipper2 = class extends EventShipper {
2193
- constructor(options) {
2194
- var _a;
2195
- const ownsAppGitContext = options.appGitContext === void 0;
2196
- const appGitContext = (_a = options.appGitContext) != null ? _a : createAppGitContext2(options.appGit, { allowDiscovery: hasDestination(options) });
2197
- try {
2198
- super({ ...options, appGitContext });
2199
- } catch (error) {
2200
- if (ownsAppGitContext) appGitContext.dispose();
2201
- throw error;
2202
- }
2203
- if (ownsAppGitContext) this.ownAppGitContextForShutdown();
2204
- }
2205
- };
2206
- var TraceShipper2 = class extends TraceShipper {
2207
- constructor(options) {
2208
- var _a;
2209
- const ownsAppGitContext = options.appGitContext === void 0;
2210
- const appGitContext = (_a = options.appGitContext) != null ? _a : createAppGitContext2(options.appGit, { allowDiscovery: hasDestination(options) });
2211
- try {
2212
- super({ ...options, appGitContext });
2213
- } catch (error) {
2214
- if (ownsAppGitContext) appGitContext.dispose();
2215
- throw error;
2216
- }
2217
- this.ownsAppGitContext = ownsAppGitContext;
2218
- }
2219
- };
2220
- globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = AsyncLocalStorage;
2221
- var SUPPRESS_TRACING_KEY = /* @__PURE__ */ Symbol.for(
2222
- "OpenTelemetry SDK Context Key SUPPRESS_TRACING"
2223
- );
2224
- function findOtelContextManager() {
2225
- var _a;
2226
- for (const sym of Object.getOwnPropertySymbols(globalThis)) {
2227
- if (!((_a = sym.description) == null ? void 0 : _a.startsWith("opentelemetry.js.api."))) continue;
2228
- const api = globalThis[sym];
2229
- const cm = api == null ? void 0 : api.context;
2230
- if (cm && typeof cm.with === "function" && typeof cm.active === "function") {
2231
- return cm;
2232
- }
2233
- }
2234
- return void 0;
2235
- }
2236
- function installTracingSuppressionHook() {
2237
- if (typeof globalThis.RAINDROP_SUPPRESS_TRACING === "function") return;
2238
- const hook = (fn) => {
2239
- const cm = findOtelContextManager();
2240
- if (!cm) return fn();
2241
- return cm.with(cm.active().setValue(SUPPRESS_TRACING_KEY, true), fn);
2242
- };
2243
- globalThis.RAINDROP_SUPPRESS_TRACING = hook;
2244
- }
2245
- installTracingSuppressionHook();
2246
-
2247
- // src/config.ts
2248
- import { existsSync, readFileSync } from "fs";
2249
- import { homedir } from "os";
2250
- import { join } from "path";
2251
- function loadConfig(projectDirectory) {
2252
- var _a, _b, _c, _d, _e, _f, _g, _h;
2253
- let merged = {};
2254
- const configPaths = [
2255
- join(homedir(), ".config", "opencode", "raindrop.json"),
2256
- join(projectDirectory, ".opencode", "raindrop.json")
2257
- ];
2258
- for (const configPath of configPaths) {
2259
- try {
2260
- if (existsSync(configPath)) {
2261
- const content = readFileSync(configPath, "utf-8");
2262
- const parsed = JSON.parse(content);
2263
- merged = { ...merged, ...parsed };
2264
- }
2265
- } catch (e) {
2266
- }
2267
- }
2268
- let eventMetadata;
2269
- const envMeta = process.env["RAINDROP_EVENT_METADATA"];
2270
- if (envMeta) {
2271
- try {
2272
- eventMetadata = JSON.parse(envMeta);
2273
- } catch (e) {
2274
- }
2275
- }
2276
- return {
2277
- writeKey: (_b = (_a = process.env["RAINDROP_WRITE_KEY"]) != null ? _a : merged.write_key) != null ? _b : "",
2278
- endpoint: (_d = (_c = process.env["RAINDROP_API_URL"]) != null ? _c : merged.api_url) != null ? _d : "https://api.raindrop.ai/v1",
2279
- projectId: (_e = process.env["RAINDROP_PROJECT_ID"]) != null ? _e : merged.project_id,
2280
- eventName: (_f = merged.event_name) != null ? _f : "opencode_session",
2281
- debug: process.env["RAINDROP_DEBUG"] === "true" ? true : (_g = merged.debug) != null ? _g : false,
2282
- captureSystemPrompt: process.env["RAINDROP_CAPTURE_SYSTEM_PROMPT"] !== void 0 ? process.env["RAINDROP_CAPTURE_SYSTEM_PROMPT"] === "true" : (_h = merged.capture_system_prompt) != null ? _h : false,
2283
- eventMetadata,
2284
- localWorkshopUrl: resolveLocalWorkshopUrl(merged.local_workshop_url),
2285
- appGit: mapAppGit(merged.app_git)
2286
- };
2287
- }
2288
- function mapAppGit(value) {
2289
- if (value === false) return false;
2290
- if (value === null || typeof value !== "object" || Array.isArray(value)) return void 0;
2291
- return {
2292
- commitSha: "commit_sha" in value && (typeof value.commit_sha === "string" || value.commit_sha === null) ? value.commit_sha : void 0,
2293
- commitDirty: "commit_dirty" in value && (typeof value.commit_dirty === "boolean" || value.commit_dirty === null) ? value.commit_dirty : void 0,
2294
- branch: "branch" in value && (typeof value.branch === "string" || value.branch === null) ? value.branch : void 0,
2295
- detectBranch: "detect_branch" in value && typeof value.detect_branch === "boolean" ? value.detect_branch : void 0,
2296
- sourceDirectory: "source_directory" in value && typeof value.source_directory === "string" ? value.source_directory : void 0,
2297
- autoDetect: "auto_detect" in value && typeof value.auto_detect === "boolean" ? value.auto_detect : void 0
2298
- };
2299
- }
2300
- function resolveLocalWorkshopUrl(fileValue) {
2301
- const envValue = process.env["RAINDROP_LOCAL_WORKSHOP_URL"];
2302
- if (envValue !== void 0) {
2303
- if (envValue === "" || envValue.toLowerCase() === "null" || envValue.toLowerCase() === "false") {
2304
- return null;
2305
- }
2306
- return envValue;
2307
- }
2308
- return fileValue;
2309
- }
2310
-
2311
- // package.json
2312
- var package_default = {
2313
- name: "@raindrop-ai/opencode-plugin",
2314
- version: "0.1.4",
2315
- description: "Raindrop observability plugin for OpenCode \u2014 automatic session/event/span tracing",
2316
- type: "module",
2317
- main: "dist/index.js",
2318
- module: "dist/index.js",
2319
- types: "dist/index.d.ts",
2320
- license: "MIT",
2321
- homepage: "https://www.raindrop.ai/docs/integrations/opencode/",
2322
- bugs: {
2323
- url: "https://www.raindrop.ai/docs/support/"
2324
- },
2325
- exports: {
2326
- ".": {
2327
- types: "./dist/index.d.ts",
2328
- import: "./dist/index.js",
2329
- require: "./dist/index.cjs"
2330
- }
2331
- },
2332
- sideEffects: false,
2333
- files: [
2334
- "dist/**"
2335
- ],
2336
- scripts: {
2337
- build: "tsup",
2338
- dev: "tsup --watch",
2339
- clean: "rm -rf dist",
2340
- test: "cd tests && pnpm test"
2341
- },
2342
- peerDependencies: {
2343
- "@opencode-ai/plugin": ">=1.3.0",
2344
- "@opencode-ai/sdk": ">=1.3.0"
2345
- },
2346
- peerDependenciesMeta: {
2347
- "@opencode-ai/sdk": {
2348
- optional: true
2349
- }
2350
- },
2351
- devDependencies: {
2352
- "@raindrop-ai/core": "workspace:*",
2353
- "@opencode-ai/plugin": "^1.3.3",
2354
- "@opencode-ai/sdk": "^1.3.3",
2355
- "@types/node": "^20.11.17",
2356
- tsup: "^8.4.0",
2357
- typescript: "^5.3.3"
2358
- },
2359
- tsup: {
2360
- entry: [
2361
- "src/index.ts"
2362
- ],
2363
- format: [
2364
- "cjs",
2365
- "esm"
2366
- ],
2367
- dts: {
2368
- resolve: true
2369
- },
2370
- clean: true,
2371
- noExternal: [
2372
- "@raindrop-ai/core"
2373
- ]
2374
- },
2375
- publishConfig: {
2376
- access: "public"
2377
- }
2378
- };
2379
-
2380
- // src/package-info.ts
2381
- var PLUGIN_NAME = package_default.name;
2382
- var PLUGIN_VERSION = package_default.version;
2383
-
2384
- // src/shipper.ts
2385
- var EventShipper3 = class extends EventShipper2 {
2386
- constructor(opts) {
2387
- var _a, _b, _c, _d;
2388
- super({
2389
- ...opts,
2390
- sdkName: (_a = opts.sdkName) != null ? _a : "opencode-plugin",
2391
- libraryName: (_b = opts.libraryName) != null ? _b : PLUGIN_NAME,
2392
- libraryVersion: (_c = opts.libraryVersion) != null ? _c : PLUGIN_VERSION,
2393
- defaultEventName: (_d = opts.defaultEventName) != null ? _d : "opencode_session"
2394
- });
2395
- }
2396
- };
2397
- var TraceShipper3 = class extends TraceShipper2 {
2398
- constructor(opts) {
2399
- var _a, _b, _c;
2400
- super({
2401
- ...opts,
2402
- sdkName: (_a = opts.sdkName) != null ? _a : "opencode-plugin",
2403
- serviceName: (_b = opts.serviceName) != null ? _b : "raindrop.opencode-plugin",
2404
- serviceVersion: (_c = opts.serviceVersion) != null ? _c : PLUGIN_VERSION
2405
- });
2406
- }
2407
- enqueue(span) {
2408
- var _a;
2409
- const attrs = (_a = span.attributes) != null ? _a : [];
2410
- attrs.unshift(
2411
- { key: "span.id", value: { stringValue: span.spanId } },
2412
- ...span.parentSpanId ? [{ key: "span.parent.id", value: { stringValue: span.parentSpanId } }] : []
2413
- );
2414
- span.attributes = attrs;
2415
- super.enqueue(span);
2416
- }
2417
- };
1
+ import {
2
+ EventShipper,
3
+ PLUGIN_NAME,
4
+ PLUGIN_VERSION,
5
+ TraceShipper,
6
+ attrString,
7
+ boundedStringify,
8
+ buildLlmGenAiAttributes,
9
+ capText,
10
+ createAppGitContext,
11
+ generateId,
12
+ loadConfig,
13
+ nowUnixNanoString,
14
+ resolveLocalDebuggerBaseUrl
15
+ } from "./chunk-4DAI6CYK.js";
2418
16
 
2419
17
  // src/tracing.ts
2420
18
  import { hostname as osHostname } from "os";
2421
19
 
2422
- // src/bounded.ts
2423
- var TRUNCATION_MARKER2 = "...[truncated by raindrop]";
2424
- var MAX_TEXT_FIELD_CHARS = 1e6;
2425
- var MAX_BOUNDED_DEPTH = 12;
2426
- function truncateToLimit2(text, limit) {
2427
- if (text.length <= limit) return text;
2428
- if (limit > TRUNCATION_MARKER2.length) {
2429
- return text.slice(0, limit - TRUNCATION_MARKER2.length) + TRUNCATION_MARKER2;
2430
- }
2431
- return text.slice(0, limit);
2432
- }
2433
- function capText2(value, limit = MAX_TEXT_FIELD_CHARS) {
2434
- if (value.length <= limit) return value;
2435
- return truncateToLimit2(value, limit);
2436
- }
2437
- function boundedClone2(value, budget, depth) {
2438
- if (budget.remaining <= 0) return TRUNCATION_MARKER2;
2439
- if (typeof value === "string") {
2440
- if (value.length > budget.remaining) {
2441
- const taken = value.slice(0, Math.max(0, budget.remaining)) + TRUNCATION_MARKER2;
2442
- budget.remaining = 0;
2443
- return taken;
2444
- }
2445
- budget.remaining -= Math.max(value.length, 1);
2446
- return value;
2447
- }
2448
- if (value === null || typeof value === "number" || typeof value === "boolean") {
2449
- budget.remaining -= 8;
2450
- return value;
2451
- }
2452
- if (typeof value !== "object") {
2453
- budget.remaining -= 8;
2454
- return value;
2455
- }
2456
- if (depth >= MAX_BOUNDED_DEPTH) {
2457
- budget.remaining -= 16;
2458
- return `<max depth: ${TRUNCATION_MARKER2}>`;
2459
- }
2460
- const withToJson = value;
2461
- if (typeof withToJson.toJSON === "function") {
2462
- try {
2463
- return boundedClone2(withToJson.toJSON(), budget, depth + 1);
2464
- } catch (e) {
2465
- }
2466
- }
2467
- if (Array.isArray(value)) {
2468
- const out2 = [];
2469
- for (const item of value) {
2470
- if (budget.remaining <= 0) {
2471
- out2.push(TRUNCATION_MARKER2);
2472
- break;
2473
- }
2474
- out2.push(boundedClone2(item, budget, depth + 1));
2475
- }
2476
- return out2;
2477
- }
2478
- const out = {};
2479
- for (const key of Object.keys(value)) {
2480
- if (budget.remaining <= 0) {
2481
- out["..."] = TRUNCATION_MARKER2;
2482
- break;
2483
- }
2484
- budget.remaining -= Math.max(key.length, 1);
2485
- out[key] = boundedClone2(value[key], budget, depth + 1);
2486
- }
2487
- return out;
2488
- }
2489
- function boundedStringify(value, limit = MAX_TEXT_FIELD_CHARS) {
2490
- var _a;
2491
- try {
2492
- if (typeof value === "string") {
2493
- return truncateToLimit2(JSON.stringify(capText2(value, limit)), limit);
2494
- }
2495
- const pruned = boundedClone2(value, { remaining: limit + TRUNCATION_MARKER2.length + 256 }, 0);
2496
- return truncateToLimit2((_a = JSON.stringify(pruned)) != null ? _a : "", limit);
2497
- } catch (e) {
2498
- return capText2(String(value), limit);
2499
- }
2500
- }
2501
-
2502
- // src/model-spend.ts
2503
- function parseOpenCodeAssistantTokens(tokens) {
2504
- const input = tokens["input"];
2505
- const output = tokens["output"];
2506
- if (typeof input !== "number" || typeof output !== "number") return void 0;
2507
- const reasoning = tokens["reasoning"];
2508
- const cache = tokens["cache"];
2509
- const cacheObj = cache && typeof cache === "object" && cache !== null ? cache : void 0;
2510
- return {
2511
- input,
2512
- output,
2513
- reasoning: typeof reasoning === "number" ? reasoning : 0,
2514
- cacheRead: typeof (cacheObj == null ? void 0 : cacheObj["read"]) === "number" ? cacheObj["read"] : 0,
2515
- cacheWrite: typeof (cacheObj == null ? void 0 : cacheObj["write"]) === "number" ? cacheObj["write"] : 0
2516
- };
2517
- }
2518
- function modelSpendSpanAttributes(input) {
2519
- const providerAttr = attrString("gen_ai.provider.name", canonicalModelProvider(input.providerID));
2520
- const usageAttrs = buildRawModelUsageAttributes({
2521
- inputTokens: input.tokens.input,
2522
- outputTokens: input.tokens.output,
2523
- reasoningTokens: input.tokens.reasoning,
2524
- cacheReadInputTokens: input.tokens.cacheRead,
2525
- cacheWriteInputTokens: input.tokens.cacheWrite
2526
- });
2527
- return providerAttr ? [providerAttr, ...usageAttrs] : usageAttrs;
2528
- }
2529
- function buildLlmGenAiAttributes(input) {
2530
- const parsed = parseOpenCodeAssistantTokens(input.tokens);
2531
- if (!parsed) return [];
2532
- return [
2533
- // OpenCode has already normalized both token axes. Provenance lets Dawn
2534
- // select that contract without the SDK or customer declaring semantics.
2535
- attrString(MODEL_USAGE_ATTRIBUTES.usageSource, "opencode"),
2536
- attrString("gen_ai.system", input.providerID),
2537
- attrString("gen_ai.request.model", input.modelID),
2538
- attrString("gen_ai.response.model", input.modelID),
2539
- ...modelSpendSpanAttributes({ providerID: input.providerID, tokens: parsed })
2540
- ].filter((attribute) => attribute !== void 0);
2541
- }
2542
-
2543
20
  // src/tracing-linkage-helpers.ts
2544
21
  function createSessionParentMapHelpers({
2545
22
  sessions: sessions2,
@@ -2552,11 +29,11 @@ function createSessionParentMapHelpers({
2552
29
  }) {
2553
30
  function applyChildSessionParentToState(childSessionId) {
2554
31
  const parentInfo = mapChildSessionToParent2.get(childSessionId);
2555
- const state2 = sessions2.get(childSessionId);
2556
- if (!parentInfo || !state2) return;
2557
- state2.parentId = parentInfo.parentId;
2558
- state2.parentTaskSpanIds = parentInfo.parentTaskSpanIds;
2559
- state2.parentEventContext = parentInfo.eventContext;
32
+ const state = sessions2.get(childSessionId);
33
+ if (!parentInfo || !state) return;
34
+ state.parentId = parentInfo.parentId;
35
+ state.parentTaskSpanIds = parentInfo.parentTaskSpanIds;
36
+ state.parentEventContext = parentInfo.eventContext;
2560
37
  }
2561
38
  function queuePendingChildByCallKey(key, childSessionId) {
2562
39
  var _a;
@@ -2652,10 +129,10 @@ function markTaskCallFinished(sessionID, callID) {
2652
129
  running.delete(callID);
2653
130
  if (running.size === 0) runningTaskCallsBySession.delete(sessionID);
2654
131
  }
2655
- function endPendingToolSpanWithError(state2, callID, tool, toolCallArgs, errorMessage, traceShipper) {
2656
- const startInfo = state2.toolSpanStarts.get(callID);
132
+ function endPendingToolSpanWithError(state, callID, tool, toolCallArgs, errorMessage, traceShipper) {
133
+ const startInfo = state.toolSpanStarts.get(callID);
2657
134
  if (!startInfo) return false;
2658
- state2.toolSpanStarts.delete(callID);
135
+ state.toolSpanStarts.delete(callID);
2659
136
  const error = new Error(errorMessage);
2660
137
  const endAttrs = [
2661
138
  attrString("ai.toolCall.args", toolCallArgs),
@@ -2755,17 +232,17 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
2755
232
  if (info == null || typeof info !== "object")
2756
233
  throw new Error("session.created: props.info is required");
2757
234
  const parentID = info["parentID"];
2758
- let state2 = sessions.get(sessionID);
2759
- if (!state2) {
2760
- state2 = createSessionState(sessionID);
2761
- sessions.set(sessionID, state2);
235
+ let state = sessions.get(sessionID);
236
+ if (!state) {
237
+ state = createSessionState(sessionID);
238
+ sessions.set(sessionID, state);
2762
239
  }
2763
- state2.parentId = parentID;
2764
- if (state2.parentId) mapChildSessionToParent.set(sessionID, { parentId: state2.parentId });
240
+ state.parentId = parentID;
241
+ if (state.parentId) mapChildSessionToParent.set(sessionID, { parentId: state.parentId });
2765
242
  } else if (event.type === "session.compacted") {
2766
- const state2 = sessions.get(String(sessionID));
2767
- if (!state2) return;
2768
- state2.isCompacting = true;
243
+ const state = sessions.get(String(sessionID));
244
+ if (!state) return;
245
+ state.isCompacting = true;
2769
246
  } else if (event.type === "message.part.updated") {
2770
247
  const part = props["part"];
2771
248
  if (part == null || typeof part !== "object")
@@ -2777,10 +254,10 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
2777
254
  throw new Error("message.part.updated: part.sessionID is required");
2778
255
  if (messageId == null || messageId === "")
2779
256
  throw new Error("message.part.updated: part.messageID is required");
2780
- const state2 = sessions.get(partSessionID);
2781
- if (!state2) return;
257
+ const state = sessions.get(partSessionID);
258
+ if (!state) return;
2782
259
  if (partObj["type"] === "text" && typeof partObj["text"] === "string") {
2783
- state2.outputParts.set(messageId, capText2(partObj["text"]));
260
+ state.outputParts.set(messageId, capText(partObj["text"]));
2784
261
  } else if (partObj["type"] === "tool" && messageId) {
2785
262
  const tool = partObj["tool"];
2786
263
  const callID = partObj["callID"];
@@ -2810,9 +287,9 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
2810
287
  if (typeof errorMessage !== "string" || errorMessage === "")
2811
288
  throw new Error("message.part.updated: error tool state must have error string");
2812
289
  const input = toolState["input"];
2813
- const toolCallArgs = input === void 0 ? void 0 : typeof input === "string" ? capText2(input) : boundedStringify(input);
290
+ const toolCallArgs = input === void 0 ? void 0 : typeof input === "string" ? capText(input) : boundedStringify(input);
2814
291
  if (endPendingToolSpanWithError(
2815
- state2,
292
+ state,
2816
293
  callID,
2817
294
  tool,
2818
295
  toolCallArgs,
@@ -2823,7 +300,7 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
2823
300
  }
2824
301
  }
2825
302
  } else if (partObj["type"] === "reasoning" && typeof partObj["text"] === "string") {
2826
- state2.reasoningParts.set(messageId, capText2(partObj["text"]));
303
+ state.reasoningParts.set(messageId, capText(partObj["text"]));
2827
304
  }
2828
305
  } else if (event.type === "message.updated") {
2829
306
  const msgInfo = props["info"];
@@ -2843,10 +320,10 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
2843
320
  throw new Error("message.updated: info.time is required");
2844
321
  const timeObj = time;
2845
322
  if (timeObj["completed"] == null) return;
2846
- const state2 = sessions.get(msgSessionID);
2847
- if (!state2 || !state2.currentEventId || !state2.currentRootSpan) return;
2848
- if (state2.processedMessages.has(messageId)) return;
2849
- state2.processedMessages.add(messageId);
323
+ const state = sessions.get(msgSessionID);
324
+ if (!state || !state.currentEventId || !state.currentRootSpan) return;
325
+ if (state.processedMessages.has(messageId)) return;
326
+ state.processedMessages.add(messageId);
2850
327
  const tokens = info2["tokens"];
2851
328
  if (tokens == null || typeof tokens !== "object")
2852
329
  throw new Error("message.updated: info.tokens is required");
@@ -2863,13 +340,13 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
2863
340
  );
2864
341
  const modelName = `${providerID}/${modelID}`;
2865
342
  const finishReason = info2["finish"];
2866
- const outputText = state2.outputParts.get(messageId);
2867
- const reasoningText = state2.reasoningParts.get(messageId);
343
+ const outputText = state.outputParts.get(messageId);
344
+ const reasoningText = state.reasoningParts.get(messageId);
2868
345
  const isToolCallsCompletion = finishReason === "tool-calls";
2869
346
  if (outputText !== void 0 && outputText.trim().length > 0) {
2870
- state2.turnOutputParts.push(outputText);
347
+ state.turnOutputParts.push(outputText);
2871
348
  }
2872
- state2.turnOutputTokens += outputTokens;
349
+ state.turnOutputTokens += outputTokens;
2873
350
  if (outputText === void 0 && !isToolCallsCompletion) return;
2874
351
  const msgError = info2["error"];
2875
352
  const errorForSpan = msgError ? (() => {
@@ -2889,17 +366,17 @@ type: ${name != null ? name : "UnknownError"}`;
2889
366
  attrString("ai.response.text", responseText),
2890
367
  ...buildLlmGenAiAttributes({ providerID, modelID, tokens: tokensObj })
2891
368
  ];
2892
- if (state2.currentSystemPrompt) {
369
+ if (state.currentSystemPrompt) {
2893
370
  llmAttrs.push(
2894
371
  attrString("gen_ai.prompt.0.role", "system"),
2895
- attrString("gen_ai.prompt.0.content", state2.currentSystemPrompt)
372
+ attrString("gen_ai.prompt.0.content", state.currentSystemPrompt)
2896
373
  );
2897
374
  }
2898
- const llmParent = state2.parentId && state2.parentTaskSpanIds ? state2.parentTaskSpanIds : state2.currentRootSpan.ids;
375
+ const llmParent = state.parentId && state.parentTaskSpanIds ? state.parentTaskSpanIds : state.currentRootSpan.ids;
2899
376
  const llmSpan = traceShipper.startSpan({
2900
377
  name: modelName,
2901
378
  parent: llmParent,
2902
- eventId: state2.currentEventId,
379
+ eventId: state.currentEventId,
2903
380
  attributes: llmAttrs
2904
381
  });
2905
382
  if (typeof timeObj["created"] === "number") {
@@ -2910,40 +387,40 @@ type: ${name != null ? name : "UnknownError"}`;
2910
387
  return;
2911
388
  }
2912
389
  if (outputText === void 0) return;
2913
- const turnOutputText = capText2(state2.turnOutputParts.join("\n\n"));
2914
- const rootSpan = state2.currentRootSpan;
2915
- const isCompaction = state2.isCompacting === true;
2916
- if (state2.parentId) {
2917
- const userInput = unwrapQuotes(state2.currentInput);
390
+ const turnOutputText = capText(state.turnOutputParts.join("\n\n"));
391
+ const rootSpan = state.currentRootSpan;
392
+ const isCompaction = state.isCompacting === true;
393
+ if (state.parentId) {
394
+ const userInput = unwrapQuotes(state.currentInput);
2918
395
  const llmAttrs = [
2919
396
  attrString("ai.operationId", "generateText"),
2920
397
  attrString("ai.prompt", userInput),
2921
398
  attrString(
2922
399
  "ai.prompt.messages",
2923
- buildPromptMessages(state2.currentSystemPrompt, state2.currentInput)
400
+ buildPromptMessages(state.currentSystemPrompt, state.currentInput)
2924
401
  ),
2925
402
  attrString("ai.response.text", turnOutputText),
2926
403
  ...buildLlmGenAiAttributes({ providerID, modelID, tokens: tokensObj })
2927
404
  ];
2928
- if (state2.currentSystemPrompt) {
405
+ if (state.currentSystemPrompt) {
2929
406
  llmAttrs.push(
2930
407
  attrString("gen_ai.prompt.0.role", "system"),
2931
- attrString("gen_ai.prompt.0.content", state2.currentSystemPrompt)
408
+ attrString("gen_ai.prompt.0.content", state.currentSystemPrompt)
2932
409
  );
2933
410
  }
2934
- if (!state2.parentTaskSpanIds) {
411
+ if (!state.parentTaskSpanIds) {
2935
412
  traceShipper.endSpan(rootSpan, {
2936
413
  error: "Missing strict parent task for child session"
2937
414
  });
2938
- state2.currentRootSpan = void 0;
2939
- state2.currentEventId = void 0;
415
+ state.currentRootSpan = void 0;
416
+ state.currentEventId = void 0;
2940
417
  await traceShipper.flush();
2941
418
  return;
2942
419
  }
2943
420
  const finalLlmSpan = traceShipper.startSpan({
2944
421
  name: modelName,
2945
- parent: state2.parentTaskSpanIds,
2946
- eventId: state2.currentEventId,
422
+ parent: state.parentTaskSpanIds,
423
+ eventId: state.currentEventId,
2947
424
  attributes: llmAttrs
2948
425
  });
2949
426
  if (typeof timeObj["created"] === "number") {
@@ -2953,19 +430,19 @@ type: ${name != null ? name : "UnknownError"}`;
2953
430
  traceShipper.endSpan(rootSpan, {
2954
431
  attributes: [
2955
432
  attrString("is_subagent", "true"),
2956
- attrString("parent_session_id", state2.parentId)
433
+ attrString("parent_session_id", state.parentId)
2957
434
  ],
2958
435
  error: errorForSpan
2959
436
  });
2960
437
  } else {
2961
438
  rootSpan.name = isCompaction ? "ai.compaction" : modelName;
2962
- const userInput = unwrapQuotes(state2.currentInput);
439
+ const userInput = unwrapQuotes(state.currentInput);
2963
440
  const rootAttrs = [
2964
441
  attrString("ai.operationId", "generateText"),
2965
442
  attrString("ai.prompt", userInput),
2966
443
  attrString(
2967
444
  "ai.prompt.messages",
2968
- buildPromptMessages(state2.currentSystemPrompt, state2.currentInput)
445
+ buildPromptMessages(state.currentSystemPrompt, state.currentInput)
2969
446
  ),
2970
447
  attrString("ai.response.text", turnOutputText),
2971
448
  ...buildLlmGenAiAttributes({ providerID, modelID, tokens: tokensObj })
@@ -2974,10 +451,10 @@ type: ${name != null ? name : "UnknownError"}`;
2974
451
  rootAttrs.push(attrString("is_compaction", "true"));
2975
452
  }
2976
453
  rootAttrs.push(attrString("message_id", messageId));
2977
- if (state2.currentSystemPrompt) {
454
+ if (state.currentSystemPrompt) {
2978
455
  rootAttrs.push(
2979
456
  attrString("gen_ai.prompt.0.role", "system"),
2980
- attrString("gen_ai.prompt.0.content", state2.currentSystemPrompt)
457
+ attrString("gen_ai.prompt.0.content", state.currentSystemPrompt)
2981
458
  );
2982
459
  }
2983
460
  traceShipper.endSpan(rootSpan, {
@@ -2985,24 +462,24 @@ type: ${name != null ? name : "UnknownError"}`;
2985
462
  error: errorForSpan
2986
463
  });
2987
464
  if (isCompaction) {
2988
- state2.isCompacting = false;
465
+ state.isCompacting = false;
2989
466
  }
2990
467
  }
2991
- state2.currentRootSpan = void 0;
468
+ state.currentRootSpan = void 0;
2992
469
  const hasAssistantResponse = turnOutputText.trim().length > 0;
2993
470
  if (!hasAssistantResponse && !msgError) {
2994
471
  await traceShipper.flush();
2995
- state2.currentEventId = void 0;
472
+ state.currentEventId = void 0;
2996
473
  return;
2997
474
  }
2998
- if (!state2.parentId) {
2999
- await eventShipper.finish(state2.currentEventId, {
3000
- userId: (_d = (_c = state2.eventMetadata) == null ? void 0 : _c.userId) != null ? _d : state2.sessionId,
475
+ if (!state.parentId) {
476
+ await eventShipper.finish(state.currentEventId, {
477
+ userId: (_d = (_c = state.eventMetadata) == null ? void 0 : _c.userId) != null ? _d : state.sessionId,
3001
478
  model: modelID,
3002
479
  output: msgError ? void 0 : turnOutputText,
3003
480
  usage: {
3004
481
  promptTokens: inputTokens,
3005
- completionTokens: state2.turnOutputTokens
482
+ completionTokens: state.turnOutputTokens
3006
483
  },
3007
484
  error: msgError ? {
3008
485
  name: msgError.name,
@@ -3017,35 +494,35 @@ type: ${name != null ? name : "UnknownError"}`;
3017
494
  });
3018
495
  }
3019
496
  await traceShipper.flush();
3020
- state2.currentEventId = void 0;
497
+ state.currentEventId = void 0;
3021
498
  } else if (event.type === "session.idle") {
3022
499
  if (!sessionID) return;
3023
- const state2 = sessions.get(String(sessionID));
3024
- if (!state2) return;
3025
- if (state2.currentRootSpan) {
3026
- traceShipper.endSpan(state2.currentRootSpan);
3027
- state2.currentRootSpan = void 0;
500
+ const state = sessions.get(String(sessionID));
501
+ if (!state) return;
502
+ if (state.currentRootSpan) {
503
+ traceShipper.endSpan(state.currentRootSpan);
504
+ state.currentRootSpan = void 0;
3028
505
  }
3029
- if (state2.currentEventId) {
3030
- state2.currentEventId = void 0;
506
+ if (state.currentEventId) {
507
+ state.currentEventId = void 0;
3031
508
  }
3032
- state2.isCompacting = false;
509
+ state.isCompacting = false;
3033
510
  await Promise.all([eventShipper.flush(), traceShipper.flush()]);
3034
- if (state2.parentId) {
511
+ if (state.parentId) {
3035
512
  cleanupSessionParentMap(String(sessionID));
3036
513
  sessions.delete(String(sessionID));
3037
514
  } else {
3038
515
  }
3039
516
  } else if (event.type === "session.deleted") {
3040
517
  if (!sessionID) return;
3041
- const state2 = sessions.get(String(sessionID));
3042
- if (!state2) return;
3043
- if (state2.currentRootSpan) {
3044
- traceShipper.endSpan(state2.currentRootSpan);
3045
- state2.currentRootSpan = void 0;
518
+ const state = sessions.get(String(sessionID));
519
+ if (!state) return;
520
+ if (state.currentRootSpan) {
521
+ traceShipper.endSpan(state.currentRootSpan);
522
+ state.currentRootSpan = void 0;
3046
523
  }
3047
- if (state2.currentEventId) {
3048
- state2.currentEventId = void 0;
524
+ if (state.currentEventId) {
525
+ state.currentEventId = void 0;
3049
526
  }
3050
527
  cleanupSessionParentMap(String(sessionID));
3051
528
  await Promise.all([eventShipper.flush(), traceShipper.flush()]);
@@ -3054,8 +531,8 @@ type: ${name != null ? name : "UnknownError"}`;
3054
531
  const errorSessionID = (_h = props["sessionID"]) != null ? _h : sessionID;
3055
532
  if (errorSessionID === void 0 || errorSessionID === "")
3056
533
  throw new Error("session.error: missing sessionID");
3057
- const state2 = sessions.get(String(errorSessionID));
3058
- if (!state2) return;
534
+ const state = sessions.get(String(errorSessionID));
535
+ if (!state) return;
3059
536
  const errorObj = props["error"];
3060
537
  if (errorObj == null) throw new Error("session.error: missing error object");
3061
538
  const errorName = errorObj.name;
@@ -3065,12 +542,12 @@ type: ${name != null ? name : "UnknownError"}`;
3065
542
  const errorStr = `${errorMessage != null ? errorMessage : errorName}
3066
543
 
3067
544
  type: ${errorName != null ? errorName : "UnknownError"}`;
3068
- if (state2.currentRootSpan) {
3069
- traceShipper.endSpan(state2.currentRootSpan, { error: errorStr });
3070
- state2.currentRootSpan = void 0;
545
+ if (state.currentRootSpan) {
546
+ traceShipper.endSpan(state.currentRootSpan, { error: errorStr });
547
+ state.currentRootSpan = void 0;
3071
548
  }
3072
- if (state2.currentEventId) {
3073
- state2.currentEventId = void 0;
549
+ if (state.currentEventId) {
550
+ state.currentEventId = void 0;
3074
551
  }
3075
552
  cleanupSessionParentMap(String(errorSessionID));
3076
553
  await Promise.all([eventShipper.flush(), traceShipper.flush()]);
@@ -3090,15 +567,15 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
3090
567
  var _a, _b, _c, _d, _e, _f, _g;
3091
568
  try {
3092
569
  const { sessionID } = messageInput;
3093
- let state2 = sessions.get(sessionID);
3094
- if (!state2) {
3095
- state2 = createSessionState(sessionID);
3096
- sessions.set(sessionID, state2);
570
+ let state = sessions.get(sessionID);
571
+ if (!state) {
572
+ state = createSessionState(sessionID);
573
+ sessions.set(sessionID, state);
3097
574
  }
3098
575
  applyChildSessionParentToState(sessionID);
3099
- if (state2.currentRootSpan) {
3100
- traceShipper.endSpan(state2.currentRootSpan);
3101
- state2.currentRootSpan = void 0;
576
+ if (state.currentRootSpan) {
577
+ traceShipper.endSpan(state.currentRootSpan);
578
+ state.currentRootSpan = void 0;
3102
579
  }
3103
580
  if (output == null) throw new Error("chat.message: output is required");
3104
581
  const parts = output.parts;
@@ -3129,39 +606,39 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
3129
606
  }
3130
607
  }
3131
608
  }
3132
- state2.eventMetadata = {
609
+ state.eventMetadata = {
3133
610
  ...baseMeta,
3134
611
  ...promptMeta,
3135
612
  properties: baseMeta.properties || promptMeta.properties ? { ...(_a = baseMeta.properties) != null ? _a : {}, ...(_b = promptMeta.properties) != null ? _b : {} } : void 0
3136
613
  };
3137
- const userText = capText2(textParts.join("\n"));
3138
- state2.currentInput = userText;
3139
- state2.turnOutputParts = [];
3140
- state2.turnOutputTokens = 0;
3141
- if (state2.parentId) {
3142
- if (!state2.parentTaskSpanIds || !state2.parentEventContext) {
614
+ const userText = capText(textParts.join("\n"));
615
+ state.currentInput = userText;
616
+ state.turnOutputParts = [];
617
+ state.turnOutputTokens = 0;
618
+ if (state.parentId) {
619
+ if (!state.parentTaskSpanIds || !state.parentEventContext) {
3143
620
  return;
3144
621
  }
3145
- state2.currentEventId = state2.parentEventContext.eventId;
3146
- state2.currentRootSpan = traceShipper.startSpan({
622
+ state.currentEventId = state.parentEventContext.eventId;
623
+ state.currentRootSpan = traceShipper.startSpan({
3147
624
  name: "Subagent",
3148
- parent: state2.parentTaskSpanIds,
3149
- eventId: state2.currentEventId,
625
+ parent: state.parentTaskSpanIds,
626
+ eventId: state.currentEventId,
3150
627
  attributes: [
3151
628
  attrString("workspace", worktree),
3152
629
  attrString("directory", directory),
3153
630
  attrString("hostname", hostname),
3154
631
  attrString("os", os),
3155
632
  attrString("is_subagent", "true"),
3156
- attrString("parent_session_id", state2.parentId)
633
+ attrString("parent_session_id", state.parentId)
3157
634
  ]
3158
635
  });
3159
636
  return;
3160
637
  }
3161
- state2.currentEventId = generateId();
3162
- state2.currentRootSpan = traceShipper.startSpan({
3163
- name: state2.isCompacting ? "ai.compaction" : "ai.event",
3164
- eventId: state2.currentEventId,
638
+ state.currentEventId = generateId();
639
+ state.currentRootSpan = traceShipper.startSpan({
640
+ name: state.isCompacting ? "ai.compaction" : "ai.event",
641
+ eventId: state.currentEventId,
3165
642
  attributes: [
3166
643
  attrString("workspace", worktree),
3167
644
  attrString("directory", directory),
@@ -3169,11 +646,11 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
3169
646
  attrString("os", os)
3170
647
  ]
3171
648
  });
3172
- await eventShipper.patch(state2.currentEventId, {
649
+ await eventShipper.patch(state.currentEventId, {
3173
650
  isPending: true,
3174
- userId: (_d = (_c = state2.eventMetadata) == null ? void 0 : _c.userId) != null ? _d : state2.sessionId,
3175
- convoId: state2.sessionId,
3176
- eventName: (_f = (_e = state2.eventMetadata) == null ? void 0 : _e.eventName) != null ? _f : config.eventName,
651
+ userId: (_d = (_c = state.eventMetadata) == null ? void 0 : _c.userId) != null ? _d : state.sessionId,
652
+ convoId: state.sessionId,
653
+ eventName: (_f = (_e = state.eventMetadata) == null ? void 0 : _e.eventName) != null ? _f : config.eventName,
3177
654
  input: userText,
3178
655
  ...newAttachments.length > 0 ? { attachments: newAttachments } : {},
3179
656
  properties: {
@@ -3182,7 +659,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
3182
659
  hostname,
3183
660
  os,
3184
661
  plugin_version: PLUGIN_VERSION,
3185
- ...(_g = state2.eventMetadata) == null ? void 0 : _g.properties
662
+ ...(_g = state.eventMetadata) == null ? void 0 : _g.properties
3186
663
  }
3187
664
  });
3188
665
  } catch (err) {
@@ -3196,16 +673,16 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
3196
673
  var _a, _b, _c;
3197
674
  try {
3198
675
  const { tool, sessionID, callID } = toolInput;
3199
- const state2 = sessions.get(sessionID);
3200
- if (!state2 || !state2.currentEventId) return;
3201
- const spanParent = state2.parentId && state2.parentTaskSpanIds ? state2.parentTaskSpanIds : (_a = state2.currentRootSpan) == null ? void 0 : _a.ids;
676
+ const state = sessions.get(sessionID);
677
+ if (!state || !state.currentEventId) return;
678
+ const spanParent = state.parentId && state.parentTaskSpanIds ? state.parentTaskSpanIds : (_a = state.currentRootSpan) == null ? void 0 : _a.ids;
3202
679
  if (!spanParent) return;
3203
680
  const startTimeUnixNano = nowUnixNanoString();
3204
681
  if (tool === "task") {
3205
682
  const liveTaskSpan = traceShipper.startSpan({
3206
683
  name: "ai.toolCall",
3207
684
  parent: spanParent,
3208
- eventId: state2.currentEventId,
685
+ eventId: state.currentEventId,
3209
686
  attributes: [
3210
687
  attrString("ai.operationId", "ai.toolCall"),
3211
688
  attrString("ai.toolCall.name", tool),
@@ -3216,9 +693,9 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
3216
693
  const ctx = {
3217
694
  ids: liveTaskSpan.ids,
3218
695
  eventContext: {
3219
- eventId: state2.currentEventId,
3220
- userId: (_c = (_b = state2.eventMetadata) == null ? void 0 : _b.userId) != null ? _c : state2.sessionId,
3221
- convoId: state2.sessionId
696
+ eventId: state.currentEventId,
697
+ userId: (_c = (_b = state.eventMetadata) == null ? void 0 : _b.userId) != null ? _c : state.sessionId,
698
+ convoId: state.sessionId
3222
699
  }
3223
700
  };
3224
701
  taskContexts.set(callKey(sessionID, callID), ctx);
@@ -3229,18 +706,18 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
3229
706
  }
3230
707
  running.add(callID);
3231
708
  resolvePendingChildrenForCall(sessionID, callID, "tool.execute.before");
3232
- state2.toolSpanStarts.set(callID, {
709
+ state.toolSpanStarts.set(callID, {
3233
710
  startTimeUnixNano,
3234
711
  parent: spanParent,
3235
- eventId: state2.currentEventId,
712
+ eventId: state.currentEventId,
3236
713
  name: tool,
3237
714
  liveSpan: liveTaskSpan
3238
715
  });
3239
716
  } else {
3240
- state2.toolSpanStarts.set(callID, {
717
+ state.toolSpanStarts.set(callID, {
3241
718
  startTimeUnixNano,
3242
719
  parent: spanParent,
3243
- eventId: state2.currentEventId,
720
+ eventId: state.currentEventId,
3244
721
  name: tool
3245
722
  });
3246
723
  }
@@ -3257,13 +734,13 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
3257
734
  "tool.execute.after": async (toolInput, result) => {
3258
735
  try {
3259
736
  const { tool, sessionID, callID, args } = toolInput;
3260
- const state2 = sessions.get(sessionID);
3261
- if (!state2 || !state2.currentEventId) return;
737
+ const state = sessions.get(sessionID);
738
+ if (!state || !state.currentEventId) return;
3262
739
  if (args === void 0 || args === null)
3263
740
  throw new Error("tool.execute.after: args is required");
3264
- const toolCallArgs = typeof args === "string" ? capText2(args) : boundedStringify(args);
3265
- const startInfo = state2.toolSpanStarts.get(callID);
3266
- state2.toolSpanStarts.delete(callID);
741
+ const toolCallArgs = typeof args === "string" ? capText(args) : boundedStringify(args);
742
+ const startInfo = state.toolSpanStarts.get(callID);
743
+ state.toolSpanStarts.delete(callID);
3267
744
  const resultMetadata = result.metadata;
3268
745
  const childSessionId = resultMetadata == null ? void 0 : resultMetadata["sessionId"];
3269
746
  if (tool === "task" && childSessionId) {
@@ -3316,9 +793,9 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
3316
793
  try {
3317
794
  const sessionID = input.sessionID;
3318
795
  if (!sessionID) return;
3319
- const state2 = sessions.get(sessionID);
3320
- if (state2) {
3321
- state2.isCompacting = true;
796
+ const state = sessions.get(sessionID);
797
+ if (state) {
798
+ state.isCompacting = true;
3322
799
  }
3323
800
  } catch (err) {
3324
801
  rateLimitedErrorLog(
@@ -3335,15 +812,15 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
3335
812
  if (!config.captureSystemPrompt) return;
3336
813
  const sessionID = input.sessionID;
3337
814
  if (!sessionID) return;
3338
- let state2 = sessions.get(sessionID);
3339
- if (!state2) {
3340
- state2 = createSessionState(sessionID);
3341
- sessions.set(sessionID, state2);
815
+ let state = sessions.get(sessionID);
816
+ if (!state) {
817
+ state = createSessionState(sessionID);
818
+ sessions.set(sessionID, state);
3342
819
  }
3343
820
  const MAX_SYSTEM_PROMPT_LENGTH = 32768;
3344
- const TRUNCATION_MARKER3 = "\n...[truncated]";
821
+ const TRUNCATION_MARKER = "\n...[truncated]";
3345
822
  const joined = output.system.join("\n\n");
3346
- state2.currentSystemPrompt = joined.length > MAX_SYSTEM_PROMPT_LENGTH ? joined.slice(0, MAX_SYSTEM_PROMPT_LENGTH - TRUNCATION_MARKER3.length) + TRUNCATION_MARKER3 : joined;
823
+ state.currentSystemPrompt = joined.length > MAX_SYSTEM_PROMPT_LENGTH ? joined.slice(0, MAX_SYSTEM_PROMPT_LENGTH - TRUNCATION_MARKER.length) + TRUNCATION_MARKER : joined;
3347
824
  } catch (err) {
3348
825
  rateLimitedErrorLog(
3349
826
  "experimental.chat.system.transform",
@@ -3401,11 +878,11 @@ async function plugin(input, opts = {}) {
3401
878
  appLog("info", `Raindrop tracing enabled \u2014 destinations: ${destinations.join(", ")}`);
3402
879
  }
3403
880
  const configuredAppGit = (_a = opts.appGit) != null ? _a : config.appGit;
3404
- const appGitContext = createAppGitContext2(
881
+ const appGitContext = createAppGitContext(
3405
882
  ((_b = config.writeKey) == null ? void 0 : _b.trim()) || hasLocalDestination ? configuredAppGit : false,
3406
883
  { allowLocalGit: false }
3407
884
  );
3408
- const eventShipper = new EventShipper3({
885
+ const eventShipper = new EventShipper({
3409
886
  writeKey: config.writeKey,
3410
887
  endpoint: config.endpoint,
3411
888
  debug: config.debug,
@@ -3413,7 +890,7 @@ async function plugin(input, opts = {}) {
3413
890
  localDebuggerUrl: config.localWorkshopUrl,
3414
891
  appGitContext
3415
892
  });
3416
- const traceShipper = new TraceShipper3({
893
+ const traceShipper = new TraceShipper({
3417
894
  writeKey: config.writeKey,
3418
895
  endpoint: config.endpoint,
3419
896
  debug: config.debug,