@raindrop-ai/ai-sdk 0.2.0 → 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 +114 -0
- package/dist/{chunk-RBVZVH46.mjs → chunk-GMY7QXIQ.mjs} +1205 -117
- package/dist/{index-BUWOlY-2.d.mts → index-BqXHiknB.d.mts} +532 -1
- package/dist/{index-BUWOlY-2.d.ts → index-BqXHiknB.d.ts} +532 -1
- package/dist/index.browser.d.mts +532 -1
- package/dist/index.browser.d.ts +532 -1
- package/dist/index.browser.js +1217 -116
- package/dist/index.browser.mjs +1205 -117
- package/dist/index.node.d.mts +1 -1
- package/dist/index.node.d.ts +1 -1
- package/dist/index.node.js +1217 -116
- package/dist/index.node.mjs +1 -1
- package/dist/index.workers.d.mts +1 -1
- package/dist/index.workers.d.ts +1 -1
- package/dist/index.workers.js +1217 -116
- package/dist/index.workers.mjs +1 -1
- package/package.json +2 -2
package/dist/index.node.js
CHANGED
|
@@ -4,7 +4,7 @@ var async_hooks = require('async_hooks');
|
|
|
4
4
|
|
|
5
5
|
// src/index.node.ts
|
|
6
6
|
|
|
7
|
-
// ../core/dist/chunk-
|
|
7
|
+
// ../core/dist/chunk-YUIXRQWN.js
|
|
8
8
|
function normalizeFeatureFlags(input) {
|
|
9
9
|
if (Array.isArray(input)) {
|
|
10
10
|
return Object.fromEntries(input.map((name) => [name, "true"]));
|
|
@@ -67,6 +67,311 @@ function base64Encode(bytes) {
|
|
|
67
67
|
}
|
|
68
68
|
return out;
|
|
69
69
|
}
|
|
70
|
+
function base64ToHex(value) {
|
|
71
|
+
if (!value) return "";
|
|
72
|
+
const maybeBuffer = globalThis.Buffer;
|
|
73
|
+
if (maybeBuffer) {
|
|
74
|
+
return maybeBuffer.from(value, "base64").toString("hex");
|
|
75
|
+
}
|
|
76
|
+
const atobFn = globalThis.atob;
|
|
77
|
+
if (typeof atobFn !== "function") return "";
|
|
78
|
+
try {
|
|
79
|
+
const binary = atobFn(value);
|
|
80
|
+
let hex = "";
|
|
81
|
+
for (let i = 0; i < binary.length; i++) {
|
|
82
|
+
hex += (binary.charCodeAt(i) & 255).toString(16).padStart(2, "0");
|
|
83
|
+
}
|
|
84
|
+
return hex;
|
|
85
|
+
} catch (e) {
|
|
86
|
+
return "";
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
var HANDOFF_ATTRIBUTE_SUFFIXES = {
|
|
90
|
+
mode: "raindrop.handoff.mode",
|
|
91
|
+
childEventId: "raindrop.handoff.childEventId",
|
|
92
|
+
parentEventId: "raindrop.handoff.parentEventId",
|
|
93
|
+
parentSpanId: "raindrop.handoff.parentSpanId",
|
|
94
|
+
name: "raindrop.handoff.name",
|
|
95
|
+
terminal: "raindrop.handoff.terminal",
|
|
96
|
+
agentRole: "raindrop.agent.role"
|
|
97
|
+
};
|
|
98
|
+
var HANDOFF_ATTRIBUTE_PREFIXES = [
|
|
99
|
+
"ai.telemetry.metadata.",
|
|
100
|
+
"ai.settings.context.",
|
|
101
|
+
""
|
|
102
|
+
];
|
|
103
|
+
var AI_SDK_METADATA_PREFIX = "ai.telemetry.metadata.";
|
|
104
|
+
var DETACHED_MODE = "detached";
|
|
105
|
+
var SUBAGENT_AGENT_ROLE = "subagent";
|
|
106
|
+
var HANDOFF_TERMINAL_CANCELLED = "cancelled";
|
|
107
|
+
var TOOL_EVENTS_SUFFIX = "raindrop.toolEvents";
|
|
108
|
+
var TOOL_EVENTS_ALLOW = "allow";
|
|
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
|
+
function readHandoffField(metadata, suffix) {
|
|
153
|
+
for (const prefix of HANDOFF_ATTRIBUTE_PREFIXES) {
|
|
154
|
+
const value = metadata[`${prefix}${suffix}`];
|
|
155
|
+
if (typeof value === "string" && value.trim().length > 0) return value.trim();
|
|
156
|
+
}
|
|
157
|
+
return void 0;
|
|
158
|
+
}
|
|
159
|
+
function readDetachedChildLink(metadata) {
|
|
160
|
+
if (!metadata) return void 0;
|
|
161
|
+
const parentEventId = readHandoffField(metadata, HANDOFF_ATTRIBUTE_SUFFIXES.parentEventId);
|
|
162
|
+
if (!parentEventId) return void 0;
|
|
163
|
+
return {
|
|
164
|
+
parentEventId,
|
|
165
|
+
parentSpanId: readHandoffField(metadata, HANDOFF_ATTRIBUTE_SUFFIXES.parentSpanId),
|
|
166
|
+
name: readHandoffField(metadata, HANDOFF_ATTRIBUTE_SUFFIXES.name)
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
var BAGGAGE_KEYS = {
|
|
170
|
+
eventId: "raindrop-event-id",
|
|
171
|
+
childEventId: "raindrop-child-event-id",
|
|
172
|
+
name: "raindrop-handoff-name",
|
|
173
|
+
convoId: "raindrop-convo-id",
|
|
174
|
+
userId: "raindrop-user-id",
|
|
175
|
+
// The dispatch span and its trace, carried as fields as well as in
|
|
176
|
+
// `traceparent`. Not redundant: OTel's HTTP instrumentations rewrite
|
|
177
|
+
// `traceparent` from whatever span is current as the request goes out, so by
|
|
178
|
+
// the time the child reads it the ids name the HTTP client span and its trace
|
|
179
|
+
// instead of the dispatch. The child would then point its reverse reference at
|
|
180
|
+
// a span the launcher's UI does not know as a dispatch. A field states which
|
|
181
|
+
// span it means rather than meaning "whoever wrote this header last".
|
|
182
|
+
dispatchSpanId: "raindrop-dispatch-span-id",
|
|
183
|
+
traceId: "raindrop-trace-id"
|
|
184
|
+
};
|
|
185
|
+
var TRACEPARENT_HEADER = "traceparent";
|
|
186
|
+
var BAGGAGE_HEADER = "baggage";
|
|
187
|
+
var W3C_TRACE_ID = /^[0-9a-f]{32}$/;
|
|
188
|
+
var W3C_SPAN_ID = /^[0-9a-f]{16}$/;
|
|
189
|
+
function isW3CTraceId(value) {
|
|
190
|
+
return value !== void 0 && W3C_TRACE_ID.test(value);
|
|
191
|
+
}
|
|
192
|
+
function isW3CSpanId(value) {
|
|
193
|
+
return value !== void 0 && W3C_SPAN_ID.test(value);
|
|
194
|
+
}
|
|
195
|
+
var warnedNonConformantIds = false;
|
|
196
|
+
function warnNonConformantIdsOnce(traceId, spanId) {
|
|
197
|
+
if (warnedNonConformantIds) return;
|
|
198
|
+
warnedNonConformantIds = true;
|
|
199
|
+
console.warn(
|
|
200
|
+
`[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.`
|
|
201
|
+
);
|
|
202
|
+
}
|
|
203
|
+
var HANDOFF_HEADER = "x-raindrop-handoff";
|
|
204
|
+
var LANGSMITH_TRACE_HEADER = "langsmith-trace";
|
|
205
|
+
var LANGSMITH_METADATA_BAGGAGE_KEY = "langsmith-metadata";
|
|
206
|
+
function encodeBaggage(entries) {
|
|
207
|
+
return Object.entries(entries).filter((entry) => Boolean(entry[1])).map(([key, value]) => `${key}=${encodeURIComponent(value)}`).join(",");
|
|
208
|
+
}
|
|
209
|
+
function decodeBaggage(header) {
|
|
210
|
+
if (!header) return {};
|
|
211
|
+
const parsed = {};
|
|
212
|
+
for (const part of header.split(",")) {
|
|
213
|
+
const [rawKey, ...rest] = part.split("=");
|
|
214
|
+
if (!rawKey || rest.length === 0) continue;
|
|
215
|
+
const key = rawKey.trim();
|
|
216
|
+
let value;
|
|
217
|
+
try {
|
|
218
|
+
value = decodeURIComponent(rest.join("=").trim());
|
|
219
|
+
} catch (e) {
|
|
220
|
+
value = rest.join("=").trim();
|
|
221
|
+
}
|
|
222
|
+
if (key in parsed && parsed[key] !== value) throw new ConflictingCarrierError(key);
|
|
223
|
+
parsed[key] = value;
|
|
224
|
+
}
|
|
225
|
+
return parsed;
|
|
226
|
+
}
|
|
227
|
+
function carrierBaggage(carrier) {
|
|
228
|
+
return {
|
|
229
|
+
[BAGGAGE_KEYS.eventId]: carrier.eventId,
|
|
230
|
+
[BAGGAGE_KEYS.childEventId]: carrier.childEventId,
|
|
231
|
+
[BAGGAGE_KEYS.name]: carrier.name,
|
|
232
|
+
[BAGGAGE_KEYS.convoId]: carrier.convoId,
|
|
233
|
+
[BAGGAGE_KEYS.userId]: carrier.userId,
|
|
234
|
+
[BAGGAGE_KEYS.dispatchSpanId]: carrier.spanId,
|
|
235
|
+
[BAGGAGE_KEYS.traceId]: carrier.traceId
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
function toHeaders(carrier) {
|
|
239
|
+
const fields = encodeBaggage(carrierBaggage(carrier));
|
|
240
|
+
const headers = {
|
|
241
|
+
[BAGGAGE_HEADER]: fields,
|
|
242
|
+
[HANDOFF_HEADER]: fields
|
|
243
|
+
};
|
|
244
|
+
if (isW3CTraceId(carrier.traceId) && isW3CSpanId(carrier.spanId)) {
|
|
245
|
+
headers[TRACEPARENT_HEADER] = `00-${carrier.traceId}-${carrier.spanId}-01`;
|
|
246
|
+
}
|
|
247
|
+
return headers;
|
|
248
|
+
}
|
|
249
|
+
function langsmithStamp() {
|
|
250
|
+
return (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/g, "").replace(/\.\d+Z$/, "000000");
|
|
251
|
+
}
|
|
252
|
+
function toLangSmithHeaders(carrier) {
|
|
253
|
+
const stamp = langsmithStamp();
|
|
254
|
+
const dottedOrder = `${stamp}Z${carrier.traceId}.${stamp}Z${carrier.spanId}`;
|
|
255
|
+
return {
|
|
256
|
+
[LANGSMITH_TRACE_HEADER]: dottedOrder,
|
|
257
|
+
[BAGGAGE_HEADER]: encodeBaggage({
|
|
258
|
+
[LANGSMITH_METADATA_BAGGAGE_KEY]: JSON.stringify(carrierBaggage(carrier))
|
|
259
|
+
}),
|
|
260
|
+
// Carried here too: a LangSmith-shaped carrier is rewritten in transit
|
|
261
|
+
// exactly like the native one, and an injected `traceparent` is preferred
|
|
262
|
+
// over the dotted order on read.
|
|
263
|
+
[HANDOFF_HEADER]: encodeBaggage(carrierBaggage(carrier))
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
function isHeaderLookup(headers) {
|
|
267
|
+
return "get" in headers && typeof headers.get === "function";
|
|
268
|
+
}
|
|
269
|
+
var ConflictingCarrierError = class extends Error {
|
|
270
|
+
};
|
|
271
|
+
function readHeader(headers, name) {
|
|
272
|
+
var _a, _b, _c;
|
|
273
|
+
if (isHeaderLookup(headers)) return (_a = headers.get(name)) != null ? _a : void 0;
|
|
274
|
+
const value = (_c = headers[name]) != null ? _c : (_b = Object.entries(headers).find(([key]) => key.toLowerCase() === name)) == null ? void 0 : _b[1];
|
|
275
|
+
if (!Array.isArray(value)) return value;
|
|
276
|
+
const distinct = new Set(value);
|
|
277
|
+
if (distinct.size > 1) throw new ConflictingCarrierError(name);
|
|
278
|
+
return value[0];
|
|
279
|
+
}
|
|
280
|
+
function readTraceHeader(headers, name) {
|
|
281
|
+
const value = readHeader(headers, name);
|
|
282
|
+
if (!(value == null ? void 0 : value.includes(","))) return value;
|
|
283
|
+
const copies = value.split(",").map((copy) => copy.trim());
|
|
284
|
+
if (new Set(copies).size > 1) throw new ConflictingCarrierError(name);
|
|
285
|
+
return copies[0];
|
|
286
|
+
}
|
|
287
|
+
function fromHeaders(headers) {
|
|
288
|
+
var _a, _b;
|
|
289
|
+
let baggage;
|
|
290
|
+
let handoff;
|
|
291
|
+
let traceparent;
|
|
292
|
+
let langsmithTrace;
|
|
293
|
+
try {
|
|
294
|
+
baggage = decodeBaggage(readHeader(headers, BAGGAGE_HEADER));
|
|
295
|
+
handoff = decodeBaggage(readHeader(headers, HANDOFF_HEADER));
|
|
296
|
+
traceparent = readTraceHeader(headers, TRACEPARENT_HEADER);
|
|
297
|
+
langsmithTrace = readTraceHeader(headers, LANGSMITH_TRACE_HEADER);
|
|
298
|
+
} catch (error) {
|
|
299
|
+
if (error instanceof ConflictingCarrierError) return null;
|
|
300
|
+
throw error;
|
|
301
|
+
}
|
|
302
|
+
const langsmithMetadata = baggage[LANGSMITH_METADATA_BAGGAGE_KEY];
|
|
303
|
+
const nested = langsmithMetadata ? safeParseStringRecord(langsmithMetadata) : {};
|
|
304
|
+
for (const [key, value] of Object.entries(nested)) {
|
|
305
|
+
if (key in baggage && baggage[key] !== value) return null;
|
|
306
|
+
}
|
|
307
|
+
const fields = {
|
|
308
|
+
...baggage,
|
|
309
|
+
...nested,
|
|
310
|
+
// Last, so it wins: the standard headers may have been rewritten in transit
|
|
311
|
+
// by a propagator, this one is only ever written by us.
|
|
312
|
+
...handoff
|
|
313
|
+
};
|
|
314
|
+
let traceId;
|
|
315
|
+
let spanId;
|
|
316
|
+
if (traceparent) {
|
|
317
|
+
const [, parsedTraceId, parsedSpanId] = traceparent.split("-");
|
|
318
|
+
if (isW3CTraceId(parsedTraceId) && isW3CSpanId(parsedSpanId)) {
|
|
319
|
+
traceId = parsedTraceId;
|
|
320
|
+
spanId = parsedSpanId;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
if (!traceId && !spanId && langsmithTrace) {
|
|
324
|
+
const segments = langsmithTrace.split(".");
|
|
325
|
+
traceId = (_a = segments[0]) == null ? void 0 : _a.split("Z").pop();
|
|
326
|
+
spanId = (_b = segments[segments.length - 1]) == null ? void 0 : _b.split("Z").pop();
|
|
327
|
+
}
|
|
328
|
+
traceId = fields[BAGGAGE_KEYS.traceId] || traceId;
|
|
329
|
+
spanId = fields[BAGGAGE_KEYS.dispatchSpanId] || spanId;
|
|
330
|
+
const eventId = fields[BAGGAGE_KEYS.eventId];
|
|
331
|
+
if (!traceId || !spanId || !eventId) return null;
|
|
332
|
+
if (!isW3CTraceId(traceId) || !isW3CSpanId(spanId)) {
|
|
333
|
+
warnNonConformantIdsOnce(traceId, spanId);
|
|
334
|
+
}
|
|
335
|
+
const carrier = { traceId, spanId, eventId };
|
|
336
|
+
const childEventId = fields[BAGGAGE_KEYS.childEventId];
|
|
337
|
+
if (childEventId) carrier.childEventId = childEventId;
|
|
338
|
+
const name = fields[BAGGAGE_KEYS.name];
|
|
339
|
+
if (name) carrier.name = name;
|
|
340
|
+
const convoId = fields[BAGGAGE_KEYS.convoId];
|
|
341
|
+
if (convoId) carrier.convoId = convoId;
|
|
342
|
+
const userId = fields[BAGGAGE_KEYS.userId];
|
|
343
|
+
if (userId) carrier.userId = userId;
|
|
344
|
+
return carrier;
|
|
345
|
+
}
|
|
346
|
+
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.`;
|
|
347
|
+
var UNRESOLVED_CARRIER_WARNED_KEY = /* @__PURE__ */ Symbol.for("raindrop.handoff.warnedUnresolvedCarrier");
|
|
348
|
+
function warnedHolder() {
|
|
349
|
+
return globalThis;
|
|
350
|
+
}
|
|
351
|
+
function resetUnresolvedCarrierWarning() {
|
|
352
|
+
warnedHolder()[UNRESOLVED_CARRIER_WARNED_KEY] = false;
|
|
353
|
+
}
|
|
354
|
+
function warnUnresolvedCarrier(headers, carrier) {
|
|
355
|
+
if (carrier) return;
|
|
356
|
+
if (!headers) return;
|
|
357
|
+
const holder = warnedHolder();
|
|
358
|
+
if (holder[UNRESOLVED_CARRIER_WARNED_KEY]) return;
|
|
359
|
+
holder[UNRESOLVED_CARRIER_WARNED_KEY] = true;
|
|
360
|
+
console.warn(UNRESOLVED_CARRIER_WARNING);
|
|
361
|
+
}
|
|
362
|
+
function safeParseStringRecord(raw) {
|
|
363
|
+
try {
|
|
364
|
+
const parsed = JSON.parse(raw);
|
|
365
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
366
|
+
const result = {};
|
|
367
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
368
|
+
if (typeof value === "string") result[key] = value;
|
|
369
|
+
}
|
|
370
|
+
return result;
|
|
371
|
+
} catch (e) {
|
|
372
|
+
return {};
|
|
373
|
+
}
|
|
374
|
+
}
|
|
70
375
|
function runWithTracingSuppressed(fn) {
|
|
71
376
|
const hook = globalThis.RAINDROP_SUPPRESS_TRACING;
|
|
72
377
|
if (typeof hook !== "function") return fn();
|
|
@@ -830,6 +1135,193 @@ var EventShipper = class {
|
|
|
830
1135
|
}
|
|
831
1136
|
}
|
|
832
1137
|
};
|
|
1138
|
+
var MODEL_USAGE_ATTRIBUTES = {
|
|
1139
|
+
providerName: "gen_ai.provider.name",
|
|
1140
|
+
requestModel: "gen_ai.request.model",
|
|
1141
|
+
responseModel: "gen_ai.response.model",
|
|
1142
|
+
inputTokens: "gen_ai.usage.input_tokens",
|
|
1143
|
+
outputTokens: "gen_ai.usage.output_tokens",
|
|
1144
|
+
reasoningTokens: "gen_ai.usage.reasoning_tokens",
|
|
1145
|
+
cacheReadInputTokens: "gen_ai.usage.cache_read_input_tokens",
|
|
1146
|
+
cacheWriteInputTokens: "gen_ai.usage.cache_write_input_tokens",
|
|
1147
|
+
nonCachedInputTokens: "raindrop.usage.input_tokens.non_cached",
|
|
1148
|
+
nonReasoningOutputTokens: "raindrop.usage.output_tokens.non_reasoning",
|
|
1149
|
+
reasoningOutputTokens: "raindrop.usage.output_tokens.reasoning",
|
|
1150
|
+
cacheReadTokens: "raindrop.usage.input_tokens.cache_read",
|
|
1151
|
+
cacheWriteTokens: "raindrop.usage.input_tokens.cache_write"
|
|
1152
|
+
};
|
|
1153
|
+
var MODEL_PROVIDER_NAMES = [
|
|
1154
|
+
["google.vertex", "google-vertex"],
|
|
1155
|
+
["vertex.anthropic", "google-vertex"],
|
|
1156
|
+
["amazon-bedrock", "amazon-bedrock"],
|
|
1157
|
+
["bedrock", "amazon-bedrock"],
|
|
1158
|
+
["anthropic", "anthropic"],
|
|
1159
|
+
["openai", "openai"],
|
|
1160
|
+
["google", "google"],
|
|
1161
|
+
["azure", "azure"],
|
|
1162
|
+
["openrouter", "openrouter"]
|
|
1163
|
+
];
|
|
1164
|
+
function canonicalModelProvider(provider) {
|
|
1165
|
+
var _a;
|
|
1166
|
+
const normalizedProvider = provider.trim().toLowerCase();
|
|
1167
|
+
if (normalizedProvider === "gateway") return "vercel";
|
|
1168
|
+
const match = MODEL_PROVIDER_NAMES.find(
|
|
1169
|
+
([family]) => normalizedProvider === family || normalizedProvider.startsWith(`${family}.`)
|
|
1170
|
+
);
|
|
1171
|
+
return (_a = match == null ? void 0 : match[1]) != null ? _a : provider;
|
|
1172
|
+
}
|
|
1173
|
+
function tokenCount(value) {
|
|
1174
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
1175
|
+
}
|
|
1176
|
+
function exclusiveTokens({
|
|
1177
|
+
explicit,
|
|
1178
|
+
total,
|
|
1179
|
+
parts,
|
|
1180
|
+
semantics
|
|
1181
|
+
}) {
|
|
1182
|
+
if (explicit !== void 0) return explicit;
|
|
1183
|
+
if (total === void 0) return void 0;
|
|
1184
|
+
if (semantics === "exclusive") return total;
|
|
1185
|
+
const observedParts = parts.filter((part) => part !== void 0 && part > 0);
|
|
1186
|
+
if (semantics === void 0 && observedParts.length > 0) return void 0;
|
|
1187
|
+
const exclusive = total - observedParts.reduce((sum, part) => sum + part, 0);
|
|
1188
|
+
return exclusive >= 0 ? exclusive : void 0;
|
|
1189
|
+
}
|
|
1190
|
+
function buildModelUsageAttributes(usage) {
|
|
1191
|
+
const inputTokens = tokenCount(usage.inputTokens);
|
|
1192
|
+
const outputTokens = tokenCount(usage.outputTokens);
|
|
1193
|
+
const explicitNonCachedInputTokens = tokenCount(usage.nonCachedInputTokens);
|
|
1194
|
+
const explicitNonReasoningOutputTokens = tokenCount(usage.nonReasoningOutputTokens);
|
|
1195
|
+
const reasoningTokens = tokenCount(usage.reasoningTokens);
|
|
1196
|
+
const cacheReadInputTokens = tokenCount(usage.cacheReadInputTokens);
|
|
1197
|
+
const cacheWriteInputTokens = tokenCount(usage.cacheWriteInputTokens);
|
|
1198
|
+
const nonCachedInputTokens = exclusiveTokens({
|
|
1199
|
+
explicit: explicitNonCachedInputTokens,
|
|
1200
|
+
total: inputTokens,
|
|
1201
|
+
parts: [cacheReadInputTokens, cacheWriteInputTokens],
|
|
1202
|
+
semantics: usage.inputTokenSemantics
|
|
1203
|
+
});
|
|
1204
|
+
const nonReasoningOutputTokens = exclusiveTokens({
|
|
1205
|
+
explicit: explicitNonReasoningOutputTokens,
|
|
1206
|
+
total: outputTokens,
|
|
1207
|
+
parts: [reasoningTokens],
|
|
1208
|
+
semantics: usage.outputTokenSemantics
|
|
1209
|
+
});
|
|
1210
|
+
const exclusivePoolAttributes = nonCachedInputTokens !== void 0 && nonReasoningOutputTokens !== void 0 ? [
|
|
1211
|
+
// backend consumes this complete raindrop.* set as one atomic billing-pool contract.
|
|
1212
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.nonCachedInputTokens, nonCachedInputTokens),
|
|
1213
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.nonReasoningOutputTokens, nonReasoningOutputTokens),
|
|
1214
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.reasoningOutputTokens, reasoningTokens),
|
|
1215
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.cacheReadTokens, cacheReadInputTokens),
|
|
1216
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.cacheWriteTokens, cacheWriteInputTokens)
|
|
1217
|
+
] : [];
|
|
1218
|
+
return [
|
|
1219
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.inputTokens, inputTokens),
|
|
1220
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.outputTokens, outputTokens),
|
|
1221
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.reasoningTokens, reasoningTokens),
|
|
1222
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens, cacheReadInputTokens),
|
|
1223
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens, cacheWriteInputTokens),
|
|
1224
|
+
...exclusivePoolAttributes
|
|
1225
|
+
].filter((attribute) => attribute !== void 0);
|
|
1226
|
+
}
|
|
1227
|
+
var STRING_ALIASES = {
|
|
1228
|
+
[MODEL_USAGE_ATTRIBUTES.requestModel]: ["ai.model.id", "ai.model"]
|
|
1229
|
+
};
|
|
1230
|
+
var NUMBER_ALIASES = {
|
|
1231
|
+
[MODEL_USAGE_ATTRIBUTES.inputTokens]: [
|
|
1232
|
+
"gen_ai.usage.prompt_tokens",
|
|
1233
|
+
"ai.usage.prompt_tokens",
|
|
1234
|
+
"ai.usage.promptTokens",
|
|
1235
|
+
"ai.usage.input_tokens",
|
|
1236
|
+
"ai.usage.inputTokens"
|
|
1237
|
+
],
|
|
1238
|
+
[MODEL_USAGE_ATTRIBUTES.outputTokens]: [
|
|
1239
|
+
"gen_ai.usage.completion_tokens",
|
|
1240
|
+
"ai.usage.completion_tokens",
|
|
1241
|
+
"ai.usage.completionTokens",
|
|
1242
|
+
"ai.usage.output_tokens",
|
|
1243
|
+
"ai.usage.outputTokens"
|
|
1244
|
+
],
|
|
1245
|
+
[MODEL_USAGE_ATTRIBUTES.reasoningTokens]: [
|
|
1246
|
+
"gen_ai.usage.reasoning.output_tokens",
|
|
1247
|
+
"ai.usage.reasoningTokens",
|
|
1248
|
+
"ai.usage.thoughts_tokens"
|
|
1249
|
+
],
|
|
1250
|
+
[MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens]: [
|
|
1251
|
+
"gen_ai.usage.cache_read_tokens",
|
|
1252
|
+
"gen_ai.usage.cache_read.input_tokens",
|
|
1253
|
+
"ai.usage.cachedInputTokens",
|
|
1254
|
+
"ai.usage.cached_tokens",
|
|
1255
|
+
"ai.usage.cache_read_tokens",
|
|
1256
|
+
"ai.usage.cache_read_input_tokens",
|
|
1257
|
+
"ai.usage.cacheReadInputTokens"
|
|
1258
|
+
],
|
|
1259
|
+
[MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens]: [
|
|
1260
|
+
"gen_ai.usage.cache_creation_input_tokens",
|
|
1261
|
+
"gen_ai.usage.cache_creation.input_tokens",
|
|
1262
|
+
"ai.usage.cacheWriteInputTokens",
|
|
1263
|
+
"ai.usage.cache_creation_input_tokens",
|
|
1264
|
+
"ai.usage.cacheCreationInputTokens"
|
|
1265
|
+
]
|
|
1266
|
+
};
|
|
1267
|
+
function hasAttribute(attributes, key) {
|
|
1268
|
+
return attributes.some((attribute) => attribute.key === key);
|
|
1269
|
+
}
|
|
1270
|
+
function findStringAttribute(attributes, keys) {
|
|
1271
|
+
return attributes.find(
|
|
1272
|
+
(attribute) => keys.includes(attribute.key) && typeof attribute.value.stringValue === "string" && attribute.value.stringValue.length > 0
|
|
1273
|
+
);
|
|
1274
|
+
}
|
|
1275
|
+
function findNumberAttribute(attributes, keys) {
|
|
1276
|
+
return attributes.find((attribute) => {
|
|
1277
|
+
if (!keys.includes(attribute.key)) return false;
|
|
1278
|
+
if (typeof attribute.value.doubleValue === "number" && Number.isSafeInteger(attribute.value.doubleValue) && attribute.value.doubleValue >= 0) {
|
|
1279
|
+
return true;
|
|
1280
|
+
}
|
|
1281
|
+
const intValue = attribute.value.intValue;
|
|
1282
|
+
return integerValue(intValue) !== void 0;
|
|
1283
|
+
});
|
|
1284
|
+
}
|
|
1285
|
+
function integerValue(value) {
|
|
1286
|
+
if (typeof value === "number") {
|
|
1287
|
+
return Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
1288
|
+
}
|
|
1289
|
+
if (typeof value !== "string") return void 0;
|
|
1290
|
+
const parsed = Number(value);
|
|
1291
|
+
return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : void 0;
|
|
1292
|
+
}
|
|
1293
|
+
function appendAlias(attributes, target, source) {
|
|
1294
|
+
if (!source || hasAttribute(attributes, target)) return attributes;
|
|
1295
|
+
return [...attributes, { key: target, value: { ...source.value } }];
|
|
1296
|
+
}
|
|
1297
|
+
function appendProviderAlias(attributes) {
|
|
1298
|
+
if (hasAttribute(attributes, MODEL_USAGE_ATTRIBUTES.providerName)) return attributes;
|
|
1299
|
+
const source = findStringAttribute(attributes, ["gen_ai.system", "ai.model.provider"]);
|
|
1300
|
+
if (!(source == null ? void 0 : source.value.stringValue)) return attributes;
|
|
1301
|
+
const attribute = attrString(
|
|
1302
|
+
MODEL_USAGE_ATTRIBUTES.providerName,
|
|
1303
|
+
canonicalModelProvider(source.value.stringValue)
|
|
1304
|
+
);
|
|
1305
|
+
return attribute ? [...attributes, attribute] : attributes;
|
|
1306
|
+
}
|
|
1307
|
+
function normalizeModelUsageSpan(span) {
|
|
1308
|
+
const original = span.attributes;
|
|
1309
|
+
if (!original || original.length === 0) return span;
|
|
1310
|
+
const responseModel = findStringAttribute(original, [
|
|
1311
|
+
MODEL_USAGE_ATTRIBUTES.responseModel,
|
|
1312
|
+
"ai.response.model"
|
|
1313
|
+
]);
|
|
1314
|
+
if (!responseModel) return span;
|
|
1315
|
+
let attributes = appendAlias(original, MODEL_USAGE_ATTRIBUTES.responseModel, responseModel);
|
|
1316
|
+
attributes = appendProviderAlias(attributes);
|
|
1317
|
+
for (const [target, aliases] of Object.entries(STRING_ALIASES)) {
|
|
1318
|
+
attributes = appendAlias(attributes, target, findStringAttribute(attributes, aliases));
|
|
1319
|
+
}
|
|
1320
|
+
for (const [target, aliases] of Object.entries(NUMBER_ALIASES)) {
|
|
1321
|
+
attributes = appendAlias(attributes, target, findNumberAttribute(attributes, aliases));
|
|
1322
|
+
}
|
|
1323
|
+
return attributes === original ? span : { ...span, attributes };
|
|
1324
|
+
}
|
|
833
1325
|
var DEFAULT_SECRET_KEY_NAMES = [
|
|
834
1326
|
"apikey",
|
|
835
1327
|
"apisecret",
|
|
@@ -1030,6 +1522,10 @@ var TraceShipper = class {
|
|
|
1030
1522
|
return null;
|
|
1031
1523
|
}
|
|
1032
1524
|
}
|
|
1525
|
+
try {
|
|
1526
|
+
current = normalizeModelUsageSpan(current);
|
|
1527
|
+
} catch (e) {
|
|
1528
|
+
}
|
|
1033
1529
|
if (!this.disableDefaultRedaction) {
|
|
1034
1530
|
current = defaultTransformSpan(current);
|
|
1035
1531
|
}
|
|
@@ -1389,7 +1885,7 @@ installTracingSuppressionHook();
|
|
|
1389
1885
|
// package.json
|
|
1390
1886
|
var package_default = {
|
|
1391
1887
|
name: "@raindrop-ai/ai-sdk",
|
|
1392
|
-
version: "0.
|
|
1888
|
+
version: "0.3.0"};
|
|
1393
1889
|
|
|
1394
1890
|
// src/internal/version.ts
|
|
1395
1891
|
var libraryName = package_default.name;
|
|
@@ -2086,6 +2582,15 @@ function attrsFromHeaders(headers) {
|
|
|
2086
2582
|
if (!isRecord(headers)) return [];
|
|
2087
2583
|
return Object.entries(headers).filter(([, v]) => typeof v === "string").map(([k, v]) => attrString(`ai.request.headers.${k}`, v));
|
|
2088
2584
|
}
|
|
2585
|
+
function attrsFromModelProvider(provider) {
|
|
2586
|
+
if (typeof provider !== "string" || provider.length === 0) return [];
|
|
2587
|
+
const providerName = canonicalModelProvider(provider);
|
|
2588
|
+
return [
|
|
2589
|
+
attrString("ai.model.provider", provider),
|
|
2590
|
+
attrString(MODEL_USAGE_ATTRIBUTES.providerName, providerName),
|
|
2591
|
+
attrString("gen_ai.system", provider)
|
|
2592
|
+
];
|
|
2593
|
+
}
|
|
2089
2594
|
function attrsFromSettings(args) {
|
|
2090
2595
|
if (!isRecord(args)) return [];
|
|
2091
2596
|
const result = [];
|
|
@@ -2268,6 +2773,473 @@ function runWithParentToolContext(ctx, fn) {
|
|
|
2268
2773
|
return getStorage2().run(ctx, fn);
|
|
2269
2774
|
}
|
|
2270
2775
|
|
|
2776
|
+
// src/internal/subagents.ts
|
|
2777
|
+
var SUBAGENT_CANCELLED_OUTPUT = "Cancelled before producing a result.";
|
|
2778
|
+
var SUBAGENT_ABORTED_OUTPUT = "Aborted before producing a result.";
|
|
2779
|
+
var SUBAGENT_FAILED_OPERATION_ID = SUBAGENT_ABORT_OPERATION_ID;
|
|
2780
|
+
var MAX_SETTLED_EVENT_IDS = 1024;
|
|
2781
|
+
function isTraceCarrier(value) {
|
|
2782
|
+
const candidate = value;
|
|
2783
|
+
return typeof candidate.traceId === "string" && typeof candidate.spanId === "string" && typeof candidate.eventId === "string";
|
|
2784
|
+
}
|
|
2785
|
+
function attrsFrom(metadata) {
|
|
2786
|
+
return Object.entries(withMetadataPrefix(metadata)).map(([key, value]) => attrString(key, value));
|
|
2787
|
+
}
|
|
2788
|
+
function attrsExact(attributes) {
|
|
2789
|
+
return Object.entries(attributes).map(([key, value]) => attrString(key, value));
|
|
2790
|
+
}
|
|
2791
|
+
function handoffSpanAttrs(link) {
|
|
2792
|
+
if (!link) return [];
|
|
2793
|
+
return attrsFrom(detachedChildMetadata(link));
|
|
2794
|
+
}
|
|
2795
|
+
function subagentNameAttrs(name, link) {
|
|
2796
|
+
if (!name || (link == null ? void 0 : link.name)) return [];
|
|
2797
|
+
return attrsFrom({ [HANDOFF_ATTRIBUTE_SUFFIXES.name]: name });
|
|
2798
|
+
}
|
|
2799
|
+
function cancelledSpanAttrs() {
|
|
2800
|
+
return attrsExact(cancelledTerminalAttributes());
|
|
2801
|
+
}
|
|
2802
|
+
function describeAbortReason(reason) {
|
|
2803
|
+
if (reason instanceof Error) return `Aborted: ${reason.message}`;
|
|
2804
|
+
if (typeof reason === "string" && reason.trim().length > 0) return reason;
|
|
2805
|
+
if (reason === void 0 || reason === null) return SUBAGENT_ABORTED_OUTPUT;
|
|
2806
|
+
const serialized = boundedStringify(reason);
|
|
2807
|
+
return serialized ? `Aborted: ${serialized}` : SUBAGENT_ABORTED_OUTPUT;
|
|
2808
|
+
}
|
|
2809
|
+
function stampOpenSpan(span, metadata) {
|
|
2810
|
+
if (span.endTimeUnixNano) return;
|
|
2811
|
+
span.attributes.push(...attrsFrom(metadata));
|
|
2812
|
+
}
|
|
2813
|
+
function stampOpenSpanExact(span, attributes) {
|
|
2814
|
+
if (span.endTimeUnixNano) return;
|
|
2815
|
+
span.attributes.push(...attrsExact(attributes));
|
|
2816
|
+
}
|
|
2817
|
+
var SubagentApi = class {
|
|
2818
|
+
constructor(opts) {
|
|
2819
|
+
var _a;
|
|
2820
|
+
this.opts = opts;
|
|
2821
|
+
this.settledEventIds = (_a = opts.settledEventIds) != null ? _a : /* @__PURE__ */ new Set();
|
|
2822
|
+
}
|
|
2823
|
+
/** True when this child's outcome has already been reported. */
|
|
2824
|
+
wasSettledExplicitly(eventId) {
|
|
2825
|
+
return this.settledEventIds.has(eventId);
|
|
2826
|
+
}
|
|
2827
|
+
/**
|
|
2828
|
+
* Record an outcome reported somewhere other than `cancel()` / `fail()`, so
|
|
2829
|
+
* first-outcome-wins holds across every path that can state one.
|
|
2830
|
+
*
|
|
2831
|
+
* An aborted generation is such a path: an AbortSignal cancellation IS the
|
|
2832
|
+
* run's outcome, and the `fail(err)` that a catch block around the aborted
|
|
2833
|
+
* call naturally reports would otherwise error the child's spans — which is
|
|
2834
|
+
* the only thing separating `failed` from `cancelled`.
|
|
2835
|
+
*/
|
|
2836
|
+
noteSettled(eventId) {
|
|
2837
|
+
this.remember(eventId);
|
|
2838
|
+
}
|
|
2839
|
+
remember(eventId) {
|
|
2840
|
+
if (this.settledEventIds.has(eventId)) return;
|
|
2841
|
+
if (this.settledEventIds.size >= MAX_SETTLED_EVENT_IDS) {
|
|
2842
|
+
const oldest = this.settledEventIds.values().next();
|
|
2843
|
+
if (!oldest.done) this.settledEventIds.delete(oldest.value);
|
|
2844
|
+
}
|
|
2845
|
+
this.settledEventIds.add(eventId);
|
|
2846
|
+
}
|
|
2847
|
+
/**
|
|
2848
|
+
* Record a detached sub-agent on this turn: allocate the child's event id,
|
|
2849
|
+
* stamp the dispatch, and return the headers to send with the job.
|
|
2850
|
+
*
|
|
2851
|
+
* This dispatches nothing — you do, moments later, with the returned headers.
|
|
2852
|
+
* Nothing here waits for the child either, or claims to know how it is doing.
|
|
2853
|
+
* Readers derive that from the child's own event.
|
|
2854
|
+
*/
|
|
2855
|
+
subagent(options = {}) {
|
|
2856
|
+
var _a;
|
|
2857
|
+
const childEventId = (_a = options.childEventId) != null ? _a : randomUUID();
|
|
2858
|
+
const name = options.name;
|
|
2859
|
+
try {
|
|
2860
|
+
return this.recordLaunch(childEventId, name, options);
|
|
2861
|
+
} catch (err) {
|
|
2862
|
+
if (this.opts.debug) {
|
|
2863
|
+
console.warn(
|
|
2864
|
+
`[raindrop-ai/ai-sdk] sub-agent dispatch not recorded: ${err instanceof Error ? err.message : err}`
|
|
2865
|
+
);
|
|
2866
|
+
}
|
|
2867
|
+
return { childEventId, name, headers: {}, carrier: null };
|
|
2868
|
+
}
|
|
2869
|
+
}
|
|
2870
|
+
recordLaunch(childEventId, name, options) {
|
|
2871
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
|
|
2872
|
+
const active = (_a = this.opts.spanSource) == null ? void 0 : _a.activeDispatch();
|
|
2873
|
+
const inherited = getContextManager().getParentSpanIds();
|
|
2874
|
+
const eventId = (_e = (_c = (_b = options.eventId) != null ? _b : active == null ? void 0 : active.eventId) != null ? _c : inherited == null ? void 0 : inherited.eventId) != null ? _e : (_d = this.opts.defaultContext) == null ? void 0 : _d.eventId;
|
|
2875
|
+
const userId = (_h = (_f = options.userId) != null ? _f : active == null ? void 0 : active.userId) != null ? _h : (_g = this.opts.defaultContext) == null ? void 0 : _g.userId;
|
|
2876
|
+
const convoId = (_k = (_i = options.convoId) != null ? _i : active == null ? void 0 : active.convoId) != null ? _k : (_j = this.opts.defaultContext) == null ? void 0 : _j.convoId;
|
|
2877
|
+
if (!eventId) {
|
|
2878
|
+
return { childEventId, name, headers: {}, carrier: null };
|
|
2879
|
+
}
|
|
2880
|
+
const dispatch = detachedDispatchMetadata({ childEventId, name });
|
|
2881
|
+
const toolEvents = toolEventsAllowMetadata();
|
|
2882
|
+
for (const span of (_l = active == null ? void 0 : active.turnSpans) != null ? _l : []) {
|
|
2883
|
+
stampOpenSpan(span, toolEvents);
|
|
2884
|
+
}
|
|
2885
|
+
let dispatchIds;
|
|
2886
|
+
if (active == null ? void 0 : active.dispatchSpan) {
|
|
2887
|
+
stampOpenSpan(active.dispatchSpan, dispatch);
|
|
2888
|
+
dispatchIds = active.dispatchSpan.ids;
|
|
2889
|
+
} else if (this.opts.sendTraces) {
|
|
2890
|
+
dispatchIds = this.synthesizeDispatchSpan({
|
|
2891
|
+
childEventId,
|
|
2892
|
+
name,
|
|
2893
|
+
toolName: options.toolName,
|
|
2894
|
+
eventId,
|
|
2895
|
+
userId,
|
|
2896
|
+
convoId,
|
|
2897
|
+
input: options.input,
|
|
2898
|
+
// No active turn means no telemetry setting to honor: `input` is then
|
|
2899
|
+
// recorded on the explicit say-so of whoever passed it.
|
|
2900
|
+
recordInputs: (_m = active == null ? void 0 : active.recordInputs) != null ? _m : true,
|
|
2901
|
+
dispatch,
|
|
2902
|
+
parent: (inherited == null ? void 0 : inherited.eventId) === eventId ? inherited : void 0
|
|
2903
|
+
}).ids;
|
|
2904
|
+
}
|
|
2905
|
+
const traceId = base64ToHex((_o = (_n = dispatchIds == null ? void 0 : dispatchIds.traceIdB64) != null ? _n : inherited == null ? void 0 : inherited.traceIdB64) != null ? _o : "");
|
|
2906
|
+
const spanId = base64ToHex((_p = dispatchIds == null ? void 0 : dispatchIds.spanIdB64) != null ? _p : "");
|
|
2907
|
+
if (!traceId || !spanId) {
|
|
2908
|
+
if (this.opts.debug) {
|
|
2909
|
+
console.warn(
|
|
2910
|
+
"[raindrop-ai/ai-sdk] sub-agent dispatch recorded without a carrier: no dispatch span to reference (traces disabled?)"
|
|
2911
|
+
);
|
|
2912
|
+
}
|
|
2913
|
+
return { childEventId, name, headers: {}, carrier: null };
|
|
2914
|
+
}
|
|
2915
|
+
const carrier = {
|
|
2916
|
+
traceId,
|
|
2917
|
+
spanId,
|
|
2918
|
+
eventId,
|
|
2919
|
+
childEventId,
|
|
2920
|
+
...name ? { name } : {},
|
|
2921
|
+
...convoId ? { convoId } : {},
|
|
2922
|
+
...userId ? { userId } : {}
|
|
2923
|
+
};
|
|
2924
|
+
return { childEventId, name, headers: toHeaders(carrier), carrier };
|
|
2925
|
+
}
|
|
2926
|
+
/**
|
|
2927
|
+
* Record a dispatch span for a launch with no open tool-call span to decorate:
|
|
2928
|
+
* a launch from outside a tool's `execute`, or from a caller that is not an
|
|
2929
|
+
* LLM turn at all (an HTTP handler that enqueues jobs). Shaped as a tool call
|
|
2930
|
+
* so it reads identically to a model-issued launch.
|
|
2931
|
+
*/
|
|
2932
|
+
synthesizeDispatchSpan(args) {
|
|
2933
|
+
var _a;
|
|
2934
|
+
const spanName = (_a = args.toolName) != null ? _a : DEFAULT_DISPATCH_SPAN_NAME;
|
|
2935
|
+
const span = this.opts.traceShipper.startSpan({
|
|
2936
|
+
name: spanName,
|
|
2937
|
+
parent: args.parent,
|
|
2938
|
+
eventId: args.eventId,
|
|
2939
|
+
userId: args.userId,
|
|
2940
|
+
convoId: args.convoId,
|
|
2941
|
+
operationId: "ai.toolCall",
|
|
2942
|
+
attributes: [
|
|
2943
|
+
attrString("operation.name", "ai.toolCall"),
|
|
2944
|
+
attrString("resource.name", spanName),
|
|
2945
|
+
attrString("ai.toolCall.name", spanName),
|
|
2946
|
+
attrString("ai.toolCall.id", `call_${args.childEventId.replace(/-/g, "").slice(0, 12)}`),
|
|
2947
|
+
// Gated like every other input the turn's spans record: a caller that
|
|
2948
|
+
// disabled input capture must not leak the payload through the one
|
|
2949
|
+
// span this API synthesizes on its behalf.
|
|
2950
|
+
...args.recordInputs ? [attrString("ai.toolCall.args", boundedStringify(args.input))] : [],
|
|
2951
|
+
...attrsFrom(args.dispatch)
|
|
2952
|
+
]
|
|
2953
|
+
});
|
|
2954
|
+
this.opts.traceShipper.endSpan(span, {
|
|
2955
|
+
// A dispatch returns a handle, not an answer — the answer is the child's.
|
|
2956
|
+
attributes: [
|
|
2957
|
+
attrString(
|
|
2958
|
+
"ai.toolCall.result",
|
|
2959
|
+
boundedStringify({ jobId: args.childEventId, status: "accepted" })
|
|
2960
|
+
)
|
|
2961
|
+
]
|
|
2962
|
+
});
|
|
2963
|
+
return span;
|
|
2964
|
+
}
|
|
2965
|
+
/**
|
|
2966
|
+
* Adopt a carrier as the current run's parent reference.
|
|
2967
|
+
*
|
|
2968
|
+
* A missing carrier is a legitimate state — the child was invoked directly
|
|
2969
|
+
* rather than dispatched — so this always returns a usable run and leaves
|
|
2970
|
+
* `parent` null. Call sites stay unconditional.
|
|
2971
|
+
*/
|
|
2972
|
+
resume(carrierOrHeaders, options = {}) {
|
|
2973
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
2974
|
+
const carrier = carrierOrHeaders ? isTraceCarrier(carrierOrHeaders) ? carrierOrHeaders : this.readCarrier(carrierOrHeaders) : null;
|
|
2975
|
+
warnUnresolvedCarrier(carrierOrHeaders, carrier);
|
|
2976
|
+
const name = (_a = carrier == null ? void 0 : carrier.name) != null ? _a : options.name;
|
|
2977
|
+
const eventId = (_c = (_b = carrier == null ? void 0 : carrier.childEventId) != null ? _b : options.eventId) != null ? _c : randomUUID();
|
|
2978
|
+
const userId = (_f = (_d = carrier == null ? void 0 : carrier.userId) != null ? _d : options.userId) != null ? _f : (_e = this.opts.defaultContext) == null ? void 0 : _e.userId;
|
|
2979
|
+
const convoId = (_i = (_g = carrier == null ? void 0 : carrier.convoId) != null ? _g : options.convoId) != null ? _i : (_h = this.opts.defaultContext) == null ? void 0 : _h.convoId;
|
|
2980
|
+
const parent = carrier ? {
|
|
2981
|
+
parentEventId: carrier.eventId,
|
|
2982
|
+
...carrier.spanId ? { parentSpanId: carrier.spanId } : {},
|
|
2983
|
+
...name ? { name } : {}
|
|
2984
|
+
} : null;
|
|
2985
|
+
return {
|
|
2986
|
+
eventId,
|
|
2987
|
+
name,
|
|
2988
|
+
userId,
|
|
2989
|
+
convoId,
|
|
2990
|
+
parent,
|
|
2991
|
+
metadata: {
|
|
2992
|
+
eventId,
|
|
2993
|
+
...userId ? { userId } : {},
|
|
2994
|
+
...convoId ? { convoId } : {},
|
|
2995
|
+
...parent ? { subagent: parent } : {}
|
|
2996
|
+
},
|
|
2997
|
+
cancel: (reason) => this.settle(eventId, { userId, convoId, name, cancelled: true, output: reason }),
|
|
2998
|
+
fail: (reason) => this.settle(eventId, {
|
|
2999
|
+
userId,
|
|
3000
|
+
convoId,
|
|
3001
|
+
name,
|
|
3002
|
+
handoff: parent != null ? parent : void 0,
|
|
3003
|
+
cancelled: false,
|
|
3004
|
+
output: describeAbortReason(reason),
|
|
3005
|
+
error: reason
|
|
3006
|
+
})
|
|
3007
|
+
};
|
|
3008
|
+
}
|
|
3009
|
+
/**
|
|
3010
|
+
* A carrier arrives from outside this process, so a hostile or merely broken
|
|
3011
|
+
* header bag must cost the job its link, never its run.
|
|
3012
|
+
*/
|
|
3013
|
+
readCarrier(headers) {
|
|
3014
|
+
try {
|
|
3015
|
+
return fromHeaders(headers);
|
|
3016
|
+
} catch (err) {
|
|
3017
|
+
if (this.opts.debug) {
|
|
3018
|
+
console.warn(
|
|
3019
|
+
`[raindrop-ai/ai-sdk] sub-agent carrier ignored: ${err instanceof Error ? err.message : err}`
|
|
3020
|
+
);
|
|
3021
|
+
}
|
|
3022
|
+
return null;
|
|
3023
|
+
}
|
|
3024
|
+
}
|
|
3025
|
+
/**
|
|
3026
|
+
* Mark a failed child's own spans as errored.
|
|
3027
|
+
*
|
|
3028
|
+
* Reporting the reason as output is what gets the child an event at all, but
|
|
3029
|
+
* output alone is not enough: status is derived from span shape, and a child
|
|
3030
|
+
* with final output and no error spans derives `finished`. A failed job
|
|
3031
|
+
* reporting success is worse than one reporting nothing, so the failure has
|
|
3032
|
+
* to land on the telemetry too, not just in the text.
|
|
3033
|
+
*
|
|
3034
|
+
* This is the child describing its own run, not a caller writing a status it
|
|
3035
|
+
* cannot observe — the child's own spans are exactly where the contract puts
|
|
3036
|
+
* failure.
|
|
3037
|
+
*/
|
|
3038
|
+
recordFailureOnSpans(eventId, args, reason) {
|
|
3039
|
+
var _a, _b, _c;
|
|
3040
|
+
if (!this.opts.sendTraces) return;
|
|
3041
|
+
const failure = (_a = args.error) != null ? _a : reason;
|
|
3042
|
+
let marked = 0;
|
|
3043
|
+
for (const span2 of (_c = (_b = this.opts.spanSource) == null ? void 0 : _b.openSpansForEvent(eventId)) != null ? _c : []) {
|
|
3044
|
+
if (span2.endTimeUnixNano) continue;
|
|
3045
|
+
this.opts.traceShipper.endSpan(span2, { error: failure });
|
|
3046
|
+
marked++;
|
|
3047
|
+
}
|
|
3048
|
+
if (marked > 0) return;
|
|
3049
|
+
const spanName = SUBAGENT_ABORT_SPAN_NAME;
|
|
3050
|
+
const span = this.opts.traceShipper.startSpan({
|
|
3051
|
+
name: spanName,
|
|
3052
|
+
eventId,
|
|
3053
|
+
userId: args.userId,
|
|
3054
|
+
convoId: args.convoId,
|
|
3055
|
+
// Required, not decorative: ingest drops any span carrying no
|
|
3056
|
+
// `ai.operationId` (or traceloop / `gen_ai.*` key) and still answers 200,
|
|
3057
|
+
// so without this the failure disappears silently. The value is
|
|
3058
|
+
// deliberately none of the generate/stream/tool/embed forms, which is
|
|
3059
|
+
// what classifies the span as INTERNAL rather than mislabelling a failed
|
|
3060
|
+
// job as a model call or a tool call.
|
|
3061
|
+
operationId: SUBAGENT_FAILED_OPERATION_ID,
|
|
3062
|
+
// Carries the reverse reference like every other span the child emits:
|
|
3063
|
+
// this is often the child's ONLY span, and a span read on its own is the
|
|
3064
|
+
// whole reason the reference cannot live on the root alone. The name is
|
|
3065
|
+
// stamped even for an unlinked run, which has no caller to reference —
|
|
3066
|
+
// `span_name` no longer says which sub-agent this was, so the attribute
|
|
3067
|
+
// is the only thing that can.
|
|
3068
|
+
attributes: [
|
|
3069
|
+
attrString("resource.name", spanName),
|
|
3070
|
+
...handoffSpanAttrs(args.handoff),
|
|
3071
|
+
...subagentNameAttrs(args.name, args.handoff)
|
|
3072
|
+
]
|
|
3073
|
+
});
|
|
3074
|
+
this.opts.traceShipper.endSpan(span, { error: failure });
|
|
3075
|
+
}
|
|
3076
|
+
async settle(eventId, args) {
|
|
3077
|
+
var _a, _b;
|
|
3078
|
+
if (this.settledEventIds.has(eventId)) {
|
|
3079
|
+
if (this.opts.debug) {
|
|
3080
|
+
console.warn(
|
|
3081
|
+
`[raindrop-ai/ai-sdk] sub-agent ${eventId} already reported an outcome; ignoring the second one`
|
|
3082
|
+
);
|
|
3083
|
+
}
|
|
3084
|
+
return;
|
|
3085
|
+
}
|
|
3086
|
+
this.remember(eventId);
|
|
3087
|
+
const output = args.output && args.output.trim().length > 0 ? args.output : args.cancelled ? SUBAGENT_CANCELLED_OUTPUT : SUBAGENT_ABORTED_OUTPUT;
|
|
3088
|
+
try {
|
|
3089
|
+
if (args.cancelled) {
|
|
3090
|
+
for (const span of (_b = (_a = this.opts.spanSource) == null ? void 0 : _a.openSpansForEvent(eventId)) != null ? _b : []) {
|
|
3091
|
+
stampOpenSpanExact(span, cancelledTerminalAttributes());
|
|
3092
|
+
}
|
|
3093
|
+
} else {
|
|
3094
|
+
this.recordFailureOnSpans(eventId, args, output);
|
|
3095
|
+
}
|
|
3096
|
+
} catch (err) {
|
|
3097
|
+
if (this.opts.debug) {
|
|
3098
|
+
console.warn(
|
|
3099
|
+
`[raindrop-ai/ai-sdk] sub-agent outcome not recorded on spans: ${err instanceof Error ? err.message : err}`
|
|
3100
|
+
);
|
|
3101
|
+
}
|
|
3102
|
+
}
|
|
3103
|
+
if (!this.opts.sendEvents) return;
|
|
3104
|
+
await this.opts.eventShipper.patch(eventId, {
|
|
3105
|
+
userId: args.userId,
|
|
3106
|
+
convoId: args.convoId,
|
|
3107
|
+
// An event is only created from a run that reported something. A child
|
|
3108
|
+
// that dies silently produces no event at all, which pins the caller on
|
|
3109
|
+
// `queued` forever — indistinguishable from a job that never started.
|
|
3110
|
+
output,
|
|
3111
|
+
...args.cancelled ? { properties: { [HANDOFF_TERMINAL_PROPERTY_KEY]: HANDOFF_TERMINAL_CANCELLED } } : {},
|
|
3112
|
+
isPending: false
|
|
3113
|
+
}).catch((err) => {
|
|
3114
|
+
if (this.opts.debug) {
|
|
3115
|
+
console.warn(
|
|
3116
|
+
`[raindrop-ai/ai-sdk] sub-agent outcome patch failed: ${err instanceof Error ? err.message : err}`
|
|
3117
|
+
);
|
|
3118
|
+
}
|
|
3119
|
+
});
|
|
3120
|
+
}
|
|
3121
|
+
};
|
|
3122
|
+
|
|
3123
|
+
// src/internal/usage.ts
|
|
3124
|
+
function firstTokenCount(...values) {
|
|
3125
|
+
for (const value of values) {
|
|
3126
|
+
if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) {
|
|
3127
|
+
return value;
|
|
3128
|
+
}
|
|
3129
|
+
}
|
|
3130
|
+
return void 0;
|
|
3131
|
+
}
|
|
3132
|
+
function flatUsageSemantics(provider) {
|
|
3133
|
+
const normalizedProvider = typeof provider === "string" ? provider.trim().toLowerCase() : void 0;
|
|
3134
|
+
if (normalizedProvider === "anthropic" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("anthropic.")) || normalizedProvider === "vertex.anthropic" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("vertex.anthropic."))) {
|
|
3135
|
+
return {
|
|
3136
|
+
inputTokenSemantics: "exclusive",
|
|
3137
|
+
outputTokenSemantics: "total"
|
|
3138
|
+
};
|
|
3139
|
+
}
|
|
3140
|
+
if (normalizedProvider === "openai" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("openai.")) || normalizedProvider === "azure" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("azure."))) {
|
|
3141
|
+
return {
|
|
3142
|
+
inputTokenSemantics: "total",
|
|
3143
|
+
outputTokenSemantics: "total"
|
|
3144
|
+
};
|
|
3145
|
+
}
|
|
3146
|
+
if (normalizedProvider === "google" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("google."))) {
|
|
3147
|
+
return {
|
|
3148
|
+
inputTokenSemantics: "total",
|
|
3149
|
+
// Google v5 reports candidate output and thoughts separately.
|
|
3150
|
+
outputTokenSemantics: "exclusive"
|
|
3151
|
+
};
|
|
3152
|
+
}
|
|
3153
|
+
return {};
|
|
3154
|
+
}
|
|
3155
|
+
var CACHE_WRITE_METADATA_KEYS = [
|
|
3156
|
+
["anthropic", "cacheCreationInputTokens"],
|
|
3157
|
+
["openai", "cacheWriteTokens"],
|
|
3158
|
+
["bedrock", "cacheWriteInputTokens"]
|
|
3159
|
+
];
|
|
3160
|
+
function cacheWriteTokensFromProviderMetadata(providerMetadata) {
|
|
3161
|
+
if (!isRecord(providerMetadata)) return void 0;
|
|
3162
|
+
return firstTokenCount(
|
|
3163
|
+
...CACHE_WRITE_METADATA_KEYS.flatMap(([namespace, key]) => {
|
|
3164
|
+
const scope = providerMetadata[namespace];
|
|
3165
|
+
if (!isRecord(scope)) return [];
|
|
3166
|
+
const usage = scope["usage"];
|
|
3167
|
+
return [scope[key], isRecord(usage) ? usage[key] : void 0];
|
|
3168
|
+
})
|
|
3169
|
+
);
|
|
3170
|
+
}
|
|
3171
|
+
function extractUsageMetricsFromUsage(usage, provider, providerMetadata) {
|
|
3172
|
+
if (!isRecord(usage)) return {};
|
|
3173
|
+
const inputTokenValue = usage["inputTokens"];
|
|
3174
|
+
const outputTokenValue = usage["outputTokens"];
|
|
3175
|
+
const inputTokenDetails = usage["inputTokenDetails"];
|
|
3176
|
+
const outputTokenDetails = usage["outputTokenDetails"];
|
|
3177
|
+
const hasStructuredUsage = isRecord(inputTokenValue) || isRecord(outputTokenValue) || isRecord(inputTokenDetails) || isRecord(outputTokenDetails);
|
|
3178
|
+
const inputTokens = firstTokenCount(
|
|
3179
|
+
isRecord(inputTokenValue) ? inputTokenValue["total"] : void 0,
|
|
3180
|
+
inputTokenValue,
|
|
3181
|
+
usage["promptTokens"],
|
|
3182
|
+
usage["prompt_tokens"]
|
|
3183
|
+
);
|
|
3184
|
+
const outputTokens = firstTokenCount(
|
|
3185
|
+
isRecord(outputTokenValue) ? outputTokenValue["total"] : void 0,
|
|
3186
|
+
outputTokenValue,
|
|
3187
|
+
usage["completionTokens"],
|
|
3188
|
+
usage["completion_tokens"]
|
|
3189
|
+
);
|
|
3190
|
+
const reasoningTokens = firstTokenCount(
|
|
3191
|
+
isRecord(outputTokenValue) ? outputTokenValue["reasoning"] : void 0,
|
|
3192
|
+
isRecord(outputTokenDetails) ? outputTokenDetails["reasoningTokens"] : void 0,
|
|
3193
|
+
usage["reasoningTokens"],
|
|
3194
|
+
usage["completionReasoningTokens"],
|
|
3195
|
+
usage["completion_reasoning_tokens"],
|
|
3196
|
+
usage["reasoning_tokens"],
|
|
3197
|
+
usage["thinkingTokens"],
|
|
3198
|
+
usage["thinking_tokens"]
|
|
3199
|
+
);
|
|
3200
|
+
const cacheReadInputTokens = firstTokenCount(
|
|
3201
|
+
isRecord(inputTokenValue) ? inputTokenValue["cacheRead"] : void 0,
|
|
3202
|
+
isRecord(inputTokenDetails) ? inputTokenDetails["cacheReadTokens"] : void 0,
|
|
3203
|
+
usage["cachedInputTokens"],
|
|
3204
|
+
usage["promptCachedTokens"],
|
|
3205
|
+
usage["prompt_cached_tokens"]
|
|
3206
|
+
);
|
|
3207
|
+
const cacheWriteInputTokens = firstTokenCount(
|
|
3208
|
+
isRecord(inputTokenValue) ? inputTokenValue["cacheWrite"] : void 0,
|
|
3209
|
+
isRecord(inputTokenDetails) ? inputTokenDetails["cacheWriteTokens"] : void 0,
|
|
3210
|
+
usage["cacheWriteInputTokens"],
|
|
3211
|
+
usage["cacheCreationInputTokens"],
|
|
3212
|
+
usage["cache_creation_input_tokens"],
|
|
3213
|
+
cacheWriteTokensFromProviderMetadata(providerMetadata)
|
|
3214
|
+
);
|
|
3215
|
+
const nonCachedInputTokens = firstTokenCount(
|
|
3216
|
+
isRecord(inputTokenValue) ? inputTokenValue["noCache"] : void 0,
|
|
3217
|
+
isRecord(inputTokenDetails) ? inputTokenDetails["noCacheTokens"] : void 0
|
|
3218
|
+
);
|
|
3219
|
+
const nonReasoningOutputTokens = firstTokenCount(
|
|
3220
|
+
isRecord(outputTokenValue) ? outputTokenValue["text"] : void 0,
|
|
3221
|
+
isRecord(outputTokenDetails) ? outputTokenDetails["textTokens"] : void 0
|
|
3222
|
+
);
|
|
3223
|
+
const totalTokens = firstTokenCount(
|
|
3224
|
+
usage["totalTokens"],
|
|
3225
|
+
usage["tokens"],
|
|
3226
|
+
usage["total_tokens"],
|
|
3227
|
+
inputTokens !== void 0 && outputTokens !== void 0 ? inputTokens + outputTokens : void 0
|
|
3228
|
+
);
|
|
3229
|
+
return {
|
|
3230
|
+
inputTokens,
|
|
3231
|
+
outputTokens,
|
|
3232
|
+
totalTokens,
|
|
3233
|
+
nonCachedInputTokens,
|
|
3234
|
+
nonReasoningOutputTokens,
|
|
3235
|
+
reasoningTokens,
|
|
3236
|
+
cacheReadInputTokens,
|
|
3237
|
+
cachedInputTokens: cacheReadInputTokens,
|
|
3238
|
+
cacheWriteInputTokens,
|
|
3239
|
+
...hasStructuredUsage ? {} : flatUsageSemantics(provider)
|
|
3240
|
+
};
|
|
3241
|
+
}
|
|
3242
|
+
|
|
2271
3243
|
// src/internal/raindrop-telemetry-integration.ts
|
|
2272
3244
|
function hasUnresolvedToolApproval(event) {
|
|
2273
3245
|
var _a;
|
|
@@ -2340,6 +3312,7 @@ var RaindropTelemetryIntegration = class {
|
|
|
2340
3312
|
eventName: (_f = callMeta.eventName) != null ? _f : (_e = this.defaultContext) == null ? void 0 : _e.eventName
|
|
2341
3313
|
};
|
|
2342
3314
|
const inherited = getContextManager().getParentSpanIds();
|
|
3315
|
+
const handoff = readDetachedChildLink(metadata);
|
|
2343
3316
|
const eventIdGenerated = (metadata == null ? void 0 : metadata["raindrop.internal.eventIdGenerated"]) === "true" || (metadata == null ? void 0 : metadata["raindrop.internal.eventIdGenerated"]) === true || (callContextMetadata == null ? void 0 : callContextMetadata.eventIdGenerated) === true;
|
|
2344
3317
|
const explicitEventId = callMeta.eventId && !eventIdGenerated ? callMeta.eventId : void 0;
|
|
2345
3318
|
const eventId = (_j = (_i = (_h = explicitEventId != null ? explicitEventId : (_g = this.defaultContext) == null ? void 0 : _g.eventId) != null ? _h : inherited == null ? void 0 : inherited.eventId) != null ? _i : callMeta.eventId) != null ? _j : randomUUID();
|
|
@@ -2369,7 +3342,10 @@ var RaindropTelemetryIntegration = class {
|
|
|
2369
3342
|
attrString("ai.toolCall.name", subagentName),
|
|
2370
3343
|
attrString("raindrop.subagent.name", subagentName),
|
|
2371
3344
|
attrString("raindrop.agent.role", "subagent"),
|
|
2372
|
-
...parentAttrs
|
|
3345
|
+
...parentAttrs,
|
|
3346
|
+
// Top of this child's tree, so the reverse reference matters as much
|
|
3347
|
+
// here as on the root: these are the spans a reader lands on first.
|
|
3348
|
+
...handoffSpanAttrs(handoff)
|
|
2373
3349
|
]
|
|
2374
3350
|
});
|
|
2375
3351
|
const subagentParentRef = this.spanParentRef(subagentToolCallSpan);
|
|
@@ -2382,7 +3358,8 @@ var RaindropTelemetryIntegration = class {
|
|
|
2382
3358
|
attributes: [
|
|
2383
3359
|
attrString("operation.name", "agent.subagent"),
|
|
2384
3360
|
attrString("raindrop.span.kind", "llm_call"),
|
|
2385
|
-
attrString("raindrop.subagent.name", subagentName)
|
|
3361
|
+
attrString("raindrop.subagent.name", subagentName),
|
|
3362
|
+
...handoffSpanAttrs(handoff)
|
|
2386
3363
|
]
|
|
2387
3364
|
});
|
|
2388
3365
|
this.traceShipper.endSpan(markerSpan);
|
|
@@ -2437,6 +3414,8 @@ var RaindropTelemetryIntegration = class {
|
|
|
2437
3414
|
rootParent: rootSpan ? this.spanParentRef(rootSpan) : rootParentOverride != null ? rootParentOverride : inheritedParent,
|
|
2438
3415
|
stepSpan: void 0,
|
|
2439
3416
|
stepParent: void 0,
|
|
3417
|
+
stepProvider: void 0,
|
|
3418
|
+
stepModelId: void 0,
|
|
2440
3419
|
toolSpans: /* @__PURE__ */ new Map(),
|
|
2441
3420
|
embedSpans: /* @__PURE__ */ new Map(),
|
|
2442
3421
|
parentContextToolCallIds: /* @__PURE__ */ new Set(),
|
|
@@ -2448,7 +3427,9 @@ var RaindropTelemetryIntegration = class {
|
|
|
2448
3427
|
inputText: isEmbed ? void 0 : this.extractInputText(event),
|
|
2449
3428
|
toolCallCount: 0,
|
|
2450
3429
|
subagentName,
|
|
2451
|
-
subagentToolCallSpan
|
|
3430
|
+
subagentToolCallSpan,
|
|
3431
|
+
handoff,
|
|
3432
|
+
nestedInEvent: inheritedParent !== void 0
|
|
2452
3433
|
});
|
|
2453
3434
|
};
|
|
2454
3435
|
// ── onStepStart ─────────────────────────────────────────────────────────
|
|
@@ -2490,15 +3471,17 @@ var RaindropTelemetryIntegration = class {
|
|
|
2490
3471
|
attrString("operation.name", operationName),
|
|
2491
3472
|
attrString("resource.name", resourceName),
|
|
2492
3473
|
attrString("ai.telemetry.functionId", state.functionId),
|
|
2493
|
-
|
|
3474
|
+
...attrsFromModelProvider(event.provider),
|
|
2494
3475
|
attrString("ai.model.id", event.modelId),
|
|
2495
|
-
attrString(
|
|
2496
|
-
|
|
2497
|
-
...
|
|
3476
|
+
attrString(MODEL_USAGE_ATTRIBUTES.requestModel, event.modelId),
|
|
3477
|
+
...inputAttrs,
|
|
3478
|
+
...handoffSpanAttrs(state.handoff)
|
|
2498
3479
|
]
|
|
2499
3480
|
});
|
|
2500
3481
|
state.stepSpan = stepSpan;
|
|
2501
3482
|
state.stepParent = this.spanParentRef(stepSpan);
|
|
3483
|
+
state.stepProvider = event.provider;
|
|
3484
|
+
state.stepModelId = event.modelId;
|
|
2502
3485
|
};
|
|
2503
3486
|
this.onToolExecutionStart = (event) => this.toolExecutionStart(event);
|
|
2504
3487
|
this.onToolExecutionEnd = (event) => this.toolExecutionEnd(event);
|
|
@@ -2549,23 +3532,24 @@ var RaindropTelemetryIntegration = class {
|
|
|
2549
3532
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
2550
3533
|
const state = this.getState(event.callId);
|
|
2551
3534
|
if (!(state == null ? void 0 : state.stepSpan)) return;
|
|
3535
|
+
const responseModelId = (_b = (_a = event.response) == null ? void 0 : _a.modelId) != null ? _b : state.stepModelId;
|
|
2552
3536
|
const outputAttrs = [];
|
|
2553
3537
|
if (state.recordOutputs) {
|
|
2554
3538
|
outputAttrs.push(
|
|
2555
3539
|
attrString("ai.response.finishReason", event.finishReason),
|
|
2556
|
-
attrString("ai.response.text", capText2((
|
|
2557
|
-
attrString("ai.response.id", (
|
|
2558
|
-
attrString("ai.response.model",
|
|
3540
|
+
attrString("ai.response.text", capText2((_c = event.text) != null ? _c : void 0)),
|
|
3541
|
+
attrString("ai.response.id", (_d = event.response) == null ? void 0 : _d.id),
|
|
3542
|
+
attrString("ai.response.model", responseModelId),
|
|
2559
3543
|
attrString(
|
|
2560
3544
|
"ai.response.timestamp",
|
|
2561
|
-
((
|
|
3545
|
+
((_e = event.response) == null ? void 0 : _e.timestamp) instanceof Date ? event.response.timestamp.toISOString() : (_f = event.response) == null ? void 0 : _f.timestamp
|
|
2562
3546
|
),
|
|
2563
3547
|
attrString(
|
|
2564
3548
|
"ai.response.providerMetadata",
|
|
2565
3549
|
event.providerMetadata ? safeJsonWithUint8(event.providerMetadata) : void 0
|
|
2566
3550
|
)
|
|
2567
3551
|
);
|
|
2568
|
-
if (((
|
|
3552
|
+
if (((_g = event.toolCalls) == null ? void 0 : _g.length) > 0) {
|
|
2569
3553
|
outputAttrs.push(
|
|
2570
3554
|
attrString(
|
|
2571
3555
|
"ai.response.toolCalls",
|
|
@@ -2579,7 +3563,7 @@ var RaindropTelemetryIntegration = class {
|
|
|
2579
3563
|
)
|
|
2580
3564
|
);
|
|
2581
3565
|
}
|
|
2582
|
-
if (((
|
|
3566
|
+
if (((_h = event.reasoning) == null ? void 0 : _h.length) > 0) {
|
|
2583
3567
|
const reasoningText = event.reasoning.filter((part) => "text" in part).map((part) => part.text).join("\n");
|
|
2584
3568
|
if (reasoningText) {
|
|
2585
3569
|
outputAttrs.push(attrString("ai.response.reasoning", capText2(reasoningText)));
|
|
@@ -2588,25 +3572,31 @@ var RaindropTelemetryIntegration = class {
|
|
|
2588
3572
|
}
|
|
2589
3573
|
outputAttrs.push(
|
|
2590
3574
|
attrStringArray("gen_ai.response.finish_reasons", [event.finishReason]),
|
|
2591
|
-
attrString("gen_ai.response.id", (
|
|
2592
|
-
attrString(
|
|
3575
|
+
attrString("gen_ai.response.id", (_i = event.response) == null ? void 0 : _i.id),
|
|
3576
|
+
attrString(MODEL_USAGE_ATTRIBUTES.responseModel, responseModelId)
|
|
2593
3577
|
);
|
|
2594
3578
|
const usage = event.usage;
|
|
2595
3579
|
if (usage) {
|
|
3580
|
+
const usageMetrics = extractUsageMetricsFromUsage(
|
|
3581
|
+
usage,
|
|
3582
|
+
state.stepProvider,
|
|
3583
|
+
event.providerMetadata
|
|
3584
|
+
);
|
|
2596
3585
|
outputAttrs.push(
|
|
2597
|
-
attrInt("ai.usage.inputTokens",
|
|
2598
|
-
attrInt("ai.usage.outputTokens",
|
|
2599
|
-
attrInt("ai.usage.totalTokens",
|
|
2600
|
-
attrInt("ai.usage.reasoningTokens",
|
|
2601
|
-
attrInt("ai.usage.cachedInputTokens",
|
|
2602
|
-
|
|
2603
|
-
attrInt("gen_ai.usage.output_tokens", usage.outputTokens)
|
|
3586
|
+
attrInt("ai.usage.inputTokens", usageMetrics.inputTokens),
|
|
3587
|
+
attrInt("ai.usage.outputTokens", usageMetrics.outputTokens),
|
|
3588
|
+
attrInt("ai.usage.totalTokens", usageMetrics.totalTokens),
|
|
3589
|
+
attrInt("ai.usage.reasoningTokens", usageMetrics.reasoningTokens),
|
|
3590
|
+
attrInt("ai.usage.cachedInputTokens", usageMetrics.cachedInputTokens),
|
|
3591
|
+
...buildModelUsageAttributes(usageMetrics)
|
|
2604
3592
|
);
|
|
2605
3593
|
}
|
|
2606
3594
|
this.emitProviderExecutedToolSpans(event, state);
|
|
2607
3595
|
this.traceShipper.endSpan(state.stepSpan, { attributes: outputAttrs });
|
|
2608
3596
|
state.stepSpan = void 0;
|
|
2609
3597
|
state.stepParent = void 0;
|
|
3598
|
+
state.stepProvider = void 0;
|
|
3599
|
+
state.stepModelId = void 0;
|
|
2610
3600
|
};
|
|
2611
3601
|
// ── onEmbedStart ────────────────────────────────────────────────────────
|
|
2612
3602
|
this.onEmbedStart = (event) => {
|
|
@@ -2624,7 +3614,8 @@ var RaindropTelemetryIntegration = class {
|
|
|
2624
3614
|
attrString("operation.name", operationName),
|
|
2625
3615
|
attrString("resource.name", resourceName),
|
|
2626
3616
|
attrString("ai.telemetry.functionId", state.functionId),
|
|
2627
|
-
...inputAttrs
|
|
3617
|
+
...inputAttrs,
|
|
3618
|
+
...handoffSpanAttrs(state.handoff)
|
|
2628
3619
|
]
|
|
2629
3620
|
});
|
|
2630
3621
|
state.embedSpans.set(event.embedCallId, embedSpan);
|
|
@@ -2681,6 +3672,8 @@ var RaindropTelemetryIntegration = class {
|
|
|
2681
3672
|
const actualError = (_a = event.error) != null ? _a : error;
|
|
2682
3673
|
if (state.stepSpan) {
|
|
2683
3674
|
this.traceShipper.endSpan(state.stepSpan, { error: actualError });
|
|
3675
|
+
state.stepProvider = void 0;
|
|
3676
|
+
state.stepModelId = void 0;
|
|
2684
3677
|
}
|
|
2685
3678
|
for (const embedSpan of state.embedSpans.values()) {
|
|
2686
3679
|
this.traceShipper.endSpan(embedSpan, { error: actualError });
|
|
@@ -2694,15 +3687,26 @@ var RaindropTelemetryIntegration = class {
|
|
|
2694
3687
|
this.traceShipper.endSpan(toolSpan, { error: actualError });
|
|
2695
3688
|
}
|
|
2696
3689
|
state.toolSpans.clear();
|
|
3690
|
+
const abortReason = describeAbortReason(actualError);
|
|
2697
3691
|
if (state.rootSpan) {
|
|
2698
|
-
this.traceShipper.endSpan(state.rootSpan, {
|
|
3692
|
+
this.traceShipper.endSpan(state.rootSpan, {
|
|
3693
|
+
error: actualError,
|
|
3694
|
+
attributes: this.abortOutcomeAttrs(state, abortReason, "error")
|
|
3695
|
+
});
|
|
2699
3696
|
}
|
|
2700
3697
|
if (state.subagentToolCallSpan) {
|
|
2701
3698
|
this.traceShipper.endSpan(state.subagentToolCallSpan, { error: actualError });
|
|
2702
3699
|
}
|
|
2703
3700
|
const isEmbed = state.operationId === "ai.embed" || state.operationId === "ai.embedMany";
|
|
2704
3701
|
if (!isEmbed) {
|
|
2705
|
-
|
|
3702
|
+
const errorIsTheRunsOutcome = state.handoff !== void 0 && !state.nestedInEvent;
|
|
3703
|
+
this.finalizeGenerateEvent(
|
|
3704
|
+
state,
|
|
3705
|
+
state.accumulatedText || void 0,
|
|
3706
|
+
void 0,
|
|
3707
|
+
false,
|
|
3708
|
+
errorIsTheRunsOutcome ? { fallbackOutput: abortReason } : void 0
|
|
3709
|
+
);
|
|
2706
3710
|
}
|
|
2707
3711
|
this.cleanup(event.callId);
|
|
2708
3712
|
};
|
|
@@ -2724,6 +3728,8 @@ var RaindropTelemetryIntegration = class {
|
|
|
2724
3728
|
this.traceShipper.endSpan(state.stepSpan, { attributes: [abortedAttr] });
|
|
2725
3729
|
state.stepSpan = void 0;
|
|
2726
3730
|
state.stepParent = void 0;
|
|
3731
|
+
state.stepProvider = void 0;
|
|
3732
|
+
state.stepModelId = void 0;
|
|
2727
3733
|
}
|
|
2728
3734
|
for (const embedSpan of state.embedSpans.values()) {
|
|
2729
3735
|
this.traceShipper.endSpan(embedSpan, { attributes: [abortedAttr] });
|
|
@@ -2737,9 +3743,19 @@ var RaindropTelemetryIntegration = class {
|
|
|
2737
3743
|
this.traceShipper.endSpan(toolSpan, { attributes: [abortedAttr] });
|
|
2738
3744
|
}
|
|
2739
3745
|
state.toolSpans.clear();
|
|
3746
|
+
const abortIsTheRunsOutcome = state.handoff !== void 0 && !state.nestedInEvent;
|
|
2740
3747
|
if (state.rootSpan) {
|
|
2741
3748
|
this.traceShipper.endSpan(state.rootSpan, {
|
|
2742
|
-
attributes: [
|
|
3749
|
+
attributes: [
|
|
3750
|
+
abortedAttr,
|
|
3751
|
+
attrInt("ai.toolCall.count", state.toolCallCount),
|
|
3752
|
+
// An aborted detached child IS a cancelled sub-agent, and a cancelled
|
|
3753
|
+
// run is span-for-span identical to a finished one — spans close,
|
|
3754
|
+
// nothing errors, there is just no answer. So it is the one outcome
|
|
3755
|
+
// that has to be stated, and the child states it on itself.
|
|
3756
|
+
...abortIsTheRunsOutcome ? cancelledSpanAttrs() : [],
|
|
3757
|
+
...abortIsTheRunsOutcome ? this.abortOutcomeAttrs(state, SUBAGENT_CANCELLED_OUTPUT, "stop") : []
|
|
3758
|
+
]
|
|
2743
3759
|
});
|
|
2744
3760
|
}
|
|
2745
3761
|
if (state.subagentToolCallSpan) {
|
|
@@ -2747,7 +3763,17 @@ var RaindropTelemetryIntegration = class {
|
|
|
2747
3763
|
attributes: [abortedAttr]
|
|
2748
3764
|
});
|
|
2749
3765
|
}
|
|
2750
|
-
this.finalizeGenerateEvent(
|
|
3766
|
+
this.finalizeGenerateEvent(
|
|
3767
|
+
state,
|
|
3768
|
+
state.accumulatedText || void 0,
|
|
3769
|
+
void 0,
|
|
3770
|
+
false,
|
|
3771
|
+
abortIsTheRunsOutcome ? {
|
|
3772
|
+
fallbackOutput: SUBAGENT_CANCELLED_OUTPUT,
|
|
3773
|
+
properties: { [HANDOFF_TERMINAL_PROPERTY_KEY]: HANDOFF_TERMINAL_CANCELLED }
|
|
3774
|
+
} : void 0
|
|
3775
|
+
);
|
|
3776
|
+
if (abortIsTheRunsOutcome) this.subagents.noteSettled(state.eventId);
|
|
2751
3777
|
this.cleanup(callId);
|
|
2752
3778
|
};
|
|
2753
3779
|
// ── executeTool ─────────────────────────────────────────────────────────
|
|
@@ -2775,6 +3801,97 @@ var RaindropTelemetryIntegration = class {
|
|
|
2775
3801
|
this.subagentWrapping = opts.subagentWrapping !== false;
|
|
2776
3802
|
this.debug = opts.debug === true;
|
|
2777
3803
|
this.defaultContext = opts.context;
|
|
3804
|
+
this.subagents = new SubagentApi({
|
|
3805
|
+
traceShipper: this.traceShipper,
|
|
3806
|
+
eventShipper: this.eventShipper,
|
|
3807
|
+
sendTraces: this.sendTraces,
|
|
3808
|
+
sendEvents: this.sendEvents,
|
|
3809
|
+
debug: this.debug,
|
|
3810
|
+
defaultContext: this.defaultContext,
|
|
3811
|
+
settledEventIds: opts.settledEventIds,
|
|
3812
|
+
spanSource: {
|
|
3813
|
+
activeDispatch: () => this.activeDispatch(),
|
|
3814
|
+
openSpansForEvent: (eventId) => this.openSpansForEvent(eventId)
|
|
3815
|
+
}
|
|
3816
|
+
});
|
|
3817
|
+
}
|
|
3818
|
+
/**
|
|
3819
|
+
* Record a detached sub-agent on the turn that is live right now.
|
|
3820
|
+
*
|
|
3821
|
+
* Returns the dispatch — the child's event id and the headers to send with
|
|
3822
|
+
* the job. Dispatching is still yours to do; this only states that you are
|
|
3823
|
+
* about to, so a reader can follow the link before the child exists.
|
|
3824
|
+
*/
|
|
3825
|
+
subagent(options = {}) {
|
|
3826
|
+
return this.subagents.subagent(options);
|
|
3827
|
+
}
|
|
3828
|
+
// ── detached sub-agent hand-offs ─────────────────────────────────────────
|
|
3829
|
+
/**
|
|
3830
|
+
* The turn a `subagent()` dispatch is happening inside.
|
|
3831
|
+
*
|
|
3832
|
+
* Resolved from the parent-tool context first, which is the only way to reach
|
|
3833
|
+
* the EXACT span that dispatched: the tool call the model itself issued, still
|
|
3834
|
+
* open while its `execute` runs. Falling back to the event id lets a launch
|
|
3835
|
+
* from elsewhere in the turn (a queue producer called mid-generation) still
|
|
3836
|
+
* find the turn's spans, which is where the tool-events opt-in has to land.
|
|
3837
|
+
*/
|
|
3838
|
+
activeDispatch() {
|
|
3839
|
+
var _a;
|
|
3840
|
+
const parentTool = getCurrentParentToolContext();
|
|
3841
|
+
let state = parentTool ? this.getState(parentTool.parentCallId) : void 0;
|
|
3842
|
+
const inheritedEventId = (_a = getContextManager().getParentSpanIds()) == null ? void 0 : _a.eventId;
|
|
3843
|
+
if (!state && inheritedEventId) {
|
|
3844
|
+
for (const candidate of this.callStates.values()) {
|
|
3845
|
+
if (candidate.eventId === inheritedEventId) {
|
|
3846
|
+
state = candidate;
|
|
3847
|
+
break;
|
|
3848
|
+
}
|
|
3849
|
+
}
|
|
3850
|
+
}
|
|
3851
|
+
if (!state) return void 0;
|
|
3852
|
+
return {
|
|
3853
|
+
eventId: state.eventId,
|
|
3854
|
+
userId: state.identity.userId,
|
|
3855
|
+
convoId: state.identity.convoId,
|
|
3856
|
+
dispatchSpan: parentTool ? state.toolSpans.get(parentTool.toolCallId) : void 0,
|
|
3857
|
+
turnSpans: [state.rootSpan, state.stepSpan].filter(
|
|
3858
|
+
(span) => span !== void 0
|
|
3859
|
+
),
|
|
3860
|
+
recordInputs: state.recordInputs
|
|
3861
|
+
};
|
|
3862
|
+
}
|
|
3863
|
+
/** Spans still open for an event, so a late outcome can still be stated. */
|
|
3864
|
+
openSpansForEvent(eventId) {
|
|
3865
|
+
const spans = [];
|
|
3866
|
+
for (const state of this.callStates.values()) {
|
|
3867
|
+
if (state.eventId !== eventId) continue;
|
|
3868
|
+
if (state.rootSpan) spans.push(state.rootSpan);
|
|
3869
|
+
if (state.stepSpan) spans.push(state.stepSpan);
|
|
3870
|
+
}
|
|
3871
|
+
return spans;
|
|
3872
|
+
}
|
|
3873
|
+
/**
|
|
3874
|
+
* End-attributes that keep a detached child legible when it ends without an
|
|
3875
|
+
* answer — an error, an abort, a cancellation.
|
|
3876
|
+
*
|
|
3877
|
+
* An event is created from an LLM span only when it has a finish reason and
|
|
3878
|
+
* non-empty output, so a child that dies silently produces NO event, and the
|
|
3879
|
+
* caller's hand-off pill stays on `queued` forever — indistinguishable from a
|
|
3880
|
+
* job that never started. Reporting the abort reason as the run's output is
|
|
3881
|
+
* what makes the outcome visible. Only detached children get this: an inline
|
|
3882
|
+
* generation's failure is already legible from its caller's own event.
|
|
3883
|
+
*
|
|
3884
|
+
* And only the run's OUTERMOST generation gets it (see `nestedInEvent`): an
|
|
3885
|
+
* inner sub-call ending badly is not the run ending, and since an event is
|
|
3886
|
+
* created from an LLM span with output, `ai.response.text` here would state
|
|
3887
|
+
* the run's outcome through the span while the turn is still working.
|
|
3888
|
+
*/
|
|
3889
|
+
abortOutcomeAttrs(state, reason, finishReason) {
|
|
3890
|
+
if (!state.handoff || state.nestedInEvent) return [];
|
|
3891
|
+
return [
|
|
3892
|
+
attrString("ai.response.text", capText2(state.accumulatedText || reason)),
|
|
3893
|
+
attrString("ai.response.finishReason", finishReason)
|
|
3894
|
+
];
|
|
2778
3895
|
}
|
|
2779
3896
|
// ── helpers ──────────────────────────────────────────────────────────────
|
|
2780
3897
|
getState(callId) {
|
|
@@ -2893,7 +4010,8 @@ var RaindropTelemetryIntegration = class {
|
|
|
2893
4010
|
attrString("ai.telemetry.functionId", state.functionId),
|
|
2894
4011
|
attrString("ai.toolCall.name", toolCall.toolName),
|
|
2895
4012
|
attrString("ai.toolCall.id", toolCall.toolCallId),
|
|
2896
|
-
...inputAttrs
|
|
4013
|
+
...inputAttrs,
|
|
4014
|
+
...handoffSpanAttrs(state.handoff)
|
|
2897
4015
|
]
|
|
2898
4016
|
});
|
|
2899
4017
|
state.toolSpans.set(toolCall.toolCallId, toolSpan);
|
|
@@ -2972,7 +4090,8 @@ var RaindropTelemetryIntegration = class {
|
|
|
2972
4090
|
attrString("ai.toolCall.name", call.toolName),
|
|
2973
4091
|
attrString("ai.toolCall.id", call.toolCallId),
|
|
2974
4092
|
attrString("ai.toolCall.providerExecuted", "true"),
|
|
2975
|
-
...inputAttrs
|
|
4093
|
+
...inputAttrs,
|
|
4094
|
+
...handoffSpanAttrs(state.handoff)
|
|
2976
4095
|
]
|
|
2977
4096
|
});
|
|
2978
4097
|
state.toolCallCount += 1;
|
|
@@ -3023,12 +4142,13 @@ var RaindropTelemetryIntegration = class {
|
|
|
3023
4142
|
}
|
|
3024
4143
|
const usage = (_d = event.totalUsage) != null ? _d : event.usage;
|
|
3025
4144
|
if (usage) {
|
|
4145
|
+
const usageMetrics = extractUsageMetricsFromUsage(usage);
|
|
3026
4146
|
outputAttrs.push(
|
|
3027
|
-
attrInt("ai.usage.inputTokens",
|
|
3028
|
-
attrInt("ai.usage.outputTokens",
|
|
3029
|
-
attrInt("ai.usage.totalTokens",
|
|
3030
|
-
attrInt("ai.usage.reasoningTokens",
|
|
3031
|
-
attrInt("ai.usage.cachedInputTokens",
|
|
4147
|
+
attrInt("ai.usage.inputTokens", usageMetrics.inputTokens),
|
|
4148
|
+
attrInt("ai.usage.outputTokens", usageMetrics.outputTokens),
|
|
4149
|
+
attrInt("ai.usage.totalTokens", usageMetrics.totalTokens),
|
|
4150
|
+
attrInt("ai.usage.reasoningTokens", usageMetrics.reasoningTokens),
|
|
4151
|
+
attrInt("ai.usage.cachedInputTokens", usageMetrics.cachedInputTokens)
|
|
3032
4152
|
);
|
|
3033
4153
|
}
|
|
3034
4154
|
outputAttrs.push(attrInt("ai.toolCall.count", state.toolCallCount));
|
|
@@ -3052,19 +4172,22 @@ var RaindropTelemetryIntegration = class {
|
|
|
3052
4172
|
* is finalized by that resume — otherwise each execution would finalize the
|
|
3053
4173
|
* same event ID into a separate canonical row.
|
|
3054
4174
|
*/
|
|
3055
|
-
finalizeGenerateEvent(state, output, model, keepPending = false) {
|
|
4175
|
+
finalizeGenerateEvent(state, output, model, keepPending = false, detachedOutcome) {
|
|
3056
4176
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
3057
4177
|
const suppressSubagentEvent = state.subagentName !== void 0 && state.subagentToolCallSpan !== void 0;
|
|
3058
4178
|
if (!this.sendEvents || suppressSubagentEvent) return;
|
|
4179
|
+
if (this.subagents.wasSettledExplicitly(state.eventId)) return;
|
|
3059
4180
|
const callMeta = this.extractRaindropMetadata(state.metadata);
|
|
3060
4181
|
const userId = (_b = callMeta.userId) != null ? _b : (_a = this.defaultContext) == null ? void 0 : _a.userId;
|
|
3061
4182
|
if (!userId) return;
|
|
3062
4183
|
const eventName = (_e = (_d = callMeta.eventName) != null ? _d : (_c = this.defaultContext) == null ? void 0 : _c.eventName) != null ? _e : state.operationId;
|
|
3063
4184
|
const cappedOutput = capText2(output);
|
|
4185
|
+
const reportedOutput = state.handoff && detachedOutcome && !(cappedOutput == null ? void 0 : cappedOutput.trim()) ? detachedOutcome.fallbackOutput : cappedOutput;
|
|
3064
4186
|
const input = capText2(state.inputText);
|
|
3065
4187
|
const properties = {
|
|
3066
4188
|
...(_f = this.defaultContext) == null ? void 0 : _f.properties,
|
|
3067
|
-
...callMeta.properties
|
|
4189
|
+
...callMeta.properties,
|
|
4190
|
+
...state.handoff ? detachedOutcome == null ? void 0 : detachedOutcome.properties : void 0
|
|
3068
4191
|
};
|
|
3069
4192
|
const featureFlags = {
|
|
3070
4193
|
...((_g = this.defaultContext) == null ? void 0 : _g.featureFlags) ? normalizeFeatureFlags(this.defaultContext.featureFlags) : {},
|
|
@@ -3076,7 +4199,7 @@ var RaindropTelemetryIntegration = class {
|
|
|
3076
4199
|
userId,
|
|
3077
4200
|
convoId,
|
|
3078
4201
|
input,
|
|
3079
|
-
output:
|
|
4202
|
+
output: reportedOutput,
|
|
3080
4203
|
model,
|
|
3081
4204
|
properties: Object.keys(properties).length > 0 ? properties : void 0,
|
|
3082
4205
|
featureFlags: Object.keys(featureFlags).length > 0 ? featureFlags : void 0,
|
|
@@ -3481,14 +4604,6 @@ function runWithParentSpanContextSync(ctx, fn) {
|
|
|
3481
4604
|
function isAsyncIterable(value) {
|
|
3482
4605
|
return value !== null && typeof value === "object" && Symbol.asyncIterator in value;
|
|
3483
4606
|
}
|
|
3484
|
-
function firstFiniteNumber(...values) {
|
|
3485
|
-
for (const value of values) {
|
|
3486
|
-
if (typeof value === "number" && Number.isFinite(value)) {
|
|
3487
|
-
return value;
|
|
3488
|
-
}
|
|
3489
|
-
}
|
|
3490
|
-
return void 0;
|
|
3491
|
-
}
|
|
3492
4607
|
function resolveUsageRecord(result) {
|
|
3493
4608
|
if (!isRecord(result)) return void 0;
|
|
3494
4609
|
let usage;
|
|
@@ -3504,50 +4619,7 @@ function resolveUsageRecord(result) {
|
|
|
3504
4619
|
return isRecord(usage) ? usage : void 0;
|
|
3505
4620
|
}
|
|
3506
4621
|
function extractUsageMetrics(result) {
|
|
3507
|
-
|
|
3508
|
-
if (!usage) return {};
|
|
3509
|
-
const inputTokenValue = usage["inputTokens"];
|
|
3510
|
-
const outputTokenValue = usage["outputTokens"];
|
|
3511
|
-
const inputTokens = firstFiniteNumber(
|
|
3512
|
-
isRecord(inputTokenValue) ? inputTokenValue["total"] : void 0,
|
|
3513
|
-
inputTokenValue,
|
|
3514
|
-
usage["promptTokens"],
|
|
3515
|
-
usage["prompt_tokens"]
|
|
3516
|
-
);
|
|
3517
|
-
const outputTokens = firstFiniteNumber(
|
|
3518
|
-
isRecord(outputTokenValue) ? outputTokenValue["total"] : void 0,
|
|
3519
|
-
outputTokenValue,
|
|
3520
|
-
usage["completionTokens"],
|
|
3521
|
-
usage["completion_tokens"]
|
|
3522
|
-
);
|
|
3523
|
-
const totalTokens = firstFiniteNumber(
|
|
3524
|
-
usage["totalTokens"],
|
|
3525
|
-
usage["tokens"],
|
|
3526
|
-
usage["total_tokens"],
|
|
3527
|
-
inputTokens !== void 0 && outputTokens !== void 0 ? inputTokens + outputTokens : void 0
|
|
3528
|
-
);
|
|
3529
|
-
const reasoningTokens = firstFiniteNumber(
|
|
3530
|
-
isRecord(outputTokenValue) ? outputTokenValue["reasoning"] : void 0,
|
|
3531
|
-
usage["reasoningTokens"],
|
|
3532
|
-
usage["completionReasoningTokens"],
|
|
3533
|
-
usage["completion_reasoning_tokens"],
|
|
3534
|
-
usage["reasoning_tokens"],
|
|
3535
|
-
usage["thinkingTokens"],
|
|
3536
|
-
usage["thinking_tokens"]
|
|
3537
|
-
);
|
|
3538
|
-
const cachedInputTokens = firstFiniteNumber(
|
|
3539
|
-
isRecord(inputTokenValue) ? inputTokenValue["cacheRead"] : void 0,
|
|
3540
|
-
usage["cachedInputTokens"],
|
|
3541
|
-
usage["promptCachedTokens"],
|
|
3542
|
-
usage["prompt_cached_tokens"]
|
|
3543
|
-
);
|
|
3544
|
-
return {
|
|
3545
|
-
inputTokens,
|
|
3546
|
-
outputTokens,
|
|
3547
|
-
totalTokens,
|
|
3548
|
-
reasoningTokens,
|
|
3549
|
-
cachedInputTokens
|
|
3550
|
-
};
|
|
4622
|
+
return extractUsageMetricsFromUsage(resolveUsageRecord(result));
|
|
3551
4623
|
}
|
|
3552
4624
|
function isObjectOperation(operation) {
|
|
3553
4625
|
return operation === "generateObject" || operation === "streamObject";
|
|
@@ -4039,6 +5111,7 @@ function wrapAISDK(aiSDK, deps) {
|
|
|
4039
5111
|
sendTraces: ((_a = deps.options.send) == null ? void 0 : _a.traces) !== false,
|
|
4040
5112
|
sendEvents: ((_b = deps.options.send) == null ? void 0 : _b.events) !== false,
|
|
4041
5113
|
debug,
|
|
5114
|
+
settledEventIds: deps.settledEventIds,
|
|
4042
5115
|
context: {
|
|
4043
5116
|
userId: wrapTimeCtx.userId,
|
|
4044
5117
|
eventId: wrapTimeCtx.eventId,
|
|
@@ -4938,8 +6011,13 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
|
|
|
4938
6011
|
ended = true;
|
|
4939
6012
|
const msToFirstChunk = firstChunkMs !== void 0 ? firstChunkMs - startMs : void 0;
|
|
4940
6013
|
const msToFinish = finishMs !== void 0 ? finishMs - startMs : void 0;
|
|
4941
|
-
const
|
|
4942
|
-
|
|
6014
|
+
const usageMetrics = extractUsageMetricsFromUsage(
|
|
6015
|
+
usage,
|
|
6016
|
+
modelInfo.provider,
|
|
6017
|
+
providerMetadata
|
|
6018
|
+
);
|
|
6019
|
+
const finalResponseModelId = responseModelId != null ? responseModelId : modelInfo.modelId;
|
|
6020
|
+
const { inputTokens, outputTokens } = usageMetrics;
|
|
4943
6021
|
const avgOutTokensPerSecond = msToFinish && outputTokens !== void 0 && msToFinish > 0 ? 1e3 * outputTokens / msToFinish : void 0;
|
|
4944
6022
|
ctx.traceShipper.endSpan(span, {
|
|
4945
6023
|
attributes: [
|
|
@@ -4951,7 +6029,7 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
|
|
|
4951
6029
|
safeJsonWithUint8(toolCallsLocal.length ? toolCallsLocal : void 0)
|
|
4952
6030
|
),
|
|
4953
6031
|
attrString("ai.response.id", responseId),
|
|
4954
|
-
attrString("ai.response.model",
|
|
6032
|
+
attrString("ai.response.model", finalResponseModelId),
|
|
4955
6033
|
attrString("ai.response.timestamp", responseTimestampIso),
|
|
4956
6034
|
attrString(
|
|
4957
6035
|
"ai.response.providerMetadata",
|
|
@@ -4962,9 +6040,8 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
|
|
|
4962
6040
|
attrInt("ai.usage.outputTokens", outputTokens),
|
|
4963
6041
|
...finishReason ? [attrStringArray("gen_ai.response.finish_reasons", [finishReason])] : [],
|
|
4964
6042
|
attrString("gen_ai.response.id", responseId),
|
|
4965
|
-
attrString(
|
|
4966
|
-
|
|
4967
|
-
attrInt("gen_ai.usage.output_tokens", outputTokens),
|
|
6043
|
+
attrString(MODEL_USAGE_ATTRIBUTES.responseModel, finalResponseModelId),
|
|
6044
|
+
...buildModelUsageAttributes(usageMetrics),
|
|
4968
6045
|
...msToFirstChunk !== void 0 ? [attrInt("ai.stream.msToFirstChunk", msToFirstChunk)] : [],
|
|
4969
6046
|
...msToFinish !== void 0 ? [attrInt("ai.stream.msToFinish", msToFinish)] : [],
|
|
4970
6047
|
...avgOutTokensPerSecond !== void 0 ? [attrDouble("ai.stream.avgOutputTokensPerSecond", avgOutTokensPerSecond)] : [],
|
|
@@ -5070,15 +6147,14 @@ function startDoGenerateSpan(operationId, options, modelInfo, parent, ctx) {
|
|
|
5070
6147
|
attrString("operation.name", operationName),
|
|
5071
6148
|
attrString("resource.name", resourceName),
|
|
5072
6149
|
attrString("ai.telemetry.functionId", (_b = ctx.telemetry) == null ? void 0 : _b.functionId),
|
|
5073
|
-
|
|
6150
|
+
...attrsFromModelProvider(modelInfo.provider),
|
|
5074
6151
|
attrString("ai.model.id", modelInfo.modelId),
|
|
5075
6152
|
...((_c = ctx.telemetry) == null ? void 0 : _c.recordInputs) === false ? [] : [
|
|
5076
6153
|
attrString("ai.prompt.messages", promptJson),
|
|
5077
6154
|
attrStringArray("ai.prompt.tools", toolsJson),
|
|
5078
6155
|
attrString("ai.prompt.toolChoice", toolChoiceJson)
|
|
5079
6156
|
],
|
|
5080
|
-
attrString(
|
|
5081
|
-
attrString("gen_ai.request.model", modelInfo.modelId),
|
|
6157
|
+
attrString(MODEL_USAGE_ATTRIBUTES.requestModel, modelInfo.modelId),
|
|
5082
6158
|
...attrsFromGenAiRequest(options),
|
|
5083
6159
|
attrProviderOptions(options)
|
|
5084
6160
|
]
|
|
@@ -5111,8 +6187,12 @@ function endDoGenerateSpan(span, result, modelInfo, ctx) {
|
|
|
5111
6187
|
} else {
|
|
5112
6188
|
responseTimestampIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
5113
6189
|
}
|
|
5114
|
-
const
|
|
5115
|
-
|
|
6190
|
+
const usageMetrics = extractUsageMetricsFromUsage(
|
|
6191
|
+
usage,
|
|
6192
|
+
modelInfo.provider,
|
|
6193
|
+
providerMetadata
|
|
6194
|
+
);
|
|
6195
|
+
const { inputTokens, outputTokens } = usageMetrics;
|
|
5116
6196
|
ctx.traceShipper.endSpan(span, {
|
|
5117
6197
|
attributes: [
|
|
5118
6198
|
...((_a = ctx.telemetry) == null ? void 0 : _a.recordOutputs) === false ? [] : [
|
|
@@ -5131,9 +6211,8 @@ function endDoGenerateSpan(span, result, modelInfo, ctx) {
|
|
|
5131
6211
|
attrInt("ai.usage.completionTokens", outputTokens),
|
|
5132
6212
|
...finishReason ? [attrStringArray("gen_ai.response.finish_reasons", [finishReason])] : [],
|
|
5133
6213
|
attrString("gen_ai.response.id", responseId),
|
|
5134
|
-
attrString(
|
|
5135
|
-
|
|
5136
|
-
attrInt("gen_ai.usage.output_tokens", outputTokens)
|
|
6214
|
+
attrString(MODEL_USAGE_ATTRIBUTES.responseModel, responseModelId),
|
|
6215
|
+
...buildModelUsageAttributes(usageMetrics)
|
|
5137
6216
|
]
|
|
5138
6217
|
});
|
|
5139
6218
|
}
|
|
@@ -5154,15 +6233,14 @@ function startDoStreamSpan(operationId, options, modelInfo, parent, ctx) {
|
|
|
5154
6233
|
attrString("operation.name", operationName),
|
|
5155
6234
|
attrString("resource.name", resourceName),
|
|
5156
6235
|
attrString("ai.telemetry.functionId", (_b = ctx.telemetry) == null ? void 0 : _b.functionId),
|
|
5157
|
-
|
|
6236
|
+
...attrsFromModelProvider(modelInfo.provider),
|
|
5158
6237
|
attrString("ai.model.id", modelInfo.modelId),
|
|
5159
6238
|
...((_c = ctx.telemetry) == null ? void 0 : _c.recordInputs) === false ? [] : [
|
|
5160
6239
|
attrString("ai.prompt.messages", promptJson),
|
|
5161
6240
|
attrStringArray("ai.prompt.tools", toolsJson),
|
|
5162
6241
|
attrString("ai.prompt.toolChoice", toolChoiceJson)
|
|
5163
6242
|
],
|
|
5164
|
-
attrString(
|
|
5165
|
-
attrString("gen_ai.request.model", modelInfo.modelId),
|
|
6243
|
+
attrString(MODEL_USAGE_ATTRIBUTES.requestModel, modelInfo.modelId),
|
|
5166
6244
|
...attrsFromGenAiRequest(options),
|
|
5167
6245
|
attrProviderOptions(options)
|
|
5168
6246
|
]
|
|
@@ -5227,13 +6305,6 @@ function mergeAttachments(...groups) {
|
|
|
5227
6305
|
}
|
|
5228
6306
|
return merged.length ? merged : void 0;
|
|
5229
6307
|
}
|
|
5230
|
-
function extractNestedTokens(usage, key) {
|
|
5231
|
-
if (!isRecord(usage)) return void 0;
|
|
5232
|
-
const val = usage[key];
|
|
5233
|
-
if (typeof val === "number") return val;
|
|
5234
|
-
if (isRecord(val) && typeof val["total"] === "number") return val["total"];
|
|
5235
|
-
return void 0;
|
|
5236
|
-
}
|
|
5237
6308
|
|
|
5238
6309
|
// src/index.ts
|
|
5239
6310
|
function eventMetadata(options) {
|
|
@@ -5250,6 +6321,8 @@ function eventMetadata(options) {
|
|
|
5250
6321
|
if (options.properties) result["raindrop.properties"] = JSON.stringify(options.properties);
|
|
5251
6322
|
if (options.featureFlags)
|
|
5252
6323
|
result["raindrop.featureFlags"] = JSON.stringify(normalizeFeatureFlags(options.featureFlags));
|
|
6324
|
+
if (options.subagent) Object.assign(result, detachedChildMetadata(options.subagent));
|
|
6325
|
+
if (options.toolEvents) result[TOOL_EVENTS_SUFFIX] = options.toolEvents;
|
|
5253
6326
|
return result;
|
|
5254
6327
|
}
|
|
5255
6328
|
function deriveChatTurnMessageId(request) {
|
|
@@ -5332,12 +6405,22 @@ function createRaindropAISDK(opts) {
|
|
|
5332
6405
|
transformSpan: (_j = opts.traces) == null ? void 0 : _j.transformSpan,
|
|
5333
6406
|
disableDefaultRedaction: (_k = opts.traces) == null ? void 0 : _k.disableDefaultRedaction
|
|
5334
6407
|
});
|
|
6408
|
+
const settledEventIds = /* @__PURE__ */ new Set();
|
|
6409
|
+
const subagentApi = new SubagentApi({
|
|
6410
|
+
traceShipper,
|
|
6411
|
+
eventShipper,
|
|
6412
|
+
sendTraces: tracesEnabled,
|
|
6413
|
+
sendEvents: eventsEnabled,
|
|
6414
|
+
debug: envDebug,
|
|
6415
|
+
settledEventIds
|
|
6416
|
+
});
|
|
5335
6417
|
return {
|
|
5336
6418
|
wrap(aiSDK, options) {
|
|
5337
6419
|
return wrapAISDK(aiSDK, {
|
|
5338
6420
|
options: options != null ? options : {},
|
|
5339
6421
|
eventShipper,
|
|
5340
|
-
traceShipper
|
|
6422
|
+
traceShipper,
|
|
6423
|
+
settledEventIds
|
|
5341
6424
|
});
|
|
5342
6425
|
},
|
|
5343
6426
|
createSelfDiagnosticsTool(options = {}) {
|
|
@@ -5374,9 +6457,14 @@ function createRaindropAISDK(opts) {
|
|
|
5374
6457
|
sendEvents: eventsEnabled,
|
|
5375
6458
|
subagentWrapping,
|
|
5376
6459
|
debug: envDebug,
|
|
6460
|
+
settledEventIds,
|
|
5377
6461
|
context
|
|
5378
6462
|
});
|
|
5379
6463
|
},
|
|
6464
|
+
subagents: subagentApi,
|
|
6465
|
+
subagent(options = {}) {
|
|
6466
|
+
return subagentApi.subagent(options);
|
|
6467
|
+
},
|
|
5380
6468
|
events: {
|
|
5381
6469
|
async patch(eventId, patch) {
|
|
5382
6470
|
await eventShipper.patch(eventId, patch);
|
|
@@ -5502,8 +6590,17 @@ globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = async_hooks.AsyncLocalStorage;
|
|
|
5502
6590
|
exports.DEFAULT_MAX_TEXT_FIELD_CHARS = DEFAULT_MAX_TEXT_FIELD_CHARS2;
|
|
5503
6591
|
exports.DEFAULT_REDACT_ATTRIBUTE_KEYS = DEFAULT_REDACT_ATTRIBUTE_KEYS;
|
|
5504
6592
|
exports.DEFAULT_SECRET_KEY_NAMES = DEFAULT_SECRET_KEY_NAMES;
|
|
6593
|
+
exports.DETACHED_MODE = DETACHED_MODE;
|
|
6594
|
+
exports.HANDOFF_ATTRIBUTE_PREFIXES = HANDOFF_ATTRIBUTE_PREFIXES;
|
|
6595
|
+
exports.HANDOFF_ATTRIBUTE_SUFFIXES = HANDOFF_ATTRIBUTE_SUFFIXES;
|
|
6596
|
+
exports.HANDOFF_TERMINAL_CANCELLED = HANDOFF_TERMINAL_CANCELLED;
|
|
6597
|
+
exports.HANDOFF_TERMINAL_PROPERTY_KEY = HANDOFF_TERMINAL_PROPERTY_KEY;
|
|
5505
6598
|
exports.REDACTED_PLACEHOLDER = REDACTED_PLACEHOLDER;
|
|
5506
6599
|
exports.RaindropTelemetryIntegration = RaindropTelemetryIntegration;
|
|
6600
|
+
exports.SUBAGENT_ABORTED_OUTPUT = SUBAGENT_ABORTED_OUTPUT;
|
|
6601
|
+
exports.SUBAGENT_AGENT_ROLE = SUBAGENT_AGENT_ROLE;
|
|
6602
|
+
exports.SUBAGENT_CANCELLED_OUTPUT = SUBAGENT_CANCELLED_OUTPUT;
|
|
6603
|
+
exports.TOOL_EVENTS_ALLOW = TOOL_EVENTS_ALLOW;
|
|
5507
6604
|
exports.TRUNCATION_MARKER = TRUNCATION_MARKER2;
|
|
5508
6605
|
exports._resetParentToolContextStorage = _resetParentToolContextStorage;
|
|
5509
6606
|
exports._resetRaindropCallMetadataStorage = _resetRaindropCallMetadataStorage;
|
|
@@ -5517,6 +6614,7 @@ exports.defaultTransformSpan = defaultTransformSpan;
|
|
|
5517
6614
|
exports.enterParentToolContext = enterParentToolContext;
|
|
5518
6615
|
exports.eventMetadata = eventMetadata;
|
|
5519
6616
|
exports.eventMetadataFromChatRequest = eventMetadataFromChatRequest;
|
|
6617
|
+
exports.fromHeaders = fromHeaders;
|
|
5520
6618
|
exports.getContextManager = getContextManager;
|
|
5521
6619
|
exports.getCurrentParentToolContext = getCurrentParentToolContext;
|
|
5522
6620
|
exports.getCurrentRaindropCallMetadata = getCurrentRaindropCallMetadata;
|
|
@@ -5525,6 +6623,9 @@ exports.raindrop = raindrop;
|
|
|
5525
6623
|
exports.readRaindropCallMetadataFromArgs = readRaindropCallMetadataFromArgs;
|
|
5526
6624
|
exports.redactJsonAttributeValue = redactJsonAttributeValue;
|
|
5527
6625
|
exports.redactSecretsInObject = redactSecretsInObject;
|
|
6626
|
+
exports.resetUnresolvedCarrierWarning = resetUnresolvedCarrierWarning;
|
|
5528
6627
|
exports.runWithParentToolContext = runWithParentToolContext;
|
|
5529
6628
|
exports.runWithRaindropCallMetadata = runWithRaindropCallMetadata;
|
|
6629
|
+
exports.toHeaders = toHeaders;
|
|
6630
|
+
exports.toLangSmithHeaders = toLangSmithHeaders;
|
|
5530
6631
|
exports.withCurrent = withCurrent;
|