raindrop-ai 0.2.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 +135 -0
- package/dist/{chunk-XLEPN7ZO.mjs → chunk-5Y3LWBKV.mjs} +1033 -96
- package/dist/index-DBdUrUXc.d.mts +1457 -0
- package/dist/index-DBdUrUXc.d.ts +1457 -0
- package/dist/index.d.mts +5 -1180
- package/dist/index.d.ts +5 -1180
- package/dist/index.js +1111 -116
- package/dist/index.mjs +60 -1
- package/dist/tracing/index.d.mts +3 -1
- package/dist/tracing/index.d.ts +3 -1
- package/dist/tracing/index.js +1037 -101
- package/dist/tracing/index.mjs +1 -1
- package/package.json +2 -2
package/dist/tracing/index.js
CHANGED
|
@@ -42,7 +42,7 @@ if (!globalThis.RAINDROP_ASYNC_LOCAL_STORAGE) {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
// src/tracing/tracer-core.ts
|
|
45
|
-
var
|
|
45
|
+
var import_api5 = require("@opentelemetry/api");
|
|
46
46
|
var import_exporter_trace_otlp_http = require("@opentelemetry/exporter-trace-otlp-http");
|
|
47
47
|
var import_instrumentation_anthropic = require("@traceloop/instrumentation-anthropic");
|
|
48
48
|
var import_instrumentation_bedrock = require("@traceloop/instrumentation-bedrock");
|
|
@@ -56,7 +56,7 @@ var import_instrumentation_vertexai = require("@traceloop/instrumentation-vertex
|
|
|
56
56
|
var traceloop4 = __toESM(require("@traceloop/node-server-sdk"));
|
|
57
57
|
var import_weakref = require("weakref");
|
|
58
58
|
|
|
59
|
-
// ../core/dist/chunk-
|
|
59
|
+
// ../core/dist/chunk-YUIXRQWN.js
|
|
60
60
|
function normalizeFeatureFlags(input) {
|
|
61
61
|
if (Array.isArray(input)) {
|
|
62
62
|
return Object.fromEntries(input.map((name) => [name, "true"]));
|
|
@@ -65,6 +65,293 @@ function normalizeFeatureFlags(input) {
|
|
|
65
65
|
Object.entries(input).map(([k, v]) => [k, String(v)])
|
|
66
66
|
);
|
|
67
67
|
}
|
|
68
|
+
function getCrypto() {
|
|
69
|
+
const c = globalThis.crypto;
|
|
70
|
+
return c;
|
|
71
|
+
}
|
|
72
|
+
function randomBytes(length) {
|
|
73
|
+
const cryptoObj = getCrypto();
|
|
74
|
+
const out = new Uint8Array(length);
|
|
75
|
+
if (cryptoObj && typeof cryptoObj.getRandomValues === "function") {
|
|
76
|
+
cryptoObj.getRandomValues(out);
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
for (let i = 0; i < out.length; i++) out[i] = Math.floor(Math.random() * 256);
|
|
80
|
+
return out;
|
|
81
|
+
}
|
|
82
|
+
function randomUUID() {
|
|
83
|
+
const cryptoObj = getCrypto();
|
|
84
|
+
if (cryptoObj && typeof cryptoObj.randomUUID === "function") {
|
|
85
|
+
return cryptoObj.randomUUID();
|
|
86
|
+
}
|
|
87
|
+
const b = randomBytes(16);
|
|
88
|
+
b[6] = b[6] & 15 | 64;
|
|
89
|
+
b[8] = b[8] & 63 | 128;
|
|
90
|
+
const hex = [...b].map((x) => x.toString(16).padStart(2, "0")).join("");
|
|
91
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
92
|
+
}
|
|
93
|
+
var HANDOFF_ATTRIBUTE_SUFFIXES = {
|
|
94
|
+
mode: "raindrop.handoff.mode",
|
|
95
|
+
childEventId: "raindrop.handoff.childEventId",
|
|
96
|
+
parentEventId: "raindrop.handoff.parentEventId",
|
|
97
|
+
parentSpanId: "raindrop.handoff.parentSpanId",
|
|
98
|
+
name: "raindrop.handoff.name",
|
|
99
|
+
terminal: "raindrop.handoff.terminal",
|
|
100
|
+
agentRole: "raindrop.agent.role"
|
|
101
|
+
};
|
|
102
|
+
var AI_SDK_METADATA_PREFIX = "ai.telemetry.metadata.";
|
|
103
|
+
var DETACHED_MODE = "detached";
|
|
104
|
+
var SUBAGENT_AGENT_ROLE = "subagent";
|
|
105
|
+
var HANDOFF_TERMINAL_CANCELLED = "cancelled";
|
|
106
|
+
var TOOL_EVENTS_SUFFIX = "raindrop.toolEvents";
|
|
107
|
+
var TOOL_EVENTS_ALLOW = "allow";
|
|
108
|
+
var OPERATION_ID_ATTRIBUTE = "ai.operationId";
|
|
109
|
+
var SUBAGENT_ABORT_OPERATION_ID = "ai.subagent.failed";
|
|
110
|
+
var SUBAGENT_ABORT_SPAN_NAME = SUBAGENT_ABORT_OPERATION_ID;
|
|
111
|
+
var DEFAULT_DISPATCH_SPAN_NAME = "launch_subagent";
|
|
112
|
+
var HANDOFF_TERMINAL_PROPERTY_KEY = HANDOFF_ATTRIBUTE_SUFFIXES.terminal;
|
|
113
|
+
function defined(entries) {
|
|
114
|
+
const out = {};
|
|
115
|
+
for (const [key, value] of Object.entries(entries)) {
|
|
116
|
+
if (typeof value === "string" && value.trim().length > 0) out[key] = value;
|
|
117
|
+
}
|
|
118
|
+
return out;
|
|
119
|
+
}
|
|
120
|
+
function detachedDispatchMetadata(dispatch) {
|
|
121
|
+
return defined({
|
|
122
|
+
[HANDOFF_ATTRIBUTE_SUFFIXES.mode]: DETACHED_MODE,
|
|
123
|
+
[HANDOFF_ATTRIBUTE_SUFFIXES.childEventId]: dispatch.childEventId,
|
|
124
|
+
[HANDOFF_ATTRIBUTE_SUFFIXES.name]: dispatch.name
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
function detachedChildMetadata(link) {
|
|
128
|
+
return defined({
|
|
129
|
+
[HANDOFF_ATTRIBUTE_SUFFIXES.parentEventId]: link.parentEventId,
|
|
130
|
+
[HANDOFF_ATTRIBUTE_SUFFIXES.parentSpanId]: link.parentSpanId,
|
|
131
|
+
[HANDOFF_ATTRIBUTE_SUFFIXES.name]: link.name,
|
|
132
|
+
[HANDOFF_ATTRIBUTE_SUFFIXES.agentRole]: SUBAGENT_AGENT_ROLE
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
function cancelledTerminalMetadata() {
|
|
136
|
+
return { [HANDOFF_ATTRIBUTE_SUFFIXES.terminal]: HANDOFF_TERMINAL_CANCELLED };
|
|
137
|
+
}
|
|
138
|
+
function cancelledTerminalAttributes() {
|
|
139
|
+
const bare = cancelledTerminalMetadata();
|
|
140
|
+
return { ...bare, ...withMetadataPrefix(bare) };
|
|
141
|
+
}
|
|
142
|
+
function toolEventsAllowMetadata() {
|
|
143
|
+
return { [TOOL_EVENTS_SUFFIX]: TOOL_EVENTS_ALLOW };
|
|
144
|
+
}
|
|
145
|
+
function withMetadataPrefix(metadata) {
|
|
146
|
+
const out = {};
|
|
147
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
148
|
+
out[key.startsWith(AI_SDK_METADATA_PREFIX) ? key : `${AI_SDK_METADATA_PREFIX}${key}`] = value;
|
|
149
|
+
}
|
|
150
|
+
return out;
|
|
151
|
+
}
|
|
152
|
+
var BAGGAGE_KEYS = {
|
|
153
|
+
eventId: "raindrop-event-id",
|
|
154
|
+
childEventId: "raindrop-child-event-id",
|
|
155
|
+
name: "raindrop-handoff-name",
|
|
156
|
+
convoId: "raindrop-convo-id",
|
|
157
|
+
userId: "raindrop-user-id",
|
|
158
|
+
// The dispatch span and its trace, carried as fields as well as in
|
|
159
|
+
// `traceparent`. Not redundant: OTel's HTTP instrumentations rewrite
|
|
160
|
+
// `traceparent` from whatever span is current as the request goes out, so by
|
|
161
|
+
// the time the child reads it the ids name the HTTP client span and its trace
|
|
162
|
+
// instead of the dispatch. The child would then point its reverse reference at
|
|
163
|
+
// a span the launcher's UI does not know as a dispatch. A field states which
|
|
164
|
+
// span it means rather than meaning "whoever wrote this header last".
|
|
165
|
+
dispatchSpanId: "raindrop-dispatch-span-id",
|
|
166
|
+
traceId: "raindrop-trace-id"
|
|
167
|
+
};
|
|
168
|
+
var TRACEPARENT_HEADER = "traceparent";
|
|
169
|
+
var BAGGAGE_HEADER = "baggage";
|
|
170
|
+
var W3C_TRACE_ID = /^[0-9a-f]{32}$/;
|
|
171
|
+
var W3C_SPAN_ID = /^[0-9a-f]{16}$/;
|
|
172
|
+
function isW3CTraceId(value) {
|
|
173
|
+
return value !== void 0 && W3C_TRACE_ID.test(value);
|
|
174
|
+
}
|
|
175
|
+
function isW3CSpanId(value) {
|
|
176
|
+
return value !== void 0 && W3C_SPAN_ID.test(value);
|
|
177
|
+
}
|
|
178
|
+
var warnedNonConformantIds = false;
|
|
179
|
+
function warnNonConformantIdsOnce(traceId, spanId) {
|
|
180
|
+
if (warnedNonConformantIds) return;
|
|
181
|
+
warnedNonConformantIds = true;
|
|
182
|
+
console.warn(
|
|
183
|
+
`[raindrop] hand-off carrier ids are not W3C-shaped (traceId="${traceId}", spanId="${spanId}"). The child still reports as its own event, but its reverse reference names a span id the backend does not store, so the link back to the launcher will not resolve. A LangSmith carrier reads this way \u2014 its run ids are UUIDs; propagate Raindrop's own carrier (toHeaders) to link.`
|
|
184
|
+
);
|
|
185
|
+
}
|
|
186
|
+
var HANDOFF_HEADER = "x-raindrop-handoff";
|
|
187
|
+
var LANGSMITH_TRACE_HEADER = "langsmith-trace";
|
|
188
|
+
var LANGSMITH_METADATA_BAGGAGE_KEY = "langsmith-metadata";
|
|
189
|
+
function encodeBaggage(entries) {
|
|
190
|
+
return Object.entries(entries).filter((entry) => Boolean(entry[1])).map(([key, value]) => `${key}=${encodeURIComponent(value)}`).join(",");
|
|
191
|
+
}
|
|
192
|
+
function decodeBaggage(header) {
|
|
193
|
+
if (!header) return {};
|
|
194
|
+
const parsed = {};
|
|
195
|
+
for (const part of header.split(",")) {
|
|
196
|
+
const [rawKey, ...rest] = part.split("=");
|
|
197
|
+
if (!rawKey || rest.length === 0) continue;
|
|
198
|
+
const key = rawKey.trim();
|
|
199
|
+
let value;
|
|
200
|
+
try {
|
|
201
|
+
value = decodeURIComponent(rest.join("=").trim());
|
|
202
|
+
} catch (e) {
|
|
203
|
+
value = rest.join("=").trim();
|
|
204
|
+
}
|
|
205
|
+
if (key in parsed && parsed[key] !== value) throw new ConflictingCarrierError(key);
|
|
206
|
+
parsed[key] = value;
|
|
207
|
+
}
|
|
208
|
+
return parsed;
|
|
209
|
+
}
|
|
210
|
+
function carrierBaggage(carrier) {
|
|
211
|
+
return {
|
|
212
|
+
[BAGGAGE_KEYS.eventId]: carrier.eventId,
|
|
213
|
+
[BAGGAGE_KEYS.childEventId]: carrier.childEventId,
|
|
214
|
+
[BAGGAGE_KEYS.name]: carrier.name,
|
|
215
|
+
[BAGGAGE_KEYS.convoId]: carrier.convoId,
|
|
216
|
+
[BAGGAGE_KEYS.userId]: carrier.userId,
|
|
217
|
+
[BAGGAGE_KEYS.dispatchSpanId]: carrier.spanId,
|
|
218
|
+
[BAGGAGE_KEYS.traceId]: carrier.traceId
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
function toHeaders(carrier) {
|
|
222
|
+
const fields = encodeBaggage(carrierBaggage(carrier));
|
|
223
|
+
const headers = {
|
|
224
|
+
[BAGGAGE_HEADER]: fields,
|
|
225
|
+
[HANDOFF_HEADER]: fields
|
|
226
|
+
};
|
|
227
|
+
if (isW3CTraceId(carrier.traceId) && isW3CSpanId(carrier.spanId)) {
|
|
228
|
+
headers[TRACEPARENT_HEADER] = `00-${carrier.traceId}-${carrier.spanId}-01`;
|
|
229
|
+
}
|
|
230
|
+
return headers;
|
|
231
|
+
}
|
|
232
|
+
function langsmithStamp() {
|
|
233
|
+
return (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/g, "").replace(/\.\d+Z$/, "000000");
|
|
234
|
+
}
|
|
235
|
+
function toLangSmithHeaders(carrier) {
|
|
236
|
+
const stamp = langsmithStamp();
|
|
237
|
+
const dottedOrder = `${stamp}Z${carrier.traceId}.${stamp}Z${carrier.spanId}`;
|
|
238
|
+
return {
|
|
239
|
+
[LANGSMITH_TRACE_HEADER]: dottedOrder,
|
|
240
|
+
[BAGGAGE_HEADER]: encodeBaggage({
|
|
241
|
+
[LANGSMITH_METADATA_BAGGAGE_KEY]: JSON.stringify(carrierBaggage(carrier))
|
|
242
|
+
}),
|
|
243
|
+
// Carried here too: a LangSmith-shaped carrier is rewritten in transit
|
|
244
|
+
// exactly like the native one, and an injected `traceparent` is preferred
|
|
245
|
+
// over the dotted order on read.
|
|
246
|
+
[HANDOFF_HEADER]: encodeBaggage(carrierBaggage(carrier))
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
function isHeaderLookup(headers) {
|
|
250
|
+
return "get" in headers && typeof headers.get === "function";
|
|
251
|
+
}
|
|
252
|
+
var ConflictingCarrierError = class extends Error {
|
|
253
|
+
};
|
|
254
|
+
function readHeader(headers, name) {
|
|
255
|
+
var _a, _b, _c;
|
|
256
|
+
if (isHeaderLookup(headers)) return (_a = headers.get(name)) != null ? _a : void 0;
|
|
257
|
+
const value = (_c = headers[name]) != null ? _c : (_b = Object.entries(headers).find(([key]) => key.toLowerCase() === name)) == null ? void 0 : _b[1];
|
|
258
|
+
if (!Array.isArray(value)) return value;
|
|
259
|
+
const distinct = new Set(value);
|
|
260
|
+
if (distinct.size > 1) throw new ConflictingCarrierError(name);
|
|
261
|
+
return value[0];
|
|
262
|
+
}
|
|
263
|
+
function readTraceHeader(headers, name) {
|
|
264
|
+
const value = readHeader(headers, name);
|
|
265
|
+
if (!(value == null ? void 0 : value.includes(","))) return value;
|
|
266
|
+
const copies = value.split(",").map((copy) => copy.trim());
|
|
267
|
+
if (new Set(copies).size > 1) throw new ConflictingCarrierError(name);
|
|
268
|
+
return copies[0];
|
|
269
|
+
}
|
|
270
|
+
function fromHeaders(headers) {
|
|
271
|
+
var _a, _b;
|
|
272
|
+
let baggage;
|
|
273
|
+
let handoff;
|
|
274
|
+
let traceparent;
|
|
275
|
+
let langsmithTrace;
|
|
276
|
+
try {
|
|
277
|
+
baggage = decodeBaggage(readHeader(headers, BAGGAGE_HEADER));
|
|
278
|
+
handoff = decodeBaggage(readHeader(headers, HANDOFF_HEADER));
|
|
279
|
+
traceparent = readTraceHeader(headers, TRACEPARENT_HEADER);
|
|
280
|
+
langsmithTrace = readTraceHeader(headers, LANGSMITH_TRACE_HEADER);
|
|
281
|
+
} catch (error) {
|
|
282
|
+
if (error instanceof ConflictingCarrierError) return null;
|
|
283
|
+
throw error;
|
|
284
|
+
}
|
|
285
|
+
const langsmithMetadata = baggage[LANGSMITH_METADATA_BAGGAGE_KEY];
|
|
286
|
+
const nested = langsmithMetadata ? safeParseStringRecord(langsmithMetadata) : {};
|
|
287
|
+
for (const [key, value] of Object.entries(nested)) {
|
|
288
|
+
if (key in baggage && baggage[key] !== value) return null;
|
|
289
|
+
}
|
|
290
|
+
const fields = {
|
|
291
|
+
...baggage,
|
|
292
|
+
...nested,
|
|
293
|
+
// Last, so it wins: the standard headers may have been rewritten in transit
|
|
294
|
+
// by a propagator, this one is only ever written by us.
|
|
295
|
+
...handoff
|
|
296
|
+
};
|
|
297
|
+
let traceId;
|
|
298
|
+
let spanId;
|
|
299
|
+
if (traceparent) {
|
|
300
|
+
const [, parsedTraceId, parsedSpanId] = traceparent.split("-");
|
|
301
|
+
if (isW3CTraceId(parsedTraceId) && isW3CSpanId(parsedSpanId)) {
|
|
302
|
+
traceId = parsedTraceId;
|
|
303
|
+
spanId = parsedSpanId;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
if (!traceId && !spanId && langsmithTrace) {
|
|
307
|
+
const segments = langsmithTrace.split(".");
|
|
308
|
+
traceId = (_a = segments[0]) == null ? void 0 : _a.split("Z").pop();
|
|
309
|
+
spanId = (_b = segments[segments.length - 1]) == null ? void 0 : _b.split("Z").pop();
|
|
310
|
+
}
|
|
311
|
+
traceId = fields[BAGGAGE_KEYS.traceId] || traceId;
|
|
312
|
+
spanId = fields[BAGGAGE_KEYS.dispatchSpanId] || spanId;
|
|
313
|
+
const eventId = fields[BAGGAGE_KEYS.eventId];
|
|
314
|
+
if (!traceId || !spanId || !eventId) return null;
|
|
315
|
+
if (!isW3CTraceId(traceId) || !isW3CSpanId(spanId)) {
|
|
316
|
+
warnNonConformantIdsOnce(traceId, spanId);
|
|
317
|
+
}
|
|
318
|
+
const carrier = { traceId, spanId, eventId };
|
|
319
|
+
const childEventId = fields[BAGGAGE_KEYS.childEventId];
|
|
320
|
+
if (childEventId) carrier.childEventId = childEventId;
|
|
321
|
+
const name = fields[BAGGAGE_KEYS.name];
|
|
322
|
+
if (name) carrier.name = name;
|
|
323
|
+
const convoId = fields[BAGGAGE_KEYS.convoId];
|
|
324
|
+
if (convoId) carrier.convoId = convoId;
|
|
325
|
+
const userId = fields[BAGGAGE_KEYS.userId];
|
|
326
|
+
if (userId) carrier.userId = userId;
|
|
327
|
+
return carrier;
|
|
328
|
+
}
|
|
329
|
+
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.`;
|
|
330
|
+
var UNRESOLVED_CARRIER_WARNED_KEY = /* @__PURE__ */ Symbol.for("raindrop.handoff.warnedUnresolvedCarrier");
|
|
331
|
+
function warnedHolder() {
|
|
332
|
+
return globalThis;
|
|
333
|
+
}
|
|
334
|
+
function warnUnresolvedCarrier(headers, carrier) {
|
|
335
|
+
if (carrier) return;
|
|
336
|
+
if (!headers) return;
|
|
337
|
+
const holder = warnedHolder();
|
|
338
|
+
if (holder[UNRESOLVED_CARRIER_WARNED_KEY]) return;
|
|
339
|
+
holder[UNRESOLVED_CARRIER_WARNED_KEY] = true;
|
|
340
|
+
console.warn(UNRESOLVED_CARRIER_WARNING);
|
|
341
|
+
}
|
|
342
|
+
function safeParseStringRecord(raw) {
|
|
343
|
+
try {
|
|
344
|
+
const parsed = JSON.parse(raw);
|
|
345
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
346
|
+
const result = {};
|
|
347
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
348
|
+
if (typeof value === "string") result[key] = value;
|
|
349
|
+
}
|
|
350
|
+
return result;
|
|
351
|
+
} catch (e) {
|
|
352
|
+
return {};
|
|
353
|
+
}
|
|
354
|
+
}
|
|
68
355
|
function runWithTracingSuppressed(fn) {
|
|
69
356
|
const hook = globalThis.RAINDROP_SUPPRESS_TRACING;
|
|
70
357
|
if (typeof hook !== "function") return fn();
|
|
@@ -408,6 +695,62 @@ function projectIdHeaders(projectId) {
|
|
|
408
695
|
}
|
|
409
696
|
var SHUTDOWN_DEADLINE_MS = 1e4;
|
|
410
697
|
var POST_SHUTDOWN_TIMEOUT_MS = 5e3;
|
|
698
|
+
var MODEL_USAGE_ATTRIBUTES = {
|
|
699
|
+
providerName: "gen_ai.provider.name",
|
|
700
|
+
requestModel: "gen_ai.request.model",
|
|
701
|
+
responseModel: "gen_ai.response.model",
|
|
702
|
+
inputTokens: "gen_ai.usage.input_tokens",
|
|
703
|
+
outputTokens: "gen_ai.usage.output_tokens",
|
|
704
|
+
reasoningTokens: "gen_ai.usage.reasoning_tokens",
|
|
705
|
+
cacheReadInputTokens: "gen_ai.usage.cache_read_input_tokens",
|
|
706
|
+
cacheWriteInputTokens: "gen_ai.usage.cache_write_input_tokens",
|
|
707
|
+
nonCachedInputTokens: "raindrop.usage.input_tokens.non_cached",
|
|
708
|
+
nonReasoningOutputTokens: "raindrop.usage.output_tokens.non_reasoning",
|
|
709
|
+
totalOutputTokens: "raindrop.usage.output_tokens.total",
|
|
710
|
+
reasoningOutputTokens: "raindrop.usage.output_tokens.reasoning",
|
|
711
|
+
cacheReadTokens: "raindrop.usage.input_tokens.cache_read",
|
|
712
|
+
cacheWriteTokens: "raindrop.usage.input_tokens.cache_write"
|
|
713
|
+
};
|
|
714
|
+
var STRING_ALIASES = {
|
|
715
|
+
[MODEL_USAGE_ATTRIBUTES.requestModel]: ["ai.model.id", "ai.model"]
|
|
716
|
+
};
|
|
717
|
+
var NUMBER_ALIASES = {
|
|
718
|
+
[MODEL_USAGE_ATTRIBUTES.inputTokens]: [
|
|
719
|
+
"gen_ai.usage.prompt_tokens",
|
|
720
|
+
"ai.usage.prompt_tokens",
|
|
721
|
+
"ai.usage.promptTokens",
|
|
722
|
+
"ai.usage.input_tokens",
|
|
723
|
+
"ai.usage.inputTokens"
|
|
724
|
+
],
|
|
725
|
+
[MODEL_USAGE_ATTRIBUTES.outputTokens]: [
|
|
726
|
+
"gen_ai.usage.completion_tokens",
|
|
727
|
+
"ai.usage.completion_tokens",
|
|
728
|
+
"ai.usage.completionTokens",
|
|
729
|
+
"ai.usage.output_tokens",
|
|
730
|
+
"ai.usage.outputTokens"
|
|
731
|
+
],
|
|
732
|
+
[MODEL_USAGE_ATTRIBUTES.reasoningTokens]: [
|
|
733
|
+
"gen_ai.usage.reasoning.output_tokens",
|
|
734
|
+
"ai.usage.reasoningTokens",
|
|
735
|
+
"ai.usage.thoughts_tokens"
|
|
736
|
+
],
|
|
737
|
+
[MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens]: [
|
|
738
|
+
"gen_ai.usage.cache_read_tokens",
|
|
739
|
+
"gen_ai.usage.cache_read.input_tokens",
|
|
740
|
+
"ai.usage.cachedInputTokens",
|
|
741
|
+
"ai.usage.cached_tokens",
|
|
742
|
+
"ai.usage.cache_read_tokens",
|
|
743
|
+
"ai.usage.cache_read_input_tokens",
|
|
744
|
+
"ai.usage.cacheReadInputTokens"
|
|
745
|
+
],
|
|
746
|
+
[MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens]: [
|
|
747
|
+
"gen_ai.usage.cache_creation_input_tokens",
|
|
748
|
+
"gen_ai.usage.cache_creation.input_tokens",
|
|
749
|
+
"ai.usage.cacheWriteInputTokens",
|
|
750
|
+
"ai.usage.cache_creation_input_tokens",
|
|
751
|
+
"ai.usage.cacheCreationInputTokens"
|
|
752
|
+
]
|
|
753
|
+
};
|
|
411
754
|
var DEFAULT_REDACT_ATTRIBUTE_KEYS = [
|
|
412
755
|
"ai.request.providerOptions",
|
|
413
756
|
"ai.response.providerMetadata"
|
|
@@ -422,8 +765,10 @@ function getWeakRefCtor() {
|
|
|
422
765
|
}
|
|
423
766
|
var MAX_BINDING_STACK = 128;
|
|
424
767
|
var EMPTY_STACK = [];
|
|
425
|
-
var
|
|
426
|
-
|
|
768
|
+
var ContextStackStorage = class {
|
|
769
|
+
/** Emitted once when this runtime cannot support an ambient push. */
|
|
770
|
+
constructor(noAmbientBindWarning) {
|
|
771
|
+
this.noAmbientBindWarning = noAmbientBindWarning;
|
|
427
772
|
this._als = null;
|
|
428
773
|
this._enterWithUsable = false;
|
|
429
774
|
this._syncStack = EMPTY_STACK;
|
|
@@ -520,17 +865,17 @@ var RoutingContextStorage = class {
|
|
|
520
865
|
warnNoAmbientBindOnce() {
|
|
521
866
|
if (this._warnedNoAmbientBind) return;
|
|
522
867
|
this._warnedNoAmbientBind = true;
|
|
523
|
-
console.warn(
|
|
524
|
-
"[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."
|
|
525
|
-
);
|
|
868
|
+
console.warn(this.noAmbientBindWarning);
|
|
526
869
|
}
|
|
527
870
|
};
|
|
871
|
+
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.";
|
|
872
|
+
var NO_AMBIENT_ATTRIBUTE_BIND_WARNING = "[raindrop] This runtime's AsyncLocalStorage does not implement enterWith (e.g. Cloudflare Workers), so contextual span attributes (the detached sub-agent hand-off reference) cannot be bound ambiently without cross-contaminating concurrent requests. The child's own event still reports; only the per-span reverse reference is skipped.";
|
|
528
873
|
var ROUTING_STORAGE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.routingContextStorage");
|
|
529
874
|
function routingStorage() {
|
|
530
875
|
const holder = globalThis;
|
|
531
876
|
let storage = holder[ROUTING_STORAGE_KEY];
|
|
532
877
|
if (!storage) {
|
|
533
|
-
storage = new
|
|
878
|
+
storage = new ContextStackStorage(NO_AMBIENT_ROUTING_BIND_WARNING);
|
|
534
879
|
holder[ROUTING_STORAGE_KEY] = storage;
|
|
535
880
|
}
|
|
536
881
|
return storage;
|
|
@@ -578,6 +923,104 @@ function currentRoutingBinding() {
|
|
|
578
923
|
function isBoundContext(value) {
|
|
579
924
|
return typeof value.isLive === "function";
|
|
580
925
|
}
|
|
926
|
+
var ATTRIBUTE_STORAGE_KEY = /* @__PURE__ */ Symbol.for("raindrop.tracing.spanAttributeStorage");
|
|
927
|
+
function attributeStorage() {
|
|
928
|
+
const holder = globalThis;
|
|
929
|
+
let storage = holder[ATTRIBUTE_STORAGE_KEY];
|
|
930
|
+
if (!storage) {
|
|
931
|
+
storage = new ContextStackStorage(NO_AMBIENT_ATTRIBUTE_BIND_WARNING);
|
|
932
|
+
holder[ATTRIBUTE_STORAGE_KEY] = storage;
|
|
933
|
+
}
|
|
934
|
+
return storage;
|
|
935
|
+
}
|
|
936
|
+
function makeAttributeFrame(attributes, owner) {
|
|
937
|
+
const snapshot = { ...attributes };
|
|
938
|
+
const WeakRefCtor = owner !== void 0 ? getWeakRefCtor() : void 0;
|
|
939
|
+
const ref = WeakRefCtor && owner !== void 0 ? new WeakRefCtor(owner) : void 0;
|
|
940
|
+
const owned = /* @__PURE__ */ new WeakSet();
|
|
941
|
+
let dead = false;
|
|
942
|
+
let sawError = false;
|
|
943
|
+
return {
|
|
944
|
+
attributes: snapshot,
|
|
945
|
+
sawErrorSpan: () => sawError,
|
|
946
|
+
ownsSpan: (span) => owned.has(span),
|
|
947
|
+
claimSpan(span) {
|
|
948
|
+
owned.add(span);
|
|
949
|
+
},
|
|
950
|
+
markErrorSpanSeen() {
|
|
951
|
+
sawError = true;
|
|
952
|
+
},
|
|
953
|
+
// A frame whose owner has been collected is dead even though nothing
|
|
954
|
+
// unbound it: a run that never settles must not keep handing its reverse
|
|
955
|
+
// reference to whatever runs next on a reused context.
|
|
956
|
+
isLive() {
|
|
957
|
+
if (dead) return false;
|
|
958
|
+
return ref === void 0 || ref.deref() !== void 0;
|
|
959
|
+
},
|
|
960
|
+
markDead() {
|
|
961
|
+
dead = true;
|
|
962
|
+
}
|
|
963
|
+
};
|
|
964
|
+
}
|
|
965
|
+
function bindSpanAttributes(attributes, owner) {
|
|
966
|
+
if (Object.keys(attributes).length === 0) return void 0;
|
|
967
|
+
const frame = makeAttributeFrame(attributes, owner);
|
|
968
|
+
try {
|
|
969
|
+
attributeStorage().push(frame);
|
|
970
|
+
} catch (e) {
|
|
971
|
+
return void 0;
|
|
972
|
+
}
|
|
973
|
+
return frame;
|
|
974
|
+
}
|
|
975
|
+
function unbindSpanAttributes(frame) {
|
|
976
|
+
if (!frame || !isAttributeFrame(frame)) return;
|
|
977
|
+
try {
|
|
978
|
+
attributeStorage().remove(frame);
|
|
979
|
+
} catch (e) {
|
|
980
|
+
}
|
|
981
|
+
}
|
|
982
|
+
function applySpanAttributeFrames(span, setAttribute) {
|
|
983
|
+
try {
|
|
984
|
+
for (const frame of attributeStorage().getStack()) {
|
|
985
|
+
if (!frame.isLive()) continue;
|
|
986
|
+
frame.claimSpan(span);
|
|
987
|
+
for (const [key, value] of Object.entries(frame.attributes)) {
|
|
988
|
+
setAttribute(key, value);
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
} catch (e) {
|
|
992
|
+
}
|
|
993
|
+
}
|
|
994
|
+
function claimSpanForFrames(span) {
|
|
995
|
+
try {
|
|
996
|
+
for (const frame of attributeStorage().getStack()) {
|
|
997
|
+
if (frame.isLive()) frame.claimSpan(span);
|
|
998
|
+
}
|
|
999
|
+
} catch (e) {
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
function currentSpanAttributes() {
|
|
1003
|
+
const merged = {};
|
|
1004
|
+
try {
|
|
1005
|
+
for (const frame of attributeStorage().getStack()) {
|
|
1006
|
+
if (!frame.isLive()) continue;
|
|
1007
|
+
Object.assign(merged, frame.attributes);
|
|
1008
|
+
}
|
|
1009
|
+
} catch (e) {
|
|
1010
|
+
}
|
|
1011
|
+
return merged;
|
|
1012
|
+
}
|
|
1013
|
+
function markErrorSpanSeen(span) {
|
|
1014
|
+
try {
|
|
1015
|
+
for (const frame of attributeStorage().getStack()) {
|
|
1016
|
+
if (frame.ownsSpan(span)) frame.markErrorSpanSeen();
|
|
1017
|
+
}
|
|
1018
|
+
} catch (e) {
|
|
1019
|
+
}
|
|
1020
|
+
}
|
|
1021
|
+
function isAttributeFrame(value) {
|
|
1022
|
+
return typeof value.isLive === "function";
|
|
1023
|
+
}
|
|
581
1024
|
|
|
582
1025
|
// ../core/dist/index.node.js
|
|
583
1026
|
var import_async_hooks = require("async_hooks");
|
|
@@ -701,12 +1144,12 @@ async function postJson2(url, body, headers, opts) {
|
|
|
701
1144
|
}
|
|
702
1145
|
|
|
703
1146
|
// src/tracing/direct/ids.ts
|
|
704
|
-
function
|
|
1147
|
+
function getCrypto2() {
|
|
705
1148
|
const c = globalThis.crypto;
|
|
706
1149
|
return c;
|
|
707
1150
|
}
|
|
708
1151
|
function randomBytes2(length) {
|
|
709
|
-
const cryptoObj =
|
|
1152
|
+
const cryptoObj = getCrypto2();
|
|
710
1153
|
const out = new Uint8Array(length);
|
|
711
1154
|
if (cryptoObj && typeof cryptoObj.getRandomValues === "function") {
|
|
712
1155
|
cryptoObj.getRandomValues(out);
|
|
@@ -744,7 +1187,7 @@ function base64Encode2(bytes) {
|
|
|
744
1187
|
}
|
|
745
1188
|
return out;
|
|
746
1189
|
}
|
|
747
|
-
function
|
|
1190
|
+
function base64ToHex2(base64) {
|
|
748
1191
|
const maybeBuffer = globalThis.Buffer;
|
|
749
1192
|
if (maybeBuffer) {
|
|
750
1193
|
return maybeBuffer.from(base64, "base64").toString("hex");
|
|
@@ -764,7 +1207,7 @@ function base64ToHex(base64) {
|
|
|
764
1207
|
// package.json
|
|
765
1208
|
var package_default = {
|
|
766
1209
|
name: "raindrop-ai",
|
|
767
|
-
version: "0.
|
|
1210
|
+
version: "0.3.0",
|
|
768
1211
|
main: "dist/index.js",
|
|
769
1212
|
module: "dist/index.mjs",
|
|
770
1213
|
types: "dist/index.d.ts",
|
|
@@ -961,6 +1404,7 @@ var PROJECT_ID_SPAN_ATTRIBUTE = "raindrop.project_id";
|
|
|
961
1404
|
var AUTH_HINT_SPAN_ATTRIBUTE = "raindrop.auth_hint";
|
|
962
1405
|
var EXPORT_SUCCESS = 0;
|
|
963
1406
|
var EXPORT_FAILED = 1;
|
|
1407
|
+
var SPAN_STATUS_ERROR = 2;
|
|
964
1408
|
function authHintForKey(writeKey) {
|
|
965
1409
|
if (!writeKey) return void 0;
|
|
966
1410
|
return (0, import_node_crypto.createHash)("sha256").update(writeKey, "utf8").digest("hex").slice(0, 8);
|
|
@@ -1023,16 +1467,29 @@ function stampSpan(span, projectId, authHint) {
|
|
|
1023
1467
|
} catch (e) {
|
|
1024
1468
|
}
|
|
1025
1469
|
}
|
|
1470
|
+
function stampContextAttributes(span) {
|
|
1471
|
+
try {
|
|
1472
|
+
applySpanAttributeFrames(span, (key, value) => span.setAttribute(key, value));
|
|
1473
|
+
} catch (e) {
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1026
1476
|
var RaindropContextSpanProcessor = class {
|
|
1027
1477
|
onStart(span) {
|
|
1028
1478
|
try {
|
|
1479
|
+
stampContextAttributes(span);
|
|
1029
1480
|
const bound = currentRoutingBinding();
|
|
1030
1481
|
if (!bound) return;
|
|
1031
1482
|
stampSpan(span, bound.projectId, bound.authHint);
|
|
1032
1483
|
} catch (e) {
|
|
1033
1484
|
}
|
|
1034
1485
|
}
|
|
1035
|
-
onEnd() {
|
|
1486
|
+
onEnd(span) {
|
|
1487
|
+
var _a;
|
|
1488
|
+
try {
|
|
1489
|
+
if (((_a = span == null ? void 0 : span.status) == null ? void 0 : _a.code) !== SPAN_STATUS_ERROR) return;
|
|
1490
|
+
markErrorSpanSeen(span);
|
|
1491
|
+
} catch (e) {
|
|
1492
|
+
}
|
|
1036
1493
|
}
|
|
1037
1494
|
async forceFlush() {
|
|
1038
1495
|
}
|
|
@@ -1211,9 +1668,18 @@ var DirectTraceShipper = class {
|
|
|
1211
1668
|
attrString2(`traceloop.association.properties.${key}`, serializeAssociationValue(value))
|
|
1212
1669
|
);
|
|
1213
1670
|
}
|
|
1671
|
+
const spanIdentity = { spanIdB64 };
|
|
1672
|
+
claimSpanForFrames(spanIdentity);
|
|
1673
|
+
for (const [key, value] of Object.entries({
|
|
1674
|
+
...currentSpanAttributes(),
|
|
1675
|
+
...params.attributes
|
|
1676
|
+
})) {
|
|
1677
|
+
attributes.push(attrString2(key, value));
|
|
1678
|
+
}
|
|
1214
1679
|
let status;
|
|
1215
1680
|
if (params.error) {
|
|
1216
1681
|
status = { code: 2, message: params.error };
|
|
1682
|
+
markErrorSpanSeen(spanIdentity);
|
|
1217
1683
|
} else {
|
|
1218
1684
|
status = {
|
|
1219
1685
|
code: 1
|
|
@@ -1362,18 +1828,305 @@ var DirectTraceShipper = class {
|
|
|
1362
1828
|
};
|
|
1363
1829
|
|
|
1364
1830
|
// src/tracing/liveInteraction.ts
|
|
1365
|
-
var
|
|
1831
|
+
var import_api3 = require("@opentelemetry/api");
|
|
1366
1832
|
var traceloop = __toESM(require("@traceloop/node-server-sdk"));
|
|
1367
|
-
|
|
1833
|
+
|
|
1834
|
+
// src/tracing/subagents.ts
|
|
1835
|
+
var import_api2 = require("@opentelemetry/api");
|
|
1836
|
+
var DEFAULT_SUBAGENT_NAME = "subagent";
|
|
1837
|
+
var DISPATCH_ACCEPTED = "accepted";
|
|
1838
|
+
function reasonText(reason) {
|
|
1839
|
+
var _a;
|
|
1840
|
+
if (reason instanceof Error) return `${reason.name}: ${reason.message}`;
|
|
1841
|
+
if (typeof reason === "string") return reason;
|
|
1842
|
+
if (reason === void 0 || reason === null) return "";
|
|
1843
|
+
try {
|
|
1844
|
+
return (_a = JSON.stringify(reason)) != null ? _a : String(reason);
|
|
1845
|
+
} catch (e) {
|
|
1846
|
+
return String(reason);
|
|
1847
|
+
}
|
|
1848
|
+
}
|
|
1849
|
+
function stampCurrentSpan(attributes) {
|
|
1850
|
+
try {
|
|
1851
|
+
const span = import_api2.trace.getSpan(import_api2.context.active());
|
|
1852
|
+
if (!(span == null ? void 0 : span.isRecording())) return;
|
|
1853
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
1854
|
+
span.setAttribute(key, value);
|
|
1855
|
+
}
|
|
1856
|
+
} catch (e) {
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
function stampOwnSpan(attributes, frame) {
|
|
1860
|
+
if (!frame) return;
|
|
1861
|
+
try {
|
|
1862
|
+
const span = import_api2.trace.getSpan(import_api2.context.active());
|
|
1863
|
+
if (!(span == null ? void 0 : span.isRecording()) || !frame.ownsSpan(span)) return;
|
|
1864
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
1865
|
+
span.setAttribute(key, value);
|
|
1866
|
+
}
|
|
1867
|
+
} catch (e) {
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
function failOwnSpan(reason, frame) {
|
|
1871
|
+
try {
|
|
1872
|
+
const span = import_api2.trace.getSpan(import_api2.context.active());
|
|
1873
|
+
if (!(span == null ? void 0 : span.isRecording())) return false;
|
|
1874
|
+
if (!(frame == null ? void 0 : frame.ownsSpan(span))) return false;
|
|
1875
|
+
const message = reasonText(reason);
|
|
1876
|
+
span.setStatus({ code: import_api2.SpanStatusCode.ERROR, message });
|
|
1877
|
+
span.recordException(reason instanceof Error ? reason : new Error(message));
|
|
1878
|
+
return true;
|
|
1879
|
+
} catch (e) {
|
|
1880
|
+
return false;
|
|
1881
|
+
}
|
|
1882
|
+
}
|
|
1883
|
+
function allowToolEvents(interaction) {
|
|
1884
|
+
const attributes = withMetadataPrefix(toolEventsAllowMetadata());
|
|
1885
|
+
interaction.bindToolEventsOptIn(attributes);
|
|
1886
|
+
stampCurrentSpan(attributes);
|
|
1887
|
+
}
|
|
1888
|
+
function recordSubagentDispatch(interaction, options) {
|
|
1889
|
+
var _a;
|
|
1890
|
+
const childEventId = options.childEventId || randomUUID();
|
|
1891
|
+
const name = options.name || DEFAULT_SUBAGENT_NAME;
|
|
1892
|
+
const parentEventId = (_a = interaction.getEventId()) != null ? _a : "";
|
|
1893
|
+
let traceIdHex;
|
|
1894
|
+
let dispatchSpanId;
|
|
1895
|
+
try {
|
|
1896
|
+
allowToolEvents(interaction);
|
|
1897
|
+
const recorded = interaction.recordDispatchSpan({
|
|
1898
|
+
name: options.toolName || DEFAULT_DISPATCH_SPAN_NAME,
|
|
1899
|
+
input: options.input,
|
|
1900
|
+
// A launch's "result" is the job handle; the answer belongs to the
|
|
1901
|
+
// child's event and never appears here.
|
|
1902
|
+
output: { jobId: childEventId, status: DISPATCH_ACCEPTED },
|
|
1903
|
+
properties: options.properties,
|
|
1904
|
+
attributes: detachedDispatchMetadata({ childEventId, name })
|
|
1905
|
+
});
|
|
1906
|
+
traceIdHex = recorded.traceIdHex;
|
|
1907
|
+
dispatchSpanId = recorded.spanIdHex;
|
|
1908
|
+
if (!dispatchSpanId) {
|
|
1909
|
+
console.warn(
|
|
1910
|
+
`[raindrop] subagent(${name}): no dispatch span was recorded, so event ${parentEventId} will not show the launch and NO carrier is returned \u2014 there is no span for the child to reference. Pass childEventId (${childEventId}) to the worker yourself if it must still report under that id. Tracing must be enabled for dispatches to be recorded.`
|
|
1911
|
+
);
|
|
1912
|
+
}
|
|
1913
|
+
} catch (error) {
|
|
1914
|
+
console.warn(
|
|
1915
|
+
`[raindrop] subagent(${name}) failed to record the dispatch; returning a carrier so the child still links back.`,
|
|
1916
|
+
error instanceof Error ? error.message : error
|
|
1917
|
+
);
|
|
1918
|
+
}
|
|
1919
|
+
if (!traceIdHex || !dispatchSpanId) {
|
|
1920
|
+
return {
|
|
1921
|
+
childEventId,
|
|
1922
|
+
name,
|
|
1923
|
+
parentEventId,
|
|
1924
|
+
dispatchSpanId: void 0,
|
|
1925
|
+
carrier: null,
|
|
1926
|
+
headers: {},
|
|
1927
|
+
langsmithHeaders: {}
|
|
1928
|
+
};
|
|
1929
|
+
}
|
|
1930
|
+
const carrier = {
|
|
1931
|
+
traceId: traceIdHex,
|
|
1932
|
+
spanId: dispatchSpanId,
|
|
1933
|
+
eventId: parentEventId,
|
|
1934
|
+
childEventId,
|
|
1935
|
+
name,
|
|
1936
|
+
...interaction.getConvoId() ? { convoId: interaction.getConvoId() } : {},
|
|
1937
|
+
...interaction.getUserId() ? { userId: interaction.getUserId() } : {}
|
|
1938
|
+
};
|
|
1939
|
+
return {
|
|
1940
|
+
childEventId,
|
|
1941
|
+
name,
|
|
1942
|
+
parentEventId,
|
|
1943
|
+
dispatchSpanId,
|
|
1944
|
+
carrier,
|
|
1945
|
+
headers: toHeaders(carrier),
|
|
1946
|
+
langsmithHeaders: toLangSmithHeaders(carrier)
|
|
1947
|
+
};
|
|
1948
|
+
}
|
|
1949
|
+
function carrierFirst(local, carried, field) {
|
|
1950
|
+
if (carried && local && local !== carried) {
|
|
1951
|
+
console.warn(
|
|
1952
|
+
`[raindrop] resumeSubagent: ignoring ${field}="${local}" in favor of the launcher's "${carried}" from the carrier; the launcher allocated it, and a child that substitutes its own breaks the link back to it.`
|
|
1953
|
+
);
|
|
1954
|
+
}
|
|
1955
|
+
return carried || local;
|
|
1956
|
+
}
|
|
1957
|
+
function isTraceCarrier(value) {
|
|
1958
|
+
const candidate = value;
|
|
1959
|
+
return typeof candidate.traceId === "string" && typeof candidate.spanId === "string" && typeof candidate.eventId === "string";
|
|
1960
|
+
}
|
|
1961
|
+
function readCarrier(carrierOrHeaders) {
|
|
1962
|
+
if (!carrierOrHeaders) return null;
|
|
1963
|
+
try {
|
|
1964
|
+
if (isTraceCarrier(carrierOrHeaders)) return carrierOrHeaders;
|
|
1965
|
+
return fromHeaders(carrierOrHeaders);
|
|
1966
|
+
} catch (error) {
|
|
1967
|
+
console.warn(
|
|
1968
|
+
`[raindrop] resumeSubagent: ignoring an unreadable hand-off carrier; the run reports as an unlinked event.`,
|
|
1969
|
+
error instanceof Error ? error.message : error
|
|
1970
|
+
);
|
|
1971
|
+
return null;
|
|
1972
|
+
}
|
|
1973
|
+
}
|
|
1974
|
+
function resolveSubagentResume(carrierOrHeaders, options = {}) {
|
|
1975
|
+
const parentStated = options.parent !== void 0;
|
|
1976
|
+
const parent = parentStated ? options.parent : readCarrier(carrierOrHeaders);
|
|
1977
|
+
if (!parentStated) warnUnresolvedCarrier(carrierOrHeaders, parent);
|
|
1978
|
+
const name = carrierFirst(options.name, parent == null ? void 0 : parent.name, "name") || DEFAULT_SUBAGENT_NAME;
|
|
1979
|
+
const eventId = carrierFirst(options.eventId, parent == null ? void 0 : parent.childEventId, "eventId") || randomUUID();
|
|
1980
|
+
const userId = carrierFirst(options.userId, parent == null ? void 0 : parent.userId, "userId") || "";
|
|
1981
|
+
const convoId = carrierFirst(options.convoId, parent == null ? void 0 : parent.convoId, "convoId");
|
|
1982
|
+
const link = parent ? {
|
|
1983
|
+
parentEventId: parent.eventId,
|
|
1984
|
+
...parent.spanId ? { parentSpanId: parent.spanId } : {},
|
|
1985
|
+
name
|
|
1986
|
+
} : null;
|
|
1987
|
+
return {
|
|
1988
|
+
parent,
|
|
1989
|
+
link,
|
|
1990
|
+
name,
|
|
1991
|
+
eventId,
|
|
1992
|
+
event: options.event || `subagent.${name}`,
|
|
1993
|
+
userId,
|
|
1994
|
+
...convoId ? { convoId } : {}
|
|
1995
|
+
};
|
|
1996
|
+
}
|
|
1997
|
+
function bindSubagentLink(link, owner) {
|
|
1998
|
+
if (!link) return void 0;
|
|
1999
|
+
return bindSpanAttributes(detachedChildMetadata(link), owner);
|
|
2000
|
+
}
|
|
2001
|
+
var LiveSubagentRun = class {
|
|
2002
|
+
constructor(params) {
|
|
2003
|
+
this.settled = false;
|
|
2004
|
+
this.interaction = params.interaction;
|
|
2005
|
+
this.eventId = params.eventId;
|
|
2006
|
+
this.name = params.name;
|
|
2007
|
+
this.convoId = params.convoId;
|
|
2008
|
+
this.parent = params.parent;
|
|
2009
|
+
this.frame = params.frame;
|
|
2010
|
+
this.frameOwner = params.frameOwner;
|
|
2011
|
+
}
|
|
2012
|
+
get linked() {
|
|
2013
|
+
return this.parent !== null;
|
|
2014
|
+
}
|
|
2015
|
+
async finish(result) {
|
|
2016
|
+
await this.close(result);
|
|
2017
|
+
}
|
|
2018
|
+
async fail(reason) {
|
|
2019
|
+
await this.abort(reason);
|
|
2020
|
+
}
|
|
2021
|
+
async cancel(reason) {
|
|
2022
|
+
const text = reason === void 0 ? "cancelled by caller" : reasonText(reason);
|
|
2023
|
+
const cancelled = cancelledTerminalAttributes();
|
|
2024
|
+
stampOwnSpan(cancelled, this.frame);
|
|
2025
|
+
await this.close({
|
|
2026
|
+
output: `Cancelled: ${text}`,
|
|
2027
|
+
// The caller's view of the child is its EVENT, not its spans, so the
|
|
2028
|
+
// marker has to be a property of the event as well.
|
|
2029
|
+
properties: { [HANDOFF_TERMINAL_PROPERTY_KEY]: HANDOFF_TERMINAL_CANCELLED }
|
|
2030
|
+
});
|
|
2031
|
+
}
|
|
2032
|
+
/**
|
|
2033
|
+
* Close the run with an abort reason, having first made sure the failure is
|
|
2034
|
+
* visible on a span.
|
|
2035
|
+
*
|
|
2036
|
+
* A failure has to leave an errored span behind or it is derived as finished.
|
|
2037
|
+
* Mark whatever is open; if nothing is and the child has not errored a span
|
|
2038
|
+
* already, record one — the killed-before-it-reached-the-model case, which is
|
|
2039
|
+
* much of what aborting is.
|
|
2040
|
+
*/
|
|
2041
|
+
async abort(reason) {
|
|
2042
|
+
var _a, _b, _c;
|
|
2043
|
+
const text = reasonText(reason);
|
|
2044
|
+
if (!this.settled && !failOwnSpan(reason, this.frame)) {
|
|
2045
|
+
if (!((_a = this.frame) == null ? void 0 : _a.sawErrorSpan())) {
|
|
2046
|
+
this.interaction.recordSubagentAbortSpan({
|
|
2047
|
+
reason,
|
|
2048
|
+
message: text,
|
|
2049
|
+
attributes: {
|
|
2050
|
+
[HANDOFF_ATTRIBUTE_SUFFIXES.name]: this.name,
|
|
2051
|
+
// The name explicitly, not only via the frame: an UNLINKED run has
|
|
2052
|
+
// no frame, and since the span is named for the operation
|
|
2053
|
+
// (`ai.subagent.failed`) rather than the sub-agent, this attribute
|
|
2054
|
+
// is the only thing left that says which sub-agent failed.
|
|
2055
|
+
...(_c = (_b = this.frame) == null ? void 0 : _b.attributes) != null ? _c : {}
|
|
2056
|
+
}
|
|
2057
|
+
});
|
|
2058
|
+
}
|
|
2059
|
+
}
|
|
2060
|
+
await this.close({ output: text ? `Aborted: ${text}` : "Aborted before producing a result." });
|
|
2061
|
+
}
|
|
2062
|
+
async close(result) {
|
|
2063
|
+
if (this.settled) return;
|
|
2064
|
+
this.settled = true;
|
|
2065
|
+
try {
|
|
2066
|
+
await this.interaction.finish({ ...result, eventId: this.eventId });
|
|
2067
|
+
} finally {
|
|
2068
|
+
unbindSpanAttributes(this.frame);
|
|
2069
|
+
this.frame = void 0;
|
|
2070
|
+
this.frameOwner = void 0;
|
|
2071
|
+
}
|
|
2072
|
+
}
|
|
2073
|
+
/**
|
|
2074
|
+
* Run `fn` and guarantee the run reports an outcome, mirroring the Python
|
|
2075
|
+
* SDK's `with rd.resume_subagent(...) as run:`.
|
|
2076
|
+
*
|
|
2077
|
+
* A run that leaves without reporting output is closed with its abort reason.
|
|
2078
|
+
* That is not cosmetic: an event is created only from a run with non-empty
|
|
2079
|
+
* output, so a child that dies silently produces no event at all and the
|
|
2080
|
+
* caller's launch stays `queued` forever — indistinguishable from a job that
|
|
2081
|
+
* never started.
|
|
2082
|
+
*/
|
|
2083
|
+
async use(fn) {
|
|
2084
|
+
try {
|
|
2085
|
+
const result = await fn(this);
|
|
2086
|
+
if (!this.settled) {
|
|
2087
|
+
console.warn(
|
|
2088
|
+
`[raindrop] sub-agent run ${this.eventId} (${this.name}) ended without reporting output; closing it with an abort reason. An event needs non-empty output to exist, so a silent child leaves its launcher showing "queued" forever \u2014 call finish({ output }), fail(reason) or cancel() before returning.`
|
|
2089
|
+
);
|
|
2090
|
+
await this.abortQuietly("sub-agent ended without reporting output");
|
|
2091
|
+
}
|
|
2092
|
+
return result;
|
|
2093
|
+
} catch (error) {
|
|
2094
|
+
await this.abortQuietly(error);
|
|
2095
|
+
throw error;
|
|
2096
|
+
}
|
|
2097
|
+
}
|
|
2098
|
+
/**
|
|
2099
|
+
* {@link abort} for the outcomes this class reports on the caller's behalf.
|
|
2100
|
+
*
|
|
2101
|
+
* `abort()` ends in `interaction.finish()`, which awaits the terminal event
|
|
2102
|
+
* POST and rejects when it fails. An explicit `fail()` may surface that — the
|
|
2103
|
+
* caller awaited it — but an implicit one must not: rejecting on the error
|
|
2104
|
+
* path replaces the caller's exception with a telemetry one, and rejecting on
|
|
2105
|
+
* the success path loses a result `fn` already produced.
|
|
2106
|
+
*/
|
|
2107
|
+
async abortQuietly(reason) {
|
|
2108
|
+
try {
|
|
2109
|
+
await this.abort(reason);
|
|
2110
|
+
} catch (error) {
|
|
2111
|
+
console.warn(
|
|
2112
|
+
`[raindrop] sub-agent run ${this.eventId} (${this.name}) could not report its outcome; the run itself is unaffected.`,
|
|
2113
|
+
error instanceof Error ? error.message : error
|
|
2114
|
+
);
|
|
2115
|
+
}
|
|
2116
|
+
}
|
|
2117
|
+
};
|
|
2118
|
+
|
|
2119
|
+
// src/tracing/liveInteraction.ts
|
|
2120
|
+
function getPropertiesFromContext(context6) {
|
|
1368
2121
|
const properties = {
|
|
1369
|
-
...
|
|
1370
|
-
...
|
|
1371
|
-
...
|
|
1372
|
-
...
|
|
1373
|
-
...
|
|
2122
|
+
...context6.userId && { user_id: context6.userId },
|
|
2123
|
+
...context6.convoId && { convo_id: context6.convoId },
|
|
2124
|
+
...context6.eventId && { event_id: context6.eventId },
|
|
2125
|
+
...context6.event && { event_name: context6.event },
|
|
2126
|
+
...context6.properties || {}
|
|
1374
2127
|
};
|
|
1375
|
-
if (
|
|
1376
|
-
properties.attachments = stringifyBounded(
|
|
2128
|
+
if (context6.attachments && context6.attachments.length > 0) {
|
|
2129
|
+
properties.attachments = stringifyBounded(context6.attachments);
|
|
1377
2130
|
}
|
|
1378
2131
|
return properties;
|
|
1379
2132
|
}
|
|
@@ -1393,12 +2146,12 @@ function serializeAssociationProperties(properties) {
|
|
|
1393
2146
|
function serializeSpanValue(value) {
|
|
1394
2147
|
return stringifyBounded(value);
|
|
1395
2148
|
}
|
|
1396
|
-
function getLocalDebuggerMetadata(
|
|
2149
|
+
function getLocalDebuggerMetadata(context6) {
|
|
1397
2150
|
return {
|
|
1398
|
-
...
|
|
1399
|
-
...
|
|
1400
|
-
...
|
|
1401
|
-
...
|
|
2151
|
+
...context6.eventId ? { eventId: context6.eventId } : {},
|
|
2152
|
+
...context6.event ? { eventName: context6.event } : {},
|
|
2153
|
+
...context6.userId ? { userId: context6.userId } : {},
|
|
2154
|
+
...context6.convoId ? { convoId: context6.convoId } : {}
|
|
1402
2155
|
};
|
|
1403
2156
|
}
|
|
1404
2157
|
var LiveToolSpan = class {
|
|
@@ -1410,7 +2163,7 @@ var LiveToolSpan = class {
|
|
|
1410
2163
|
}
|
|
1411
2164
|
spanIdHex() {
|
|
1412
2165
|
const ctx = this.span.spanContext();
|
|
1413
|
-
return (0,
|
|
2166
|
+
return (0, import_api3.isValidSpanId)(ctx.spanId) ? ctx.spanId : void 0;
|
|
1414
2167
|
}
|
|
1415
2168
|
setInput(input) {
|
|
1416
2169
|
this.span.setAttribute("traceloop.entity.input", serializeSpanValue(input));
|
|
@@ -1422,13 +2175,13 @@ var LiveToolSpan = class {
|
|
|
1422
2175
|
setError(error) {
|
|
1423
2176
|
this.hasError = true;
|
|
1424
2177
|
this.errorMessage = error instanceof Error ? error.message : String(error);
|
|
1425
|
-
this.span.setStatus({ code:
|
|
2178
|
+
this.span.setStatus({ code: import_api3.SpanStatusCode.ERROR, message: this.errorMessage });
|
|
1426
2179
|
this.span.recordException(error instanceof Error ? error : new Error(this.errorMessage));
|
|
1427
2180
|
}
|
|
1428
2181
|
end() {
|
|
1429
2182
|
var _a;
|
|
1430
2183
|
if (!this.hasError) {
|
|
1431
|
-
this.span.setStatus({ code:
|
|
2184
|
+
this.span.setStatus({ code: import_api3.SpanStatusCode.OK });
|
|
1432
2185
|
}
|
|
1433
2186
|
this.span.end();
|
|
1434
2187
|
(_a = this.emitLiveEvent) == null ? void 0 : _a.call(this, {
|
|
@@ -1499,10 +2252,10 @@ var DirectToolSpan = class {
|
|
|
1499
2252
|
}
|
|
1500
2253
|
};
|
|
1501
2254
|
var LiveInteraction = class {
|
|
1502
|
-
constructor(
|
|
1503
|
-
this.context =
|
|
2255
|
+
constructor(context6, traceId, analytics, directShipper, routing) {
|
|
2256
|
+
this.context = context6;
|
|
1504
2257
|
this.analytics = analytics;
|
|
1505
|
-
this.tracer =
|
|
2258
|
+
this.tracer = import_api3.trace.getTracer("traceloop.tracer");
|
|
1506
2259
|
this.traceId = traceId;
|
|
1507
2260
|
this.directShipper = directShipper;
|
|
1508
2261
|
this.routing = routing;
|
|
@@ -1537,7 +2290,7 @@ var LiveInteraction = class {
|
|
|
1537
2290
|
this.traceId = explicitTraceId;
|
|
1538
2291
|
return explicitTraceId;
|
|
1539
2292
|
}
|
|
1540
|
-
const activeSpan =
|
|
2293
|
+
const activeSpan = import_api3.trace.getSpan(import_api3.context.active());
|
|
1541
2294
|
const activeTraceId = activeSpan == null ? void 0 : activeSpan.spanContext().traceId;
|
|
1542
2295
|
if (activeTraceId) {
|
|
1543
2296
|
this.traceId = activeTraceId;
|
|
@@ -1580,17 +2333,17 @@ var LiveInteraction = class {
|
|
|
1580
2333
|
const spanIdB64 = base64Encode2(randomBytes2(8));
|
|
1581
2334
|
const startTimeMs = Date.now();
|
|
1582
2335
|
const spanContext = {
|
|
1583
|
-
traceId:
|
|
1584
|
-
spanId:
|
|
1585
|
-
traceFlags:
|
|
2336
|
+
traceId: base64ToHex2(traceIdB64),
|
|
2337
|
+
spanId: base64ToHex2(spanIdB64),
|
|
2338
|
+
traceFlags: import_api3.TraceFlags.SAMPLED
|
|
1586
2339
|
};
|
|
1587
|
-
const wrappedContext =
|
|
1588
|
-
|
|
1589
|
-
|
|
2340
|
+
const wrappedContext = import_api3.trace.setSpan(
|
|
2341
|
+
import_api3.context.active(),
|
|
2342
|
+
import_api3.trace.wrapSpanContext(spanContext)
|
|
1590
2343
|
);
|
|
1591
2344
|
const invoke = () => this.routing ? withRoutingContext(this.routing, () => fn.apply(thisArg, args)) : fn.apply(thisArg, args);
|
|
1592
2345
|
try {
|
|
1593
|
-
const result = await
|
|
2346
|
+
const result = await import_api3.context.with(wrappedContext, invoke);
|
|
1594
2347
|
const endTimeMs = Date.now();
|
|
1595
2348
|
this.directShipper.sendSpan({
|
|
1596
2349
|
name: taskName,
|
|
@@ -1625,7 +2378,7 @@ var LiveInteraction = class {
|
|
|
1625
2378
|
}
|
|
1626
2379
|
}
|
|
1627
2380
|
const wrappedFn = (...fnArgs) => {
|
|
1628
|
-
const activeSpan =
|
|
2381
|
+
const activeSpan = import_api3.trace.getSpan(import_api3.context.active());
|
|
1629
2382
|
const activeTraceId = activeSpan == null ? void 0 : activeSpan.spanContext().traceId;
|
|
1630
2383
|
if (activeTraceId) {
|
|
1631
2384
|
this.traceId = activeTraceId;
|
|
@@ -1675,19 +2428,19 @@ var LiveInteraction = class {
|
|
|
1675
2428
|
metadata: params.inputParameters ? { args: params.inputParameters } : void 0
|
|
1676
2429
|
});
|
|
1677
2430
|
const spanContext = {
|
|
1678
|
-
traceId:
|
|
1679
|
-
spanId:
|
|
1680
|
-
traceFlags:
|
|
2431
|
+
traceId: base64ToHex2(traceIdB64),
|
|
2432
|
+
spanId: base64ToHex2(spanIdB64),
|
|
2433
|
+
traceFlags: import_api3.TraceFlags.SAMPLED
|
|
1681
2434
|
};
|
|
1682
|
-
const wrappedContext =
|
|
1683
|
-
|
|
1684
|
-
|
|
2435
|
+
const wrappedContext = import_api3.trace.setSpan(
|
|
2436
|
+
import_api3.context.active(),
|
|
2437
|
+
import_api3.trace.wrapSpanContext(spanContext)
|
|
1685
2438
|
);
|
|
1686
2439
|
const invoke = () => this.routing ? withRoutingContext(this.routing, () => fn.apply(thisArg, args)) : fn.apply(thisArg, args);
|
|
1687
2440
|
let result;
|
|
1688
2441
|
let error;
|
|
1689
2442
|
try {
|
|
1690
|
-
result = await
|
|
2443
|
+
result = await import_api3.context.with(wrappedContext, invoke);
|
|
1691
2444
|
} catch (err) {
|
|
1692
2445
|
error = err instanceof Error ? err.message : String(err);
|
|
1693
2446
|
const endTimeMs2 = Date.now();
|
|
@@ -1752,9 +2505,9 @@ var LiveInteraction = class {
|
|
|
1752
2505
|
const inputParams = params.inputParameters ? [params.inputParameters] : void 0;
|
|
1753
2506
|
const emitLive = (event) => this.emitLiveEvent(event);
|
|
1754
2507
|
const wrapped = async (...wrappedArgs) => {
|
|
1755
|
-
const activeSpan =
|
|
2508
|
+
const activeSpan = import_api3.trace.getSpan(import_api3.context.active());
|
|
1756
2509
|
const ctx = activeSpan == null ? void 0 : activeSpan.spanContext();
|
|
1757
|
-
const liveSpanId = ctx && (0,
|
|
2510
|
+
const liveSpanId = ctx && (0, import_api3.isValidSpanId)(ctx.spanId) ? ctx.spanId : void 0;
|
|
1758
2511
|
if (activeSpan) {
|
|
1759
2512
|
this.stampRouting(activeSpan);
|
|
1760
2513
|
}
|
|
@@ -1862,7 +2615,7 @@ var LiveInteraction = class {
|
|
|
1862
2615
|
console.log(`[raindrop] startToolSpan: started tool span "${name}"`);
|
|
1863
2616
|
}
|
|
1864
2617
|
const startSpanCtx = span.spanContext();
|
|
1865
|
-
const startSpanIdHex = (0,
|
|
2618
|
+
const startSpanIdHex = (0, import_api3.isValidSpanId)(startSpanCtx.spanId) ? startSpanCtx.spanId : void 0;
|
|
1866
2619
|
this.emitLiveEvent({
|
|
1867
2620
|
type: "tool_start",
|
|
1868
2621
|
spanId: startSpanIdHex,
|
|
@@ -1955,10 +2708,151 @@ var LiveInteraction = class {
|
|
|
1955
2708
|
getEventId() {
|
|
1956
2709
|
return this.context.eventId;
|
|
1957
2710
|
}
|
|
2711
|
+
getUserId() {
|
|
2712
|
+
return this.context.userId;
|
|
2713
|
+
}
|
|
2714
|
+
getConvoId() {
|
|
2715
|
+
return this.context.convoId;
|
|
2716
|
+
}
|
|
2717
|
+
/**
|
|
2718
|
+
* Bind this turn's tool-call event opt-in, once.
|
|
2719
|
+
*
|
|
2720
|
+
* Owned by the interaction rather than by the execution context: the frame
|
|
2721
|
+
* lives exactly as long as the turn does (removed by `finish()`, and dead once
|
|
2722
|
+
* this interaction is collected), instead of outliving it on a context the
|
|
2723
|
+
* host may reuse for unrelated work.
|
|
2724
|
+
*/
|
|
2725
|
+
bindToolEventsOptIn(attributes) {
|
|
2726
|
+
if (this.toolEventsFrame) return;
|
|
2727
|
+
this.toolEventsFrame = bindSpanAttributes(attributes, this);
|
|
2728
|
+
}
|
|
2729
|
+
subagent(options) {
|
|
2730
|
+
return recordSubagentDispatch(this, options);
|
|
2731
|
+
}
|
|
2732
|
+
/**
|
|
2733
|
+
* Record the tool span a detached dispatch is written on.
|
|
2734
|
+
*
|
|
2735
|
+
* Distinct from {@link startToolSpan} in the two ways the hand-off needs:
|
|
2736
|
+
* the contract's keys are set as RAW span attributes (under the
|
|
2737
|
+
* `traceloop.association.properties.` prefix the backend's reader cannot see
|
|
2738
|
+
* them), and the caller needs the span's ids to build the carrier.
|
|
2739
|
+
*
|
|
2740
|
+
* @internal
|
|
2741
|
+
*/
|
|
2742
|
+
recordDispatchSpan(params) {
|
|
2743
|
+
var _a;
|
|
2744
|
+
const properties = {
|
|
2745
|
+
...getPropertiesFromContext(this.context),
|
|
2746
|
+
...(_a = params.properties) != null ? _a : {}
|
|
2747
|
+
};
|
|
2748
|
+
const input = params.input !== void 0 ? serializeSpanValue(params.input) : void 0;
|
|
2749
|
+
const output = serializeSpanValue(params.output);
|
|
2750
|
+
if (this.directShipper) {
|
|
2751
|
+
const activeContext = getActiveTraceContext();
|
|
2752
|
+
const traceIdB64 = this.ensureTraceId(activeContext.traceIdB64);
|
|
2753
|
+
const spanIdB64 = base64Encode2(randomBytes2(8));
|
|
2754
|
+
const timeMs = Date.now();
|
|
2755
|
+
this.directShipper.sendToolSpan({
|
|
2756
|
+
name: params.name,
|
|
2757
|
+
spanId: spanIdB64,
|
|
2758
|
+
input,
|
|
2759
|
+
output,
|
|
2760
|
+
durationMs: 0,
|
|
2761
|
+
startTimeMs: timeMs,
|
|
2762
|
+
endTimeMs: timeMs,
|
|
2763
|
+
properties,
|
|
2764
|
+
traceId: traceIdB64,
|
|
2765
|
+
parentSpanId: activeContext.parentSpanIdB64,
|
|
2766
|
+
attributes: params.attributes
|
|
2767
|
+
});
|
|
2768
|
+
this.emitLiveEvent({
|
|
2769
|
+
traceId: traceIdB64,
|
|
2770
|
+
spanId: spanIdB64,
|
|
2771
|
+
type: "tool_result",
|
|
2772
|
+
content: params.name,
|
|
2773
|
+
timestamp: timeMs,
|
|
2774
|
+
metadata: { result: params.output }
|
|
2775
|
+
});
|
|
2776
|
+
return { traceIdHex: base64ToHex2(traceIdB64), spanIdHex: base64ToHex2(spanIdB64) };
|
|
2777
|
+
}
|
|
2778
|
+
const span = this.tracer.startSpan(params.name);
|
|
2779
|
+
setAssociationProperties(span, properties);
|
|
2780
|
+
span.setAttribute("traceloop.span.kind", "tool");
|
|
2781
|
+
this.stampRouting(span);
|
|
2782
|
+
for (const [key, value] of Object.entries(params.attributes)) {
|
|
2783
|
+
span.setAttribute(key, value);
|
|
2784
|
+
}
|
|
2785
|
+
if (input !== void 0) {
|
|
2786
|
+
span.setAttribute("traceloop.entity.input", input);
|
|
2787
|
+
}
|
|
2788
|
+
span.setAttribute("traceloop.entity.output", output);
|
|
2789
|
+
span.setStatus({ code: import_api3.SpanStatusCode.OK });
|
|
2790
|
+
const spanContext = span.spanContext();
|
|
2791
|
+
span.end();
|
|
2792
|
+
this.emitLiveEvent({
|
|
2793
|
+
spanId: (0, import_api3.isValidSpanId)(spanContext.spanId) ? spanContext.spanId : void 0,
|
|
2794
|
+
type: "tool_result",
|
|
2795
|
+
content: params.name,
|
|
2796
|
+
timestamp: Date.now(),
|
|
2797
|
+
metadata: { result: params.output }
|
|
2798
|
+
});
|
|
2799
|
+
return {
|
|
2800
|
+
traceIdHex: (0, import_api3.isValidTraceId)(spanContext.traceId) ? spanContext.traceId : void 0,
|
|
2801
|
+
spanIdHex: (0, import_api3.isValidSpanId)(spanContext.spanId) ? spanContext.spanId : void 0
|
|
2802
|
+
};
|
|
2803
|
+
}
|
|
2804
|
+
/**
|
|
2805
|
+
* Record the errored span a detached sub-agent's failure needs when nothing
|
|
2806
|
+
* else is open.
|
|
2807
|
+
*
|
|
2808
|
+
* Frequently the child's ONLY span, so it carries the full reverse reference:
|
|
2809
|
+
* anything reading it alone still knows which launch it belongs to. Those
|
|
2810
|
+
* attributes come from the run's own frame rather than the ambient stack,
|
|
2811
|
+
* because `fail()` is often called from a different task than the one that
|
|
2812
|
+
* opened the run and this is the span that can least afford to lose the link.
|
|
2813
|
+
*
|
|
2814
|
+
* @internal
|
|
2815
|
+
*/
|
|
2816
|
+
recordSubagentAbortSpan(params) {
|
|
2817
|
+
const { reason, message, attributes } = params;
|
|
2818
|
+
const properties = getPropertiesFromContext(this.context);
|
|
2819
|
+
if (this.directShipper) {
|
|
2820
|
+
const activeContext = getActiveTraceContext();
|
|
2821
|
+
const timeMs = Date.now();
|
|
2822
|
+
this.directShipper.sendSpan({
|
|
2823
|
+
name: SUBAGENT_ABORT_SPAN_NAME,
|
|
2824
|
+
// Not "tool": the run died, it did not call anything. `ai.operationId`
|
|
2825
|
+
// below is what keeps the span (see the attribute's docs in core).
|
|
2826
|
+
spanKind: "task",
|
|
2827
|
+
spanId: base64Encode2(randomBytes2(8)),
|
|
2828
|
+
durationMs: 0,
|
|
2829
|
+
startTimeMs: timeMs,
|
|
2830
|
+
endTimeMs: timeMs,
|
|
2831
|
+
error: message,
|
|
2832
|
+
properties,
|
|
2833
|
+
traceId: this.ensureTraceId(activeContext.traceIdB64),
|
|
2834
|
+
parentSpanId: activeContext.parentSpanIdB64,
|
|
2835
|
+
attributes: { ...attributes, [OPERATION_ID_ATTRIBUTE]: SUBAGENT_ABORT_OPERATION_ID }
|
|
2836
|
+
});
|
|
2837
|
+
return;
|
|
2838
|
+
}
|
|
2839
|
+
const span = this.tracer.startSpan(SUBAGENT_ABORT_SPAN_NAME);
|
|
2840
|
+
span.setAttribute(OPERATION_ID_ATTRIBUTE, SUBAGENT_ABORT_OPERATION_ID);
|
|
2841
|
+
setAssociationProperties(span, properties);
|
|
2842
|
+
this.stampRouting(span);
|
|
2843
|
+
for (const [key, value] of Object.entries(attributes)) {
|
|
2844
|
+
span.setAttribute(key, value);
|
|
2845
|
+
}
|
|
2846
|
+
span.setStatus({ code: import_api3.SpanStatusCode.ERROR, message });
|
|
2847
|
+
span.recordException(reason instanceof Error ? reason : new Error(message));
|
|
2848
|
+
span.end();
|
|
2849
|
+
}
|
|
1958
2850
|
async finish(resultEvent) {
|
|
1959
2851
|
var _a, _b, _c, _d;
|
|
1960
2852
|
unbindRoutingContext(this.boundContext);
|
|
1961
2853
|
this.boundContext = void 0;
|
|
2854
|
+
unbindSpanAttributes(this.toolEventsFrame);
|
|
2855
|
+
this.toolEventsFrame = void 0;
|
|
1962
2856
|
if (!this.traceId) {
|
|
1963
2857
|
this.resolveLiveTraceId();
|
|
1964
2858
|
}
|
|
@@ -2068,10 +2962,10 @@ var LiveInteraction = class {
|
|
|
2068
2962
|
}
|
|
2069
2963
|
if (error) {
|
|
2070
2964
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2071
|
-
span.setStatus({ code:
|
|
2965
|
+
span.setStatus({ code: import_api3.SpanStatusCode.ERROR, message: errorMessage });
|
|
2072
2966
|
span.recordException(error instanceof Error ? error : new Error(errorMessage));
|
|
2073
2967
|
} else {
|
|
2074
|
-
span.setStatus({ code:
|
|
2968
|
+
span.setStatus({ code: import_api3.SpanStatusCode.OK });
|
|
2075
2969
|
}
|
|
2076
2970
|
span.end(endTimeMs);
|
|
2077
2971
|
if ((_c = this.analytics) == null ? void 0 : _c.debugLogs) {
|
|
@@ -2083,7 +2977,7 @@ var LiveInteraction = class {
|
|
|
2083
2977
|
});
|
|
2084
2978
|
}
|
|
2085
2979
|
const trackToolCtx = span.spanContext();
|
|
2086
|
-
const trackToolSpanIdHex = (0,
|
|
2980
|
+
const trackToolSpanIdHex = (0, import_api3.isValidSpanId)(trackToolCtx.spanId) ? trackToolCtx.spanId : void 0;
|
|
2087
2981
|
this.emitLiveEvent({
|
|
2088
2982
|
type: "tool_result",
|
|
2089
2983
|
spanId: trackToolSpanIdHex,
|
|
@@ -2099,11 +2993,11 @@ var LiveInteraction = class {
|
|
|
2099
2993
|
};
|
|
2100
2994
|
|
|
2101
2995
|
// src/tracing/liveTracer.ts
|
|
2102
|
-
var
|
|
2996
|
+
var import_api4 = require("@opentelemetry/api");
|
|
2103
2997
|
var traceloop2 = __toESM(require("@traceloop/node-server-sdk"));
|
|
2104
2998
|
var LiveTracer = class {
|
|
2105
2999
|
constructor(globalProperties, directShipper, routing) {
|
|
2106
|
-
this.tracer =
|
|
3000
|
+
this.tracer = import_api4.trace.getTracer("traceloop.tracer");
|
|
2107
3001
|
this.globalProperties = globalProperties || {};
|
|
2108
3002
|
this.directShipper = directShipper;
|
|
2109
3003
|
this.routing = routing;
|
|
@@ -2115,7 +3009,7 @@ var LiveTracer = class {
|
|
|
2115
3009
|
}
|
|
2116
3010
|
emitLiveEvent(event) {
|
|
2117
3011
|
var _a, _b;
|
|
2118
|
-
const activeSpan =
|
|
3012
|
+
const activeSpan = import_api4.trace.getSpan(import_api4.context.active());
|
|
2119
3013
|
const activeTraceId = activeSpan == null ? void 0 : activeSpan.spanContext().traceId;
|
|
2120
3014
|
const active = getActiveTraceContext();
|
|
2121
3015
|
const traceId = (_b = (_a = event.traceId) != null ? _a : activeTraceId) != null ? _b : active.traceIdB64;
|
|
@@ -2135,7 +3029,7 @@ var LiveTracer = class {
|
|
|
2135
3029
|
};
|
|
2136
3030
|
const inputParameters = typeof params === "string" ? void 0 : params.inputParameters;
|
|
2137
3031
|
const wrappedFn = (...fnArgs) => {
|
|
2138
|
-
const activeSpan =
|
|
3032
|
+
const activeSpan = import_api4.trace.getSpan(import_api4.context.active());
|
|
2139
3033
|
if (activeSpan) {
|
|
2140
3034
|
this.stampRouting(activeSpan);
|
|
2141
3035
|
}
|
|
@@ -2230,15 +3124,15 @@ var LiveTracer = class {
|
|
|
2230
3124
|
}
|
|
2231
3125
|
if (error) {
|
|
2232
3126
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
2233
|
-
span.setStatus({ code:
|
|
3127
|
+
span.setStatus({ code: import_api4.SpanStatusCode.ERROR, message: errorMessage });
|
|
2234
3128
|
span.recordException(error instanceof Error ? error : new Error(errorMessage));
|
|
2235
3129
|
} else {
|
|
2236
|
-
span.setStatus({ code:
|
|
3130
|
+
span.setStatus({ code: import_api4.SpanStatusCode.OK });
|
|
2237
3131
|
}
|
|
2238
3132
|
span.end(endTimeMs);
|
|
2239
3133
|
const ctx = span.spanContext();
|
|
2240
|
-
const traceId = ctx.traceId || ((_b =
|
|
2241
|
-
const spanIdHex = (0,
|
|
3134
|
+
const traceId = ctx.traceId || ((_b = import_api4.trace.getSpan(import_api4.context.active())) == null ? void 0 : _b.spanContext().traceId);
|
|
3135
|
+
const spanIdHex = (0, import_api4.isValidSpanId)(ctx.spanId) ? ctx.spanId : void 0;
|
|
2242
3136
|
if (traceId) {
|
|
2243
3137
|
this.emitLiveEvent({
|
|
2244
3138
|
traceId,
|
|
@@ -2530,7 +3424,7 @@ try {
|
|
|
2530
3424
|
e instanceof Error ? e.message : e
|
|
2531
3425
|
);
|
|
2532
3426
|
span.setStatus({
|
|
2533
|
-
code:
|
|
3427
|
+
code: import_api5.SpanStatusCode.ERROR,
|
|
2534
3428
|
message: e instanceof Error ? e.message : String(e)
|
|
2535
3429
|
});
|
|
2536
3430
|
span.end();
|
|
@@ -2562,7 +3456,7 @@ try {
|
|
|
2562
3456
|
);
|
|
2563
3457
|
if (!spanEnded) {
|
|
2564
3458
|
span.setStatus({
|
|
2565
|
-
code:
|
|
3459
|
+
code: import_api5.SpanStatusCode.ERROR,
|
|
2566
3460
|
message: e instanceof Error ? e.message : String(e)
|
|
2567
3461
|
});
|
|
2568
3462
|
span.end();
|
|
@@ -2576,7 +3470,7 @@ try {
|
|
|
2576
3470
|
} catch (error) {
|
|
2577
3471
|
if (!spanEnded) {
|
|
2578
3472
|
const msg = error instanceof Error ? error.message : String(error);
|
|
2579
|
-
span.setStatus({ code:
|
|
3473
|
+
span.setStatus({ code: import_api5.SpanStatusCode.ERROR, message: msg });
|
|
2580
3474
|
span.recordException(error);
|
|
2581
3475
|
span.end();
|
|
2582
3476
|
spanEnded = true;
|
|
@@ -2599,7 +3493,7 @@ try {
|
|
|
2599
3493
|
return result;
|
|
2600
3494
|
}).catch((error) => {
|
|
2601
3495
|
span.setStatus({
|
|
2602
|
-
code:
|
|
3496
|
+
code: import_api5.SpanStatusCode.ERROR,
|
|
2603
3497
|
message: error.message
|
|
2604
3498
|
});
|
|
2605
3499
|
span.recordException(error);
|
|
@@ -2662,7 +3556,7 @@ function patchBedrockStreamingBug(inst) {
|
|
|
2662
3556
|
} catch (error) {
|
|
2663
3557
|
if (!spanEnded) {
|
|
2664
3558
|
const msg = error instanceof Error ? error.message : String(error);
|
|
2665
|
-
span.setStatus({ code:
|
|
3559
|
+
span.setStatus({ code: import_api5.SpanStatusCode.ERROR, message: msg });
|
|
2666
3560
|
span.recordException(error);
|
|
2667
3561
|
span.end();
|
|
2668
3562
|
spanEnded = true;
|
|
@@ -2685,7 +3579,7 @@ function patchBedrockStreamingBug(inst) {
|
|
|
2685
3579
|
return result;
|
|
2686
3580
|
}).catch((error) => {
|
|
2687
3581
|
span.setStatus({
|
|
2688
|
-
code:
|
|
3582
|
+
code: import_api5.SpanStatusCode.ERROR,
|
|
2689
3583
|
message: error.message
|
|
2690
3584
|
});
|
|
2691
3585
|
span.recordException(error);
|
|
@@ -2767,7 +3661,7 @@ function createManualInstrumentations(instrumentModules) {
|
|
|
2767
3661
|
}
|
|
2768
3662
|
function getCurrentTraceId() {
|
|
2769
3663
|
var _a;
|
|
2770
|
-
return (_a =
|
|
3664
|
+
return (_a = import_api5.trace.getSpan(import_api5.context.active())) == null ? void 0 : _a.spanContext().traceId;
|
|
2771
3665
|
}
|
|
2772
3666
|
var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
2773
3667
|
var _a;
|
|
@@ -2960,6 +3854,72 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
|
2960
3854
|
} catch (e) {
|
|
2961
3855
|
}
|
|
2962
3856
|
}) : void 0;
|
|
3857
|
+
const beginInteraction = (traceContext) => {
|
|
3858
|
+
var _a2;
|
|
3859
|
+
if (!traceContext.eventId) {
|
|
3860
|
+
traceContext.eventId = crypto.randomUUID();
|
|
3861
|
+
}
|
|
3862
|
+
const traceId = getCurrentTraceId();
|
|
3863
|
+
const interaction = new LiveInteraction(
|
|
3864
|
+
traceContext,
|
|
3865
|
+
traceId,
|
|
3866
|
+
analytics,
|
|
3867
|
+
directShipper,
|
|
3868
|
+
{ projectId, authHint }
|
|
3869
|
+
);
|
|
3870
|
+
const bound = bindRoutingContext({ projectId, authHint }, interaction);
|
|
3871
|
+
interaction.setBoundContext(bound);
|
|
3872
|
+
try {
|
|
3873
|
+
analytics._trackAiPartial({
|
|
3874
|
+
...traceContext,
|
|
3875
|
+
properties: {
|
|
3876
|
+
...(_a2 = traceContext.properties) != null ? _a2 : {},
|
|
3877
|
+
...interaction.getTraceId() ? { trace_id: interaction.getTraceId() } : {}
|
|
3878
|
+
}
|
|
3879
|
+
});
|
|
3880
|
+
if (interaction.getTraceId()) {
|
|
3881
|
+
activeInteractions.set(interaction.getTraceId(), interaction);
|
|
3882
|
+
}
|
|
3883
|
+
activeInteractionsByEventId.set(traceContext.eventId, interaction);
|
|
3884
|
+
} catch (error) {
|
|
3885
|
+
unbindRoutingContext(bound);
|
|
3886
|
+
throw error;
|
|
3887
|
+
}
|
|
3888
|
+
return interaction;
|
|
3889
|
+
};
|
|
3890
|
+
const openSubagentRun = (carrierOrHeaders, options2) => {
|
|
3891
|
+
const resolved = resolveSubagentResume(carrierOrHeaders, options2);
|
|
3892
|
+
if (!resolved.parent && isDebug) {
|
|
3893
|
+
console.log(
|
|
3894
|
+
`[raindrop] resumeSubagent(${resolved.name}): no hand-off carrier on the request; reporting as an unlinked event ${resolved.eventId}.`
|
|
3895
|
+
);
|
|
3896
|
+
}
|
|
3897
|
+
const frameOwner = { subagentEventId: resolved.eventId };
|
|
3898
|
+
const frame = bindSubagentLink(resolved.link, frameOwner);
|
|
3899
|
+
let interaction;
|
|
3900
|
+
try {
|
|
3901
|
+
interaction = beginInteraction({
|
|
3902
|
+
eventId: resolved.eventId,
|
|
3903
|
+
event: resolved.event,
|
|
3904
|
+
userId: resolved.userId,
|
|
3905
|
+
...resolved.convoId ? { convoId: resolved.convoId } : {},
|
|
3906
|
+
...options2.input !== void 0 ? { input: options2.input } : {},
|
|
3907
|
+
...options2.model !== void 0 ? { model: options2.model } : {},
|
|
3908
|
+
...options2.properties ? { properties: options2.properties } : {}
|
|
3909
|
+
});
|
|
3910
|
+
} catch (error) {
|
|
3911
|
+
unbindSpanAttributes(frame);
|
|
3912
|
+
throw error;
|
|
3913
|
+
}
|
|
3914
|
+
return new LiveSubagentRun({
|
|
3915
|
+
interaction,
|
|
3916
|
+
eventId: resolved.eventId,
|
|
3917
|
+
name: resolved.name,
|
|
3918
|
+
...resolved.convoId ? { convoId: resolved.convoId } : {},
|
|
3919
|
+
parent: resolved.link,
|
|
3920
|
+
...frame ? { frame, frameOwner } : {}
|
|
3921
|
+
});
|
|
3922
|
+
};
|
|
2963
3923
|
return {
|
|
2964
3924
|
/**
|
|
2965
3925
|
* Returns instrumentation instances for your NodeSDK.
|
|
@@ -3069,37 +4029,13 @@ var tracing = (analytics, apiUrl, writeKey, options, isDebug = false) => {
|
|
|
3069
4029
|
);
|
|
3070
4030
|
},
|
|
3071
4031
|
begin(traceContext) {
|
|
3072
|
-
|
|
3073
|
-
|
|
3074
|
-
|
|
3075
|
-
|
|
3076
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
traceId,
|
|
3080
|
-
analytics,
|
|
3081
|
-
directShipper,
|
|
3082
|
-
{ projectId, authHint }
|
|
3083
|
-
);
|
|
3084
|
-
const bound = bindRoutingContext({ projectId, authHint }, interaction);
|
|
3085
|
-
interaction.setBoundContext(bound);
|
|
3086
|
-
try {
|
|
3087
|
-
analytics._trackAiPartial({
|
|
3088
|
-
...traceContext,
|
|
3089
|
-
properties: {
|
|
3090
|
-
...(_a2 = traceContext.properties) != null ? _a2 : {},
|
|
3091
|
-
...interaction.getTraceId() ? { trace_id: interaction.getTraceId() } : {}
|
|
3092
|
-
}
|
|
3093
|
-
});
|
|
3094
|
-
if (interaction.getTraceId()) {
|
|
3095
|
-
activeInteractions.set(interaction.getTraceId(), interaction);
|
|
3096
|
-
}
|
|
3097
|
-
activeInteractionsByEventId.set(traceContext.eventId, interaction);
|
|
3098
|
-
} catch (error) {
|
|
3099
|
-
unbindRoutingContext(bound);
|
|
3100
|
-
throw error;
|
|
3101
|
-
}
|
|
3102
|
-
return interaction;
|
|
4032
|
+
return beginInteraction(traceContext);
|
|
4033
|
+
},
|
|
4034
|
+
resumeSubagent(carrierOrHeaders, options2 = {}) {
|
|
4035
|
+
return openSubagentRun(carrierOrHeaders, options2);
|
|
4036
|
+
},
|
|
4037
|
+
withSubagentRun(carrierOrHeaders, fn, options2 = {}) {
|
|
4038
|
+
return openSubagentRun(carrierOrHeaders, options2).use(fn);
|
|
3103
4039
|
},
|
|
3104
4040
|
getActiveInteraction(eventId) {
|
|
3105
4041
|
const interactionByEventId = activeInteractionsByEventId.get(eventId);
|