@raindrop-ai/opencode-plugin 0.1.4 → 0.3.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/README.md +62 -2
- package/dist/chunk-FCORH4YS.js +2788 -0
- package/dist/index.cjs +287 -25
- package/dist/index.d.cts +7 -78
- package/dist/index.d.ts +7 -78
- package/dist/index.js +229 -2697
- package/dist/self-diagnostics-NiAq-SZ8.d.cts +122 -0
- package/dist/self-diagnostics-NiAq-SZ8.d.ts +122 -0
- package/dist/v2.cjs +3577 -0
- package/dist/v2.d.cts +44 -0
- package/dist/v2.d.ts +44 -0
- package/dist/v2.js +804 -0
- package/package.json +22 -3
package/dist/index.js
CHANGED
|
@@ -1,2545 +1,28 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
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
|
-
}
|
|
1
|
+
import {
|
|
2
|
+
EventShipper,
|
|
3
|
+
PLUGIN_NAME,
|
|
4
|
+
PLUGIN_VERSION,
|
|
5
|
+
SELF_DIAGNOSTICS_ACK,
|
|
6
|
+
TraceShipper,
|
|
7
|
+
attrString,
|
|
8
|
+
boundedStringify,
|
|
9
|
+
buildLlmGenAiAttributes,
|
|
10
|
+
capText,
|
|
11
|
+
createAppGitContext,
|
|
12
|
+
generateId,
|
|
13
|
+
loadConfig,
|
|
14
|
+
normalizeSelfDiagnosticsConfig,
|
|
15
|
+
nowUnixNanoString,
|
|
16
|
+
resolveLocalDebuggerBaseUrl,
|
|
17
|
+
trackSelfDiagnosticsSignal
|
|
18
|
+
} from "./chunk-FCORH4YS.js";
|
|
2310
19
|
|
|
2311
|
-
//
|
|
2312
|
-
|
|
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
|
-
};
|
|
20
|
+
// src/index.ts
|
|
21
|
+
import { tool } from "@opencode-ai/plugin";
|
|
2418
22
|
|
|
2419
23
|
// src/tracing.ts
|
|
2420
24
|
import { hostname as osHostname } from "os";
|
|
2421
25
|
|
|
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
26
|
// src/tracing-linkage-helpers.ts
|
|
2544
27
|
function createSessionParentMapHelpers({
|
|
2545
28
|
sessions: sessions2,
|
|
@@ -2552,11 +35,11 @@ function createSessionParentMapHelpers({
|
|
|
2552
35
|
}) {
|
|
2553
36
|
function applyChildSessionParentToState(childSessionId) {
|
|
2554
37
|
const parentInfo = mapChildSessionToParent2.get(childSessionId);
|
|
2555
|
-
const
|
|
2556
|
-
if (!parentInfo || !
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
38
|
+
const state = sessions2.get(childSessionId);
|
|
39
|
+
if (!parentInfo || !state) return;
|
|
40
|
+
state.parentId = parentInfo.parentId;
|
|
41
|
+
state.parentTaskSpanIds = parentInfo.parentTaskSpanIds;
|
|
42
|
+
state.parentEventContext = parentInfo.eventContext;
|
|
2560
43
|
}
|
|
2561
44
|
function queuePendingChildByCallKey(key, childSessionId) {
|
|
2562
45
|
var _a;
|
|
@@ -2652,10 +135,10 @@ function markTaskCallFinished(sessionID, callID) {
|
|
|
2652
135
|
running.delete(callID);
|
|
2653
136
|
if (running.size === 0) runningTaskCallsBySession.delete(sessionID);
|
|
2654
137
|
}
|
|
2655
|
-
function endPendingToolSpanWithError(
|
|
2656
|
-
const startInfo =
|
|
138
|
+
function endPendingToolSpanWithError(state, callID, tool2, toolCallArgs, errorMessage, traceShipper) {
|
|
139
|
+
const startInfo = state.toolSpanStarts.get(callID);
|
|
2657
140
|
if (!startInfo) return false;
|
|
2658
|
-
|
|
141
|
+
state.toolSpanStarts.delete(callID);
|
|
2659
142
|
const error = new Error(errorMessage);
|
|
2660
143
|
const endAttrs = [
|
|
2661
144
|
attrString("ai.toolCall.args", toolCallArgs),
|
|
@@ -2674,7 +157,7 @@ function endPendingToolSpanWithError(state2, callID, tool, toolCallArgs, errorMe
|
|
|
2674
157
|
startTimeUnixNano: startInfo.startTimeUnixNano,
|
|
2675
158
|
attributes: [
|
|
2676
159
|
attrString("ai.operationId", "ai.toolCall"),
|
|
2677
|
-
attrString("ai.toolCall.name",
|
|
160
|
+
attrString("ai.toolCall.name", tool2),
|
|
2678
161
|
attrString("ai.toolCall.id", callID)
|
|
2679
162
|
]
|
|
2680
163
|
});
|
|
@@ -2711,7 +194,7 @@ function getHostname() {
|
|
|
2711
194
|
return h;
|
|
2712
195
|
}
|
|
2713
196
|
}
|
|
2714
|
-
function
|
|
197
|
+
function createTracing(config, worktree, directory, eventShipper, traceShipper) {
|
|
2715
198
|
function log(msg, data) {
|
|
2716
199
|
if (!config.debug) return;
|
|
2717
200
|
const prefix = `[raindrop-ai/opencode-plugin] [info] ${msg}`;
|
|
@@ -2737,7 +220,7 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
2737
220
|
callKey,
|
|
2738
221
|
log
|
|
2739
222
|
});
|
|
2740
|
-
|
|
223
|
+
const hooks = {
|
|
2741
224
|
// ------------------------------------------------------------------
|
|
2742
225
|
// event — session lifecycle + streaming parts
|
|
2743
226
|
// ------------------------------------------------------------------
|
|
@@ -2755,17 +238,17 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
2755
238
|
if (info == null || typeof info !== "object")
|
|
2756
239
|
throw new Error("session.created: props.info is required");
|
|
2757
240
|
const parentID = info["parentID"];
|
|
2758
|
-
let
|
|
2759
|
-
if (!
|
|
2760
|
-
|
|
2761
|
-
sessions.set(sessionID,
|
|
241
|
+
let state = sessions.get(sessionID);
|
|
242
|
+
if (!state) {
|
|
243
|
+
state = createSessionState(sessionID);
|
|
244
|
+
sessions.set(sessionID, state);
|
|
2762
245
|
}
|
|
2763
|
-
|
|
2764
|
-
if (
|
|
246
|
+
state.parentId = parentID;
|
|
247
|
+
if (state.parentId) mapChildSessionToParent.set(sessionID, { parentId: state.parentId });
|
|
2765
248
|
} else if (event.type === "session.compacted") {
|
|
2766
|
-
const
|
|
2767
|
-
if (!
|
|
2768
|
-
|
|
249
|
+
const state = sessions.get(String(sessionID));
|
|
250
|
+
if (!state) return;
|
|
251
|
+
state.isCompacting = true;
|
|
2769
252
|
} else if (event.type === "message.part.updated") {
|
|
2770
253
|
const part = props["part"];
|
|
2771
254
|
if (part == null || typeof part !== "object")
|
|
@@ -2777,19 +260,19 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
2777
260
|
throw new Error("message.part.updated: part.sessionID is required");
|
|
2778
261
|
if (messageId == null || messageId === "")
|
|
2779
262
|
throw new Error("message.part.updated: part.messageID is required");
|
|
2780
|
-
const
|
|
2781
|
-
if (!
|
|
263
|
+
const state = sessions.get(partSessionID);
|
|
264
|
+
if (!state) return;
|
|
2782
265
|
if (partObj["type"] === "text" && typeof partObj["text"] === "string") {
|
|
2783
|
-
|
|
266
|
+
state.outputParts.set(messageId, capText(partObj["text"]));
|
|
2784
267
|
} else if (partObj["type"] === "tool" && messageId) {
|
|
2785
|
-
const
|
|
268
|
+
const tool2 = partObj["tool"];
|
|
2786
269
|
const callID = partObj["callID"];
|
|
2787
270
|
const partState = partObj["state"];
|
|
2788
271
|
if (callID == null || callID === "")
|
|
2789
272
|
throw new Error("message.part.updated: part.callID is required for tool part");
|
|
2790
273
|
if (partState == null || typeof partState !== "object")
|
|
2791
274
|
throw new Error("message.part.updated: part.state is required for tool part");
|
|
2792
|
-
if (
|
|
275
|
+
if (tool2 === "task") {
|
|
2793
276
|
const metadata = partState["metadata"];
|
|
2794
277
|
const childSessionId = metadata != null && typeof metadata === "object" ? metadata["sessionId"] : void 0;
|
|
2795
278
|
if (childSessionId != null && childSessionId !== "") {
|
|
@@ -2810,20 +293,20 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
2810
293
|
if (typeof errorMessage !== "string" || errorMessage === "")
|
|
2811
294
|
throw new Error("message.part.updated: error tool state must have error string");
|
|
2812
295
|
const input = toolState["input"];
|
|
2813
|
-
const toolCallArgs = input === void 0 ? void 0 : typeof input === "string" ?
|
|
296
|
+
const toolCallArgs = input === void 0 ? void 0 : typeof input === "string" ? capText(input) : boundedStringify(input);
|
|
2814
297
|
if (endPendingToolSpanWithError(
|
|
2815
|
-
|
|
298
|
+
state,
|
|
2816
299
|
callID,
|
|
2817
|
-
|
|
300
|
+
tool2,
|
|
2818
301
|
toolCallArgs,
|
|
2819
302
|
errorMessage,
|
|
2820
303
|
traceShipper
|
|
2821
|
-
) &&
|
|
304
|
+
) && tool2 === "task") {
|
|
2822
305
|
markTaskCallFinished(partSessionID, callID);
|
|
2823
306
|
}
|
|
2824
307
|
}
|
|
2825
308
|
} else if (partObj["type"] === "reasoning" && typeof partObj["text"] === "string") {
|
|
2826
|
-
|
|
309
|
+
state.reasoningParts.set(messageId, capText(partObj["text"]));
|
|
2827
310
|
}
|
|
2828
311
|
} else if (event.type === "message.updated") {
|
|
2829
312
|
const msgInfo = props["info"];
|
|
@@ -2843,10 +326,10 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
2843
326
|
throw new Error("message.updated: info.time is required");
|
|
2844
327
|
const timeObj = time;
|
|
2845
328
|
if (timeObj["completed"] == null) return;
|
|
2846
|
-
const
|
|
2847
|
-
if (!
|
|
2848
|
-
if (
|
|
2849
|
-
|
|
329
|
+
const state = sessions.get(msgSessionID);
|
|
330
|
+
if (!state || !state.currentEventId || !state.currentRootSpan) return;
|
|
331
|
+
if (state.processedMessages.has(messageId)) return;
|
|
332
|
+
state.processedMessages.add(messageId);
|
|
2850
333
|
const tokens = info2["tokens"];
|
|
2851
334
|
if (tokens == null || typeof tokens !== "object")
|
|
2852
335
|
throw new Error("message.updated: info.tokens is required");
|
|
@@ -2863,13 +346,13 @@ function createHooks(config, worktree, directory, eventShipper, traceShipper) {
|
|
|
2863
346
|
);
|
|
2864
347
|
const modelName = `${providerID}/${modelID}`;
|
|
2865
348
|
const finishReason = info2["finish"];
|
|
2866
|
-
const outputText =
|
|
2867
|
-
const reasoningText =
|
|
349
|
+
const outputText = state.outputParts.get(messageId);
|
|
350
|
+
const reasoningText = state.reasoningParts.get(messageId);
|
|
2868
351
|
const isToolCallsCompletion = finishReason === "tool-calls";
|
|
2869
352
|
if (outputText !== void 0 && outputText.trim().length > 0) {
|
|
2870
|
-
|
|
353
|
+
state.turnOutputParts.push(outputText);
|
|
2871
354
|
}
|
|
2872
|
-
|
|
355
|
+
state.turnOutputTokens += outputTokens;
|
|
2873
356
|
if (outputText === void 0 && !isToolCallsCompletion) return;
|
|
2874
357
|
const msgError = info2["error"];
|
|
2875
358
|
const errorForSpan = msgError ? (() => {
|
|
@@ -2889,17 +372,17 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
2889
372
|
attrString("ai.response.text", responseText),
|
|
2890
373
|
...buildLlmGenAiAttributes({ providerID, modelID, tokens: tokensObj })
|
|
2891
374
|
];
|
|
2892
|
-
if (
|
|
375
|
+
if (state.currentSystemPrompt) {
|
|
2893
376
|
llmAttrs.push(
|
|
2894
377
|
attrString("gen_ai.prompt.0.role", "system"),
|
|
2895
|
-
attrString("gen_ai.prompt.0.content",
|
|
378
|
+
attrString("gen_ai.prompt.0.content", state.currentSystemPrompt)
|
|
2896
379
|
);
|
|
2897
380
|
}
|
|
2898
|
-
const llmParent =
|
|
381
|
+
const llmParent = state.parentId && state.parentTaskSpanIds ? state.parentTaskSpanIds : state.currentRootSpan.ids;
|
|
2899
382
|
const llmSpan = traceShipper.startSpan({
|
|
2900
383
|
name: modelName,
|
|
2901
384
|
parent: llmParent,
|
|
2902
|
-
eventId:
|
|
385
|
+
eventId: state.currentEventId,
|
|
2903
386
|
attributes: llmAttrs
|
|
2904
387
|
});
|
|
2905
388
|
if (typeof timeObj["created"] === "number") {
|
|
@@ -2910,40 +393,40 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
2910
393
|
return;
|
|
2911
394
|
}
|
|
2912
395
|
if (outputText === void 0) return;
|
|
2913
|
-
const turnOutputText =
|
|
2914
|
-
const rootSpan =
|
|
2915
|
-
const isCompaction =
|
|
2916
|
-
if (
|
|
2917
|
-
const userInput = unwrapQuotes(
|
|
396
|
+
const turnOutputText = capText(state.turnOutputParts.join("\n\n"));
|
|
397
|
+
const rootSpan = state.currentRootSpan;
|
|
398
|
+
const isCompaction = state.isCompacting === true;
|
|
399
|
+
if (state.parentId) {
|
|
400
|
+
const userInput = unwrapQuotes(state.currentInput);
|
|
2918
401
|
const llmAttrs = [
|
|
2919
402
|
attrString("ai.operationId", "generateText"),
|
|
2920
403
|
attrString("ai.prompt", userInput),
|
|
2921
404
|
attrString(
|
|
2922
405
|
"ai.prompt.messages",
|
|
2923
|
-
buildPromptMessages(
|
|
406
|
+
buildPromptMessages(state.currentSystemPrompt, state.currentInput)
|
|
2924
407
|
),
|
|
2925
408
|
attrString("ai.response.text", turnOutputText),
|
|
2926
409
|
...buildLlmGenAiAttributes({ providerID, modelID, tokens: tokensObj })
|
|
2927
410
|
];
|
|
2928
|
-
if (
|
|
411
|
+
if (state.currentSystemPrompt) {
|
|
2929
412
|
llmAttrs.push(
|
|
2930
413
|
attrString("gen_ai.prompt.0.role", "system"),
|
|
2931
|
-
attrString("gen_ai.prompt.0.content",
|
|
414
|
+
attrString("gen_ai.prompt.0.content", state.currentSystemPrompt)
|
|
2932
415
|
);
|
|
2933
416
|
}
|
|
2934
|
-
if (!
|
|
417
|
+
if (!state.parentTaskSpanIds) {
|
|
2935
418
|
traceShipper.endSpan(rootSpan, {
|
|
2936
419
|
error: "Missing strict parent task for child session"
|
|
2937
420
|
});
|
|
2938
|
-
|
|
2939
|
-
|
|
421
|
+
state.currentRootSpan = void 0;
|
|
422
|
+
state.currentEventId = void 0;
|
|
2940
423
|
await traceShipper.flush();
|
|
2941
424
|
return;
|
|
2942
425
|
}
|
|
2943
426
|
const finalLlmSpan = traceShipper.startSpan({
|
|
2944
427
|
name: modelName,
|
|
2945
|
-
parent:
|
|
2946
|
-
eventId:
|
|
428
|
+
parent: state.parentTaskSpanIds,
|
|
429
|
+
eventId: state.currentEventId,
|
|
2947
430
|
attributes: llmAttrs
|
|
2948
431
|
});
|
|
2949
432
|
if (typeof timeObj["created"] === "number") {
|
|
@@ -2953,19 +436,19 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
2953
436
|
traceShipper.endSpan(rootSpan, {
|
|
2954
437
|
attributes: [
|
|
2955
438
|
attrString("is_subagent", "true"),
|
|
2956
|
-
attrString("parent_session_id",
|
|
439
|
+
attrString("parent_session_id", state.parentId)
|
|
2957
440
|
],
|
|
2958
441
|
error: errorForSpan
|
|
2959
442
|
});
|
|
2960
443
|
} else {
|
|
2961
444
|
rootSpan.name = isCompaction ? "ai.compaction" : modelName;
|
|
2962
|
-
const userInput = unwrapQuotes(
|
|
445
|
+
const userInput = unwrapQuotes(state.currentInput);
|
|
2963
446
|
const rootAttrs = [
|
|
2964
447
|
attrString("ai.operationId", "generateText"),
|
|
2965
448
|
attrString("ai.prompt", userInput),
|
|
2966
449
|
attrString(
|
|
2967
450
|
"ai.prompt.messages",
|
|
2968
|
-
buildPromptMessages(
|
|
451
|
+
buildPromptMessages(state.currentSystemPrompt, state.currentInput)
|
|
2969
452
|
),
|
|
2970
453
|
attrString("ai.response.text", turnOutputText),
|
|
2971
454
|
...buildLlmGenAiAttributes({ providerID, modelID, tokens: tokensObj })
|
|
@@ -2974,10 +457,10 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
2974
457
|
rootAttrs.push(attrString("is_compaction", "true"));
|
|
2975
458
|
}
|
|
2976
459
|
rootAttrs.push(attrString("message_id", messageId));
|
|
2977
|
-
if (
|
|
460
|
+
if (state.currentSystemPrompt) {
|
|
2978
461
|
rootAttrs.push(
|
|
2979
462
|
attrString("gen_ai.prompt.0.role", "system"),
|
|
2980
|
-
attrString("gen_ai.prompt.0.content",
|
|
463
|
+
attrString("gen_ai.prompt.0.content", state.currentSystemPrompt)
|
|
2981
464
|
);
|
|
2982
465
|
}
|
|
2983
466
|
traceShipper.endSpan(rootSpan, {
|
|
@@ -2985,24 +468,24 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
2985
468
|
error: errorForSpan
|
|
2986
469
|
});
|
|
2987
470
|
if (isCompaction) {
|
|
2988
|
-
|
|
471
|
+
state.isCompacting = false;
|
|
2989
472
|
}
|
|
2990
473
|
}
|
|
2991
|
-
|
|
474
|
+
state.currentRootSpan = void 0;
|
|
2992
475
|
const hasAssistantResponse = turnOutputText.trim().length > 0;
|
|
2993
476
|
if (!hasAssistantResponse && !msgError) {
|
|
2994
477
|
await traceShipper.flush();
|
|
2995
|
-
|
|
478
|
+
state.currentEventId = void 0;
|
|
2996
479
|
return;
|
|
2997
480
|
}
|
|
2998
|
-
if (!
|
|
2999
|
-
await eventShipper.finish(
|
|
3000
|
-
userId: (_d = (_c =
|
|
481
|
+
if (!state.parentId) {
|
|
482
|
+
await eventShipper.finish(state.currentEventId, {
|
|
483
|
+
userId: (_d = (_c = state.eventMetadata) == null ? void 0 : _c.userId) != null ? _d : state.sessionId,
|
|
3001
484
|
model: modelID,
|
|
3002
485
|
output: msgError ? void 0 : turnOutputText,
|
|
3003
486
|
usage: {
|
|
3004
487
|
promptTokens: inputTokens,
|
|
3005
|
-
completionTokens:
|
|
488
|
+
completionTokens: state.turnOutputTokens
|
|
3006
489
|
},
|
|
3007
490
|
error: msgError ? {
|
|
3008
491
|
name: msgError.name,
|
|
@@ -3017,35 +500,35 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
3017
500
|
});
|
|
3018
501
|
}
|
|
3019
502
|
await traceShipper.flush();
|
|
3020
|
-
|
|
503
|
+
state.currentEventId = void 0;
|
|
3021
504
|
} else if (event.type === "session.idle") {
|
|
3022
505
|
if (!sessionID) return;
|
|
3023
|
-
const
|
|
3024
|
-
if (!
|
|
3025
|
-
if (
|
|
3026
|
-
traceShipper.endSpan(
|
|
3027
|
-
|
|
506
|
+
const state = sessions.get(String(sessionID));
|
|
507
|
+
if (!state) return;
|
|
508
|
+
if (state.currentRootSpan) {
|
|
509
|
+
traceShipper.endSpan(state.currentRootSpan);
|
|
510
|
+
state.currentRootSpan = void 0;
|
|
3028
511
|
}
|
|
3029
|
-
if (
|
|
3030
|
-
|
|
512
|
+
if (state.currentEventId) {
|
|
513
|
+
state.currentEventId = void 0;
|
|
3031
514
|
}
|
|
3032
|
-
|
|
515
|
+
state.isCompacting = false;
|
|
3033
516
|
await Promise.all([eventShipper.flush(), traceShipper.flush()]);
|
|
3034
|
-
if (
|
|
517
|
+
if (state.parentId) {
|
|
3035
518
|
cleanupSessionParentMap(String(sessionID));
|
|
3036
519
|
sessions.delete(String(sessionID));
|
|
3037
520
|
} else {
|
|
3038
521
|
}
|
|
3039
522
|
} else if (event.type === "session.deleted") {
|
|
3040
523
|
if (!sessionID) return;
|
|
3041
|
-
const
|
|
3042
|
-
if (!
|
|
3043
|
-
if (
|
|
3044
|
-
traceShipper.endSpan(
|
|
3045
|
-
|
|
524
|
+
const state = sessions.get(String(sessionID));
|
|
525
|
+
if (!state) return;
|
|
526
|
+
if (state.currentRootSpan) {
|
|
527
|
+
traceShipper.endSpan(state.currentRootSpan);
|
|
528
|
+
state.currentRootSpan = void 0;
|
|
3046
529
|
}
|
|
3047
|
-
if (
|
|
3048
|
-
|
|
530
|
+
if (state.currentEventId) {
|
|
531
|
+
state.currentEventId = void 0;
|
|
3049
532
|
}
|
|
3050
533
|
cleanupSessionParentMap(String(sessionID));
|
|
3051
534
|
await Promise.all([eventShipper.flush(), traceShipper.flush()]);
|
|
@@ -3054,8 +537,8 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
3054
537
|
const errorSessionID = (_h = props["sessionID"]) != null ? _h : sessionID;
|
|
3055
538
|
if (errorSessionID === void 0 || errorSessionID === "")
|
|
3056
539
|
throw new Error("session.error: missing sessionID");
|
|
3057
|
-
const
|
|
3058
|
-
if (!
|
|
540
|
+
const state = sessions.get(String(errorSessionID));
|
|
541
|
+
if (!state) return;
|
|
3059
542
|
const errorObj = props["error"];
|
|
3060
543
|
if (errorObj == null) throw new Error("session.error: missing error object");
|
|
3061
544
|
const errorName = errorObj.name;
|
|
@@ -3065,12 +548,12 @@ type: ${name != null ? name : "UnknownError"}`;
|
|
|
3065
548
|
const errorStr = `${errorMessage != null ? errorMessage : errorName}
|
|
3066
549
|
|
|
3067
550
|
type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
3068
|
-
if (
|
|
3069
|
-
traceShipper.endSpan(
|
|
3070
|
-
|
|
551
|
+
if (state.currentRootSpan) {
|
|
552
|
+
traceShipper.endSpan(state.currentRootSpan, { error: errorStr });
|
|
553
|
+
state.currentRootSpan = void 0;
|
|
3071
554
|
}
|
|
3072
|
-
if (
|
|
3073
|
-
|
|
555
|
+
if (state.currentEventId) {
|
|
556
|
+
state.currentEventId = void 0;
|
|
3074
557
|
}
|
|
3075
558
|
cleanupSessionParentMap(String(errorSessionID));
|
|
3076
559
|
await Promise.all([eventShipper.flush(), traceShipper.flush()]);
|
|
@@ -3090,15 +573,15 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3090
573
|
var _a, _b, _c, _d, _e, _f, _g;
|
|
3091
574
|
try {
|
|
3092
575
|
const { sessionID } = messageInput;
|
|
3093
|
-
let
|
|
3094
|
-
if (!
|
|
3095
|
-
|
|
3096
|
-
sessions.set(sessionID,
|
|
576
|
+
let state = sessions.get(sessionID);
|
|
577
|
+
if (!state) {
|
|
578
|
+
state = createSessionState(sessionID);
|
|
579
|
+
sessions.set(sessionID, state);
|
|
3097
580
|
}
|
|
3098
581
|
applyChildSessionParentToState(sessionID);
|
|
3099
|
-
if (
|
|
3100
|
-
traceShipper.endSpan(
|
|
3101
|
-
|
|
582
|
+
if (state.currentRootSpan) {
|
|
583
|
+
traceShipper.endSpan(state.currentRootSpan);
|
|
584
|
+
state.currentRootSpan = void 0;
|
|
3102
585
|
}
|
|
3103
586
|
if (output == null) throw new Error("chat.message: output is required");
|
|
3104
587
|
const parts = output.parts;
|
|
@@ -3129,39 +612,39 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3129
612
|
}
|
|
3130
613
|
}
|
|
3131
614
|
}
|
|
3132
|
-
|
|
615
|
+
state.eventMetadata = {
|
|
3133
616
|
...baseMeta,
|
|
3134
617
|
...promptMeta,
|
|
3135
618
|
properties: baseMeta.properties || promptMeta.properties ? { ...(_a = baseMeta.properties) != null ? _a : {}, ...(_b = promptMeta.properties) != null ? _b : {} } : void 0
|
|
3136
619
|
};
|
|
3137
|
-
const userText =
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
if (
|
|
3142
|
-
if (!
|
|
620
|
+
const userText = capText(textParts.join("\n"));
|
|
621
|
+
state.currentInput = userText;
|
|
622
|
+
state.turnOutputParts = [];
|
|
623
|
+
state.turnOutputTokens = 0;
|
|
624
|
+
if (state.parentId) {
|
|
625
|
+
if (!state.parentTaskSpanIds || !state.parentEventContext) {
|
|
3143
626
|
return;
|
|
3144
627
|
}
|
|
3145
|
-
|
|
3146
|
-
|
|
628
|
+
state.currentEventId = state.parentEventContext.eventId;
|
|
629
|
+
state.currentRootSpan = traceShipper.startSpan({
|
|
3147
630
|
name: "Subagent",
|
|
3148
|
-
parent:
|
|
3149
|
-
eventId:
|
|
631
|
+
parent: state.parentTaskSpanIds,
|
|
632
|
+
eventId: state.currentEventId,
|
|
3150
633
|
attributes: [
|
|
3151
634
|
attrString("workspace", worktree),
|
|
3152
635
|
attrString("directory", directory),
|
|
3153
636
|
attrString("hostname", hostname),
|
|
3154
637
|
attrString("os", os),
|
|
3155
638
|
attrString("is_subagent", "true"),
|
|
3156
|
-
attrString("parent_session_id",
|
|
639
|
+
attrString("parent_session_id", state.parentId)
|
|
3157
640
|
]
|
|
3158
641
|
});
|
|
3159
642
|
return;
|
|
3160
643
|
}
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
name:
|
|
3164
|
-
eventId:
|
|
644
|
+
state.currentEventId = generateId();
|
|
645
|
+
state.currentRootSpan = traceShipper.startSpan({
|
|
646
|
+
name: state.isCompacting ? "ai.compaction" : "ai.event",
|
|
647
|
+
eventId: state.currentEventId,
|
|
3165
648
|
attributes: [
|
|
3166
649
|
attrString("workspace", worktree),
|
|
3167
650
|
attrString("directory", directory),
|
|
@@ -3169,11 +652,11 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3169
652
|
attrString("os", os)
|
|
3170
653
|
]
|
|
3171
654
|
});
|
|
3172
|
-
await eventShipper.patch(
|
|
655
|
+
await eventShipper.patch(state.currentEventId, {
|
|
3173
656
|
isPending: true,
|
|
3174
|
-
userId: (_d = (_c =
|
|
3175
|
-
convoId:
|
|
3176
|
-
eventName: (_f = (_e =
|
|
657
|
+
userId: (_d = (_c = state.eventMetadata) == null ? void 0 : _c.userId) != null ? _d : state.sessionId,
|
|
658
|
+
convoId: state.sessionId,
|
|
659
|
+
eventName: (_f = (_e = state.eventMetadata) == null ? void 0 : _e.eventName) != null ? _f : config.eventName,
|
|
3177
660
|
input: userText,
|
|
3178
661
|
...newAttachments.length > 0 ? { attachments: newAttachments } : {},
|
|
3179
662
|
properties: {
|
|
@@ -3182,7 +665,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3182
665
|
hostname,
|
|
3183
666
|
os,
|
|
3184
667
|
plugin_version: PLUGIN_VERSION,
|
|
3185
|
-
...(_g =
|
|
668
|
+
...(_g = state.eventMetadata) == null ? void 0 : _g.properties
|
|
3186
669
|
}
|
|
3187
670
|
});
|
|
3188
671
|
} catch (err) {
|
|
@@ -3195,20 +678,20 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3195
678
|
"tool.execute.before": async (toolInput, _output) => {
|
|
3196
679
|
var _a, _b, _c;
|
|
3197
680
|
try {
|
|
3198
|
-
const { tool, sessionID, callID } = toolInput;
|
|
3199
|
-
const
|
|
3200
|
-
if (!
|
|
3201
|
-
const spanParent =
|
|
681
|
+
const { tool: tool2, sessionID, callID } = toolInput;
|
|
682
|
+
const state = sessions.get(sessionID);
|
|
683
|
+
if (!state || !state.currentEventId) return;
|
|
684
|
+
const spanParent = state.parentId && state.parentTaskSpanIds ? state.parentTaskSpanIds : (_a = state.currentRootSpan) == null ? void 0 : _a.ids;
|
|
3202
685
|
if (!spanParent) return;
|
|
3203
686
|
const startTimeUnixNano = nowUnixNanoString();
|
|
3204
|
-
if (
|
|
687
|
+
if (tool2 === "task") {
|
|
3205
688
|
const liveTaskSpan = traceShipper.startSpan({
|
|
3206
689
|
name: "ai.toolCall",
|
|
3207
690
|
parent: spanParent,
|
|
3208
|
-
eventId:
|
|
691
|
+
eventId: state.currentEventId,
|
|
3209
692
|
attributes: [
|
|
3210
693
|
attrString("ai.operationId", "ai.toolCall"),
|
|
3211
|
-
attrString("ai.toolCall.name",
|
|
694
|
+
attrString("ai.toolCall.name", tool2),
|
|
3212
695
|
attrString("ai.toolCall.id", callID)
|
|
3213
696
|
]
|
|
3214
697
|
});
|
|
@@ -3216,9 +699,9 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3216
699
|
const ctx = {
|
|
3217
700
|
ids: liveTaskSpan.ids,
|
|
3218
701
|
eventContext: {
|
|
3219
|
-
eventId:
|
|
3220
|
-
userId: (_c = (_b =
|
|
3221
|
-
convoId:
|
|
702
|
+
eventId: state.currentEventId,
|
|
703
|
+
userId: (_c = (_b = state.eventMetadata) == null ? void 0 : _b.userId) != null ? _c : state.sessionId,
|
|
704
|
+
convoId: state.sessionId
|
|
3222
705
|
}
|
|
3223
706
|
};
|
|
3224
707
|
taskContexts.set(callKey(sessionID, callID), ctx);
|
|
@@ -3229,19 +712,19 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3229
712
|
}
|
|
3230
713
|
running.add(callID);
|
|
3231
714
|
resolvePendingChildrenForCall(sessionID, callID, "tool.execute.before");
|
|
3232
|
-
|
|
715
|
+
state.toolSpanStarts.set(callID, {
|
|
3233
716
|
startTimeUnixNano,
|
|
3234
717
|
parent: spanParent,
|
|
3235
|
-
eventId:
|
|
3236
|
-
name:
|
|
718
|
+
eventId: state.currentEventId,
|
|
719
|
+
name: tool2,
|
|
3237
720
|
liveSpan: liveTaskSpan
|
|
3238
721
|
});
|
|
3239
722
|
} else {
|
|
3240
|
-
|
|
723
|
+
state.toolSpanStarts.set(callID, {
|
|
3241
724
|
startTimeUnixNano,
|
|
3242
725
|
parent: spanParent,
|
|
3243
|
-
eventId:
|
|
3244
|
-
name:
|
|
726
|
+
eventId: state.currentEventId,
|
|
727
|
+
name: tool2
|
|
3245
728
|
});
|
|
3246
729
|
}
|
|
3247
730
|
} catch (err) {
|
|
@@ -3256,17 +739,17 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3256
739
|
// ------------------------------------------------------------------
|
|
3257
740
|
"tool.execute.after": async (toolInput, result) => {
|
|
3258
741
|
try {
|
|
3259
|
-
const { tool, sessionID, callID, args } = toolInput;
|
|
3260
|
-
const
|
|
3261
|
-
if (!
|
|
742
|
+
const { tool: tool2, sessionID, callID, args } = toolInput;
|
|
743
|
+
const state = sessions.get(sessionID);
|
|
744
|
+
if (!state || !state.currentEventId) return;
|
|
3262
745
|
if (args === void 0 || args === null)
|
|
3263
746
|
throw new Error("tool.execute.after: args is required");
|
|
3264
|
-
const toolCallArgs = typeof args === "string" ?
|
|
3265
|
-
const startInfo =
|
|
3266
|
-
|
|
747
|
+
const toolCallArgs = typeof args === "string" ? capText(args) : boundedStringify(args);
|
|
748
|
+
const startInfo = state.toolSpanStarts.get(callID);
|
|
749
|
+
state.toolSpanStarts.delete(callID);
|
|
3267
750
|
const resultMetadata = result.metadata;
|
|
3268
751
|
const childSessionId = resultMetadata == null ? void 0 : resultMetadata["sessionId"];
|
|
3269
|
-
if (
|
|
752
|
+
if (tool2 === "task" && childSessionId) {
|
|
3270
753
|
mapChildSessionToParent.set(childSessionId, { parentId: sessionID });
|
|
3271
754
|
attachChildSessionToParentTask(childSessionId, sessionID, callID, "tool.execute.after");
|
|
3272
755
|
}
|
|
@@ -3291,7 +774,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3291
774
|
endTimeUnixNano,
|
|
3292
775
|
attributes: [
|
|
3293
776
|
attrString("ai.operationId", "ai.toolCall"),
|
|
3294
|
-
attrString("ai.toolCall.name",
|
|
777
|
+
attrString("ai.toolCall.name", tool2),
|
|
3295
778
|
attrString("ai.toolCall.id", callID),
|
|
3296
779
|
attrString("ai.toolCall.args", toolCallArgs),
|
|
3297
780
|
attrString("ai.toolCall.result", toolResult)
|
|
@@ -3299,7 +782,7 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3299
782
|
});
|
|
3300
783
|
}
|
|
3301
784
|
}
|
|
3302
|
-
if (
|
|
785
|
+
if (tool2 === "task") {
|
|
3303
786
|
markTaskCallFinished(sessionID, callID);
|
|
3304
787
|
}
|
|
3305
788
|
} catch (err) {
|
|
@@ -3316,9 +799,9 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3316
799
|
try {
|
|
3317
800
|
const sessionID = input.sessionID;
|
|
3318
801
|
if (!sessionID) return;
|
|
3319
|
-
const
|
|
3320
|
-
if (
|
|
3321
|
-
|
|
802
|
+
const state = sessions.get(sessionID);
|
|
803
|
+
if (state) {
|
|
804
|
+
state.isCompacting = true;
|
|
3322
805
|
}
|
|
3323
806
|
} catch (err) {
|
|
3324
807
|
rateLimitedErrorLog(
|
|
@@ -3335,15 +818,15 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3335
818
|
if (!config.captureSystemPrompt) return;
|
|
3336
819
|
const sessionID = input.sessionID;
|
|
3337
820
|
if (!sessionID) return;
|
|
3338
|
-
let
|
|
3339
|
-
if (!
|
|
3340
|
-
|
|
3341
|
-
sessions.set(sessionID,
|
|
821
|
+
let state = sessions.get(sessionID);
|
|
822
|
+
if (!state) {
|
|
823
|
+
state = createSessionState(sessionID);
|
|
824
|
+
sessions.set(sessionID, state);
|
|
3342
825
|
}
|
|
3343
826
|
const MAX_SYSTEM_PROMPT_LENGTH = 32768;
|
|
3344
|
-
const
|
|
827
|
+
const TRUNCATION_MARKER = "\n...[truncated]";
|
|
3345
828
|
const joined = output.system.join("\n\n");
|
|
3346
|
-
|
|
829
|
+
state.currentSystemPrompt = joined.length > MAX_SYSTEM_PROMPT_LENGTH ? joined.slice(0, MAX_SYSTEM_PROMPT_LENGTH - TRUNCATION_MARKER.length) + TRUNCATION_MARKER : joined;
|
|
3347
830
|
} catch (err) {
|
|
3348
831
|
rateLimitedErrorLog(
|
|
3349
832
|
"experimental.chat.system.transform",
|
|
@@ -3352,16 +835,24 @@ type: ${errorName != null ? errorName : "UnknownError"}`;
|
|
|
3352
835
|
}
|
|
3353
836
|
}
|
|
3354
837
|
};
|
|
838
|
+
return {
|
|
839
|
+
hooks,
|
|
840
|
+
currentEventId(sessionID) {
|
|
841
|
+
var _a;
|
|
842
|
+
return (_a = sessions.get(sessionID)) == null ? void 0 : _a.currentEventId;
|
|
843
|
+
}
|
|
844
|
+
};
|
|
3355
845
|
}
|
|
3356
846
|
|
|
3357
847
|
// src/index.ts
|
|
3358
|
-
function createRaindropHandle(eventShipper, traceShipper, appGitContext) {
|
|
848
|
+
function createRaindropHandle(eventShipper, traceShipper, appGitContext, currentEventId) {
|
|
3359
849
|
return {
|
|
3360
850
|
users: {
|
|
3361
851
|
async identify(users) {
|
|
3362
852
|
await eventShipper.identify(users);
|
|
3363
853
|
}
|
|
3364
854
|
},
|
|
855
|
+
currentEventId,
|
|
3365
856
|
async flush() {
|
|
3366
857
|
await Promise.all([eventShipper.flush(), traceShipper.flush()]);
|
|
3367
858
|
},
|
|
@@ -3378,7 +869,7 @@ function createRaindropHandle(eventShipper, traceShipper, appGitContext) {
|
|
|
3378
869
|
};
|
|
3379
870
|
}
|
|
3380
871
|
async function plugin(input, opts = {}) {
|
|
3381
|
-
var _a, _b, _c;
|
|
872
|
+
var _a, _b, _c, _d;
|
|
3382
873
|
const config = loadConfig(input.directory);
|
|
3383
874
|
function appLog(level, message) {
|
|
3384
875
|
console.log(`[raindrop-ai/opencode-plugin] [${level}] ${message}`);
|
|
@@ -3401,11 +892,11 @@ async function plugin(input, opts = {}) {
|
|
|
3401
892
|
appLog("info", `Raindrop tracing enabled \u2014 destinations: ${destinations.join(", ")}`);
|
|
3402
893
|
}
|
|
3403
894
|
const configuredAppGit = (_a = opts.appGit) != null ? _a : config.appGit;
|
|
3404
|
-
const appGitContext =
|
|
895
|
+
const appGitContext = createAppGitContext(
|
|
3405
896
|
((_b = config.writeKey) == null ? void 0 : _b.trim()) || hasLocalDestination ? configuredAppGit : false,
|
|
3406
897
|
{ allowLocalGit: false }
|
|
3407
898
|
);
|
|
3408
|
-
const eventShipper = new
|
|
899
|
+
const eventShipper = new EventShipper({
|
|
3409
900
|
writeKey: config.writeKey,
|
|
3410
901
|
endpoint: config.endpoint,
|
|
3411
902
|
debug: config.debug,
|
|
@@ -3413,7 +904,7 @@ async function plugin(input, opts = {}) {
|
|
|
3413
904
|
localDebuggerUrl: config.localWorkshopUrl,
|
|
3414
905
|
appGitContext
|
|
3415
906
|
});
|
|
3416
|
-
const traceShipper = new
|
|
907
|
+
const traceShipper = new TraceShipper({
|
|
3417
908
|
writeKey: config.writeKey,
|
|
3418
909
|
endpoint: config.endpoint,
|
|
3419
910
|
debug: config.debug,
|
|
@@ -3422,14 +913,55 @@ async function plugin(input, opts = {}) {
|
|
|
3422
913
|
appGitContext
|
|
3423
914
|
});
|
|
3424
915
|
const worktree = (_c = input.worktree) != null ? _c : input.directory;
|
|
3425
|
-
const
|
|
916
|
+
const tracing = createTracing(
|
|
3426
917
|
config,
|
|
3427
918
|
worktree,
|
|
3428
919
|
input.directory,
|
|
3429
920
|
eventShipper,
|
|
3430
921
|
traceShipper
|
|
3431
922
|
);
|
|
3432
|
-
|
|
923
|
+
const hooks = tracing.hooks;
|
|
924
|
+
const selfDiagnostics = normalizeSelfDiagnosticsConfig(
|
|
925
|
+
(_d = opts.selfDiagnostics) != null ? _d : config.selfDiagnostics
|
|
926
|
+
);
|
|
927
|
+
if (selfDiagnostics && !config.writeKey.trim()) {
|
|
928
|
+
appLog(
|
|
929
|
+
"warn",
|
|
930
|
+
`selfDiagnostics enabled but RAINDROP_WRITE_KEY is not set \u2014 the ${selfDiagnostics.toolName} tool is not registered (signals require the cloud destination).`
|
|
931
|
+
);
|
|
932
|
+
}
|
|
933
|
+
const [firstSignalKey, ...restSignalKeys] = config.writeKey.trim() && selfDiagnostics ? selfDiagnostics.signalKeys : [];
|
|
934
|
+
if (selfDiagnostics && firstSignalKey !== void 0) {
|
|
935
|
+
const cfg = selfDiagnostics;
|
|
936
|
+
hooks.tool = {
|
|
937
|
+
[cfg.toolName]: tool({
|
|
938
|
+
description: cfg.toolDescription,
|
|
939
|
+
args: {
|
|
940
|
+
category: tool.schema.enum([firstSignalKey, ...restSignalKeys]),
|
|
941
|
+
detail: tool.schema.string()
|
|
942
|
+
},
|
|
943
|
+
async execute(args, ctx) {
|
|
944
|
+
await trackSelfDiagnosticsSignal(
|
|
945
|
+
args,
|
|
946
|
+
cfg,
|
|
947
|
+
eventShipper,
|
|
948
|
+
tracing.currentEventId(ctx.sessionID),
|
|
949
|
+
config.debug
|
|
950
|
+
);
|
|
951
|
+
return SELF_DIAGNOSTICS_ACK;
|
|
952
|
+
}
|
|
953
|
+
})
|
|
954
|
+
};
|
|
955
|
+
}
|
|
956
|
+
return {
|
|
957
|
+
...hooks,
|
|
958
|
+
raindrop: createRaindropHandle(
|
|
959
|
+
eventShipper,
|
|
960
|
+
traceShipper,
|
|
961
|
+
appGitContext,
|
|
962
|
+
tracing.currentEventId
|
|
963
|
+
)
|
|
964
|
+
};
|
|
3433
965
|
}
|
|
3434
966
|
export {
|
|
3435
967
|
plugin as default
|