@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.browser.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
// ../core/dist/chunk-
|
|
3
|
+
// ../core/dist/chunk-YUIXRQWN.js
|
|
4
4
|
function normalizeFeatureFlags(input) {
|
|
5
5
|
if (Array.isArray(input)) {
|
|
6
6
|
return Object.fromEntries(input.map((name) => [name, "true"]));
|
|
@@ -63,6 +63,311 @@ function base64Encode(bytes) {
|
|
|
63
63
|
}
|
|
64
64
|
return out;
|
|
65
65
|
}
|
|
66
|
+
function base64ToHex(value) {
|
|
67
|
+
if (!value) return "";
|
|
68
|
+
const maybeBuffer = globalThis.Buffer;
|
|
69
|
+
if (maybeBuffer) {
|
|
70
|
+
return maybeBuffer.from(value, "base64").toString("hex");
|
|
71
|
+
}
|
|
72
|
+
const atobFn = globalThis.atob;
|
|
73
|
+
if (typeof atobFn !== "function") return "";
|
|
74
|
+
try {
|
|
75
|
+
const binary = atobFn(value);
|
|
76
|
+
let hex = "";
|
|
77
|
+
for (let i = 0; i < binary.length; i++) {
|
|
78
|
+
hex += (binary.charCodeAt(i) & 255).toString(16).padStart(2, "0");
|
|
79
|
+
}
|
|
80
|
+
return hex;
|
|
81
|
+
} catch (e) {
|
|
82
|
+
return "";
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
var HANDOFF_ATTRIBUTE_SUFFIXES = {
|
|
86
|
+
mode: "raindrop.handoff.mode",
|
|
87
|
+
childEventId: "raindrop.handoff.childEventId",
|
|
88
|
+
parentEventId: "raindrop.handoff.parentEventId",
|
|
89
|
+
parentSpanId: "raindrop.handoff.parentSpanId",
|
|
90
|
+
name: "raindrop.handoff.name",
|
|
91
|
+
terminal: "raindrop.handoff.terminal",
|
|
92
|
+
agentRole: "raindrop.agent.role"
|
|
93
|
+
};
|
|
94
|
+
var HANDOFF_ATTRIBUTE_PREFIXES = [
|
|
95
|
+
"ai.telemetry.metadata.",
|
|
96
|
+
"ai.settings.context.",
|
|
97
|
+
""
|
|
98
|
+
];
|
|
99
|
+
var AI_SDK_METADATA_PREFIX = "ai.telemetry.metadata.";
|
|
100
|
+
var DETACHED_MODE = "detached";
|
|
101
|
+
var SUBAGENT_AGENT_ROLE = "subagent";
|
|
102
|
+
var HANDOFF_TERMINAL_CANCELLED = "cancelled";
|
|
103
|
+
var TOOL_EVENTS_SUFFIX = "raindrop.toolEvents";
|
|
104
|
+
var TOOL_EVENTS_ALLOW = "allow";
|
|
105
|
+
var SUBAGENT_ABORT_OPERATION_ID = "ai.subagent.failed";
|
|
106
|
+
var SUBAGENT_ABORT_SPAN_NAME = SUBAGENT_ABORT_OPERATION_ID;
|
|
107
|
+
var DEFAULT_DISPATCH_SPAN_NAME = "launch_subagent";
|
|
108
|
+
var HANDOFF_TERMINAL_PROPERTY_KEY = HANDOFF_ATTRIBUTE_SUFFIXES.terminal;
|
|
109
|
+
function defined(entries) {
|
|
110
|
+
const out = {};
|
|
111
|
+
for (const [key, value] of Object.entries(entries)) {
|
|
112
|
+
if (typeof value === "string" && value.trim().length > 0) out[key] = value;
|
|
113
|
+
}
|
|
114
|
+
return out;
|
|
115
|
+
}
|
|
116
|
+
function detachedDispatchMetadata(dispatch) {
|
|
117
|
+
return defined({
|
|
118
|
+
[HANDOFF_ATTRIBUTE_SUFFIXES.mode]: DETACHED_MODE,
|
|
119
|
+
[HANDOFF_ATTRIBUTE_SUFFIXES.childEventId]: dispatch.childEventId,
|
|
120
|
+
[HANDOFF_ATTRIBUTE_SUFFIXES.name]: dispatch.name
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
function detachedChildMetadata(link) {
|
|
124
|
+
return defined({
|
|
125
|
+
[HANDOFF_ATTRIBUTE_SUFFIXES.parentEventId]: link.parentEventId,
|
|
126
|
+
[HANDOFF_ATTRIBUTE_SUFFIXES.parentSpanId]: link.parentSpanId,
|
|
127
|
+
[HANDOFF_ATTRIBUTE_SUFFIXES.name]: link.name,
|
|
128
|
+
[HANDOFF_ATTRIBUTE_SUFFIXES.agentRole]: SUBAGENT_AGENT_ROLE
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
function cancelledTerminalMetadata() {
|
|
132
|
+
return { [HANDOFF_ATTRIBUTE_SUFFIXES.terminal]: HANDOFF_TERMINAL_CANCELLED };
|
|
133
|
+
}
|
|
134
|
+
function cancelledTerminalAttributes() {
|
|
135
|
+
const bare = cancelledTerminalMetadata();
|
|
136
|
+
return { ...bare, ...withMetadataPrefix(bare) };
|
|
137
|
+
}
|
|
138
|
+
function toolEventsAllowMetadata() {
|
|
139
|
+
return { [TOOL_EVENTS_SUFFIX]: TOOL_EVENTS_ALLOW };
|
|
140
|
+
}
|
|
141
|
+
function withMetadataPrefix(metadata) {
|
|
142
|
+
const out = {};
|
|
143
|
+
for (const [key, value] of Object.entries(metadata)) {
|
|
144
|
+
out[key.startsWith(AI_SDK_METADATA_PREFIX) ? key : `${AI_SDK_METADATA_PREFIX}${key}`] = value;
|
|
145
|
+
}
|
|
146
|
+
return out;
|
|
147
|
+
}
|
|
148
|
+
function readHandoffField(metadata, suffix) {
|
|
149
|
+
for (const prefix of HANDOFF_ATTRIBUTE_PREFIXES) {
|
|
150
|
+
const value = metadata[`${prefix}${suffix}`];
|
|
151
|
+
if (typeof value === "string" && value.trim().length > 0) return value.trim();
|
|
152
|
+
}
|
|
153
|
+
return void 0;
|
|
154
|
+
}
|
|
155
|
+
function readDetachedChildLink(metadata) {
|
|
156
|
+
if (!metadata) return void 0;
|
|
157
|
+
const parentEventId = readHandoffField(metadata, HANDOFF_ATTRIBUTE_SUFFIXES.parentEventId);
|
|
158
|
+
if (!parentEventId) return void 0;
|
|
159
|
+
return {
|
|
160
|
+
parentEventId,
|
|
161
|
+
parentSpanId: readHandoffField(metadata, HANDOFF_ATTRIBUTE_SUFFIXES.parentSpanId),
|
|
162
|
+
name: readHandoffField(metadata, HANDOFF_ATTRIBUTE_SUFFIXES.name)
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
var BAGGAGE_KEYS = {
|
|
166
|
+
eventId: "raindrop-event-id",
|
|
167
|
+
childEventId: "raindrop-child-event-id",
|
|
168
|
+
name: "raindrop-handoff-name",
|
|
169
|
+
convoId: "raindrop-convo-id",
|
|
170
|
+
userId: "raindrop-user-id",
|
|
171
|
+
// The dispatch span and its trace, carried as fields as well as in
|
|
172
|
+
// `traceparent`. Not redundant: OTel's HTTP instrumentations rewrite
|
|
173
|
+
// `traceparent` from whatever span is current as the request goes out, so by
|
|
174
|
+
// the time the child reads it the ids name the HTTP client span and its trace
|
|
175
|
+
// instead of the dispatch. The child would then point its reverse reference at
|
|
176
|
+
// a span the launcher's UI does not know as a dispatch. A field states which
|
|
177
|
+
// span it means rather than meaning "whoever wrote this header last".
|
|
178
|
+
dispatchSpanId: "raindrop-dispatch-span-id",
|
|
179
|
+
traceId: "raindrop-trace-id"
|
|
180
|
+
};
|
|
181
|
+
var TRACEPARENT_HEADER = "traceparent";
|
|
182
|
+
var BAGGAGE_HEADER = "baggage";
|
|
183
|
+
var W3C_TRACE_ID = /^[0-9a-f]{32}$/;
|
|
184
|
+
var W3C_SPAN_ID = /^[0-9a-f]{16}$/;
|
|
185
|
+
function isW3CTraceId(value) {
|
|
186
|
+
return value !== void 0 && W3C_TRACE_ID.test(value);
|
|
187
|
+
}
|
|
188
|
+
function isW3CSpanId(value) {
|
|
189
|
+
return value !== void 0 && W3C_SPAN_ID.test(value);
|
|
190
|
+
}
|
|
191
|
+
var warnedNonConformantIds = false;
|
|
192
|
+
function warnNonConformantIdsOnce(traceId, spanId) {
|
|
193
|
+
if (warnedNonConformantIds) return;
|
|
194
|
+
warnedNonConformantIds = true;
|
|
195
|
+
console.warn(
|
|
196
|
+
`[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.`
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
var HANDOFF_HEADER = "x-raindrop-handoff";
|
|
200
|
+
var LANGSMITH_TRACE_HEADER = "langsmith-trace";
|
|
201
|
+
var LANGSMITH_METADATA_BAGGAGE_KEY = "langsmith-metadata";
|
|
202
|
+
function encodeBaggage(entries) {
|
|
203
|
+
return Object.entries(entries).filter((entry) => Boolean(entry[1])).map(([key, value]) => `${key}=${encodeURIComponent(value)}`).join(",");
|
|
204
|
+
}
|
|
205
|
+
function decodeBaggage(header) {
|
|
206
|
+
if (!header) return {};
|
|
207
|
+
const parsed = {};
|
|
208
|
+
for (const part of header.split(",")) {
|
|
209
|
+
const [rawKey, ...rest] = part.split("=");
|
|
210
|
+
if (!rawKey || rest.length === 0) continue;
|
|
211
|
+
const key = rawKey.trim();
|
|
212
|
+
let value;
|
|
213
|
+
try {
|
|
214
|
+
value = decodeURIComponent(rest.join("=").trim());
|
|
215
|
+
} catch (e) {
|
|
216
|
+
value = rest.join("=").trim();
|
|
217
|
+
}
|
|
218
|
+
if (key in parsed && parsed[key] !== value) throw new ConflictingCarrierError(key);
|
|
219
|
+
parsed[key] = value;
|
|
220
|
+
}
|
|
221
|
+
return parsed;
|
|
222
|
+
}
|
|
223
|
+
function carrierBaggage(carrier) {
|
|
224
|
+
return {
|
|
225
|
+
[BAGGAGE_KEYS.eventId]: carrier.eventId,
|
|
226
|
+
[BAGGAGE_KEYS.childEventId]: carrier.childEventId,
|
|
227
|
+
[BAGGAGE_KEYS.name]: carrier.name,
|
|
228
|
+
[BAGGAGE_KEYS.convoId]: carrier.convoId,
|
|
229
|
+
[BAGGAGE_KEYS.userId]: carrier.userId,
|
|
230
|
+
[BAGGAGE_KEYS.dispatchSpanId]: carrier.spanId,
|
|
231
|
+
[BAGGAGE_KEYS.traceId]: carrier.traceId
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
function toHeaders(carrier) {
|
|
235
|
+
const fields = encodeBaggage(carrierBaggage(carrier));
|
|
236
|
+
const headers = {
|
|
237
|
+
[BAGGAGE_HEADER]: fields,
|
|
238
|
+
[HANDOFF_HEADER]: fields
|
|
239
|
+
};
|
|
240
|
+
if (isW3CTraceId(carrier.traceId) && isW3CSpanId(carrier.spanId)) {
|
|
241
|
+
headers[TRACEPARENT_HEADER] = `00-${carrier.traceId}-${carrier.spanId}-01`;
|
|
242
|
+
}
|
|
243
|
+
return headers;
|
|
244
|
+
}
|
|
245
|
+
function langsmithStamp() {
|
|
246
|
+
return (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/g, "").replace(/\.\d+Z$/, "000000");
|
|
247
|
+
}
|
|
248
|
+
function toLangSmithHeaders(carrier) {
|
|
249
|
+
const stamp = langsmithStamp();
|
|
250
|
+
const dottedOrder = `${stamp}Z${carrier.traceId}.${stamp}Z${carrier.spanId}`;
|
|
251
|
+
return {
|
|
252
|
+
[LANGSMITH_TRACE_HEADER]: dottedOrder,
|
|
253
|
+
[BAGGAGE_HEADER]: encodeBaggage({
|
|
254
|
+
[LANGSMITH_METADATA_BAGGAGE_KEY]: JSON.stringify(carrierBaggage(carrier))
|
|
255
|
+
}),
|
|
256
|
+
// Carried here too: a LangSmith-shaped carrier is rewritten in transit
|
|
257
|
+
// exactly like the native one, and an injected `traceparent` is preferred
|
|
258
|
+
// over the dotted order on read.
|
|
259
|
+
[HANDOFF_HEADER]: encodeBaggage(carrierBaggage(carrier))
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
function isHeaderLookup(headers) {
|
|
263
|
+
return "get" in headers && typeof headers.get === "function";
|
|
264
|
+
}
|
|
265
|
+
var ConflictingCarrierError = class extends Error {
|
|
266
|
+
};
|
|
267
|
+
function readHeader(headers, name) {
|
|
268
|
+
var _a, _b, _c;
|
|
269
|
+
if (isHeaderLookup(headers)) return (_a = headers.get(name)) != null ? _a : void 0;
|
|
270
|
+
const value = (_c = headers[name]) != null ? _c : (_b = Object.entries(headers).find(([key]) => key.toLowerCase() === name)) == null ? void 0 : _b[1];
|
|
271
|
+
if (!Array.isArray(value)) return value;
|
|
272
|
+
const distinct = new Set(value);
|
|
273
|
+
if (distinct.size > 1) throw new ConflictingCarrierError(name);
|
|
274
|
+
return value[0];
|
|
275
|
+
}
|
|
276
|
+
function readTraceHeader(headers, name) {
|
|
277
|
+
const value = readHeader(headers, name);
|
|
278
|
+
if (!(value == null ? void 0 : value.includes(","))) return value;
|
|
279
|
+
const copies = value.split(",").map((copy) => copy.trim());
|
|
280
|
+
if (new Set(copies).size > 1) throw new ConflictingCarrierError(name);
|
|
281
|
+
return copies[0];
|
|
282
|
+
}
|
|
283
|
+
function fromHeaders(headers) {
|
|
284
|
+
var _a, _b;
|
|
285
|
+
let baggage;
|
|
286
|
+
let handoff;
|
|
287
|
+
let traceparent;
|
|
288
|
+
let langsmithTrace;
|
|
289
|
+
try {
|
|
290
|
+
baggage = decodeBaggage(readHeader(headers, BAGGAGE_HEADER));
|
|
291
|
+
handoff = decodeBaggage(readHeader(headers, HANDOFF_HEADER));
|
|
292
|
+
traceparent = readTraceHeader(headers, TRACEPARENT_HEADER);
|
|
293
|
+
langsmithTrace = readTraceHeader(headers, LANGSMITH_TRACE_HEADER);
|
|
294
|
+
} catch (error) {
|
|
295
|
+
if (error instanceof ConflictingCarrierError) return null;
|
|
296
|
+
throw error;
|
|
297
|
+
}
|
|
298
|
+
const langsmithMetadata = baggage[LANGSMITH_METADATA_BAGGAGE_KEY];
|
|
299
|
+
const nested = langsmithMetadata ? safeParseStringRecord(langsmithMetadata) : {};
|
|
300
|
+
for (const [key, value] of Object.entries(nested)) {
|
|
301
|
+
if (key in baggage && baggage[key] !== value) return null;
|
|
302
|
+
}
|
|
303
|
+
const fields = {
|
|
304
|
+
...baggage,
|
|
305
|
+
...nested,
|
|
306
|
+
// Last, so it wins: the standard headers may have been rewritten in transit
|
|
307
|
+
// by a propagator, this one is only ever written by us.
|
|
308
|
+
...handoff
|
|
309
|
+
};
|
|
310
|
+
let traceId;
|
|
311
|
+
let spanId;
|
|
312
|
+
if (traceparent) {
|
|
313
|
+
const [, parsedTraceId, parsedSpanId] = traceparent.split("-");
|
|
314
|
+
if (isW3CTraceId(parsedTraceId) && isW3CSpanId(parsedSpanId)) {
|
|
315
|
+
traceId = parsedTraceId;
|
|
316
|
+
spanId = parsedSpanId;
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
if (!traceId && !spanId && langsmithTrace) {
|
|
320
|
+
const segments = langsmithTrace.split(".");
|
|
321
|
+
traceId = (_a = segments[0]) == null ? void 0 : _a.split("Z").pop();
|
|
322
|
+
spanId = (_b = segments[segments.length - 1]) == null ? void 0 : _b.split("Z").pop();
|
|
323
|
+
}
|
|
324
|
+
traceId = fields[BAGGAGE_KEYS.traceId] || traceId;
|
|
325
|
+
spanId = fields[BAGGAGE_KEYS.dispatchSpanId] || spanId;
|
|
326
|
+
const eventId = fields[BAGGAGE_KEYS.eventId];
|
|
327
|
+
if (!traceId || !spanId || !eventId) return null;
|
|
328
|
+
if (!isW3CTraceId(traceId) || !isW3CSpanId(spanId)) {
|
|
329
|
+
warnNonConformantIdsOnce(traceId, spanId);
|
|
330
|
+
}
|
|
331
|
+
const carrier = { traceId, spanId, eventId };
|
|
332
|
+
const childEventId = fields[BAGGAGE_KEYS.childEventId];
|
|
333
|
+
if (childEventId) carrier.childEventId = childEventId;
|
|
334
|
+
const name = fields[BAGGAGE_KEYS.name];
|
|
335
|
+
if (name) carrier.name = name;
|
|
336
|
+
const convoId = fields[BAGGAGE_KEYS.convoId];
|
|
337
|
+
if (convoId) carrier.convoId = convoId;
|
|
338
|
+
const userId = fields[BAGGAGE_KEYS.userId];
|
|
339
|
+
if (userId) carrier.userId = userId;
|
|
340
|
+
return carrier;
|
|
341
|
+
}
|
|
342
|
+
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.`;
|
|
343
|
+
var UNRESOLVED_CARRIER_WARNED_KEY = /* @__PURE__ */ Symbol.for("raindrop.handoff.warnedUnresolvedCarrier");
|
|
344
|
+
function warnedHolder() {
|
|
345
|
+
return globalThis;
|
|
346
|
+
}
|
|
347
|
+
function resetUnresolvedCarrierWarning() {
|
|
348
|
+
warnedHolder()[UNRESOLVED_CARRIER_WARNED_KEY] = false;
|
|
349
|
+
}
|
|
350
|
+
function warnUnresolvedCarrier(headers, carrier) {
|
|
351
|
+
if (carrier) return;
|
|
352
|
+
if (!headers) return;
|
|
353
|
+
const holder = warnedHolder();
|
|
354
|
+
if (holder[UNRESOLVED_CARRIER_WARNED_KEY]) return;
|
|
355
|
+
holder[UNRESOLVED_CARRIER_WARNED_KEY] = true;
|
|
356
|
+
console.warn(UNRESOLVED_CARRIER_WARNING);
|
|
357
|
+
}
|
|
358
|
+
function safeParseStringRecord(raw) {
|
|
359
|
+
try {
|
|
360
|
+
const parsed = JSON.parse(raw);
|
|
361
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return {};
|
|
362
|
+
const result = {};
|
|
363
|
+
for (const [key, value] of Object.entries(parsed)) {
|
|
364
|
+
if (typeof value === "string") result[key] = value;
|
|
365
|
+
}
|
|
366
|
+
return result;
|
|
367
|
+
} catch (e) {
|
|
368
|
+
return {};
|
|
369
|
+
}
|
|
370
|
+
}
|
|
66
371
|
function runWithTracingSuppressed(fn) {
|
|
67
372
|
const hook = globalThis.RAINDROP_SUPPRESS_TRACING;
|
|
68
373
|
if (typeof hook !== "function") return fn();
|
|
@@ -826,6 +1131,193 @@ var EventShipper = class {
|
|
|
826
1131
|
}
|
|
827
1132
|
}
|
|
828
1133
|
};
|
|
1134
|
+
var MODEL_USAGE_ATTRIBUTES = {
|
|
1135
|
+
providerName: "gen_ai.provider.name",
|
|
1136
|
+
requestModel: "gen_ai.request.model",
|
|
1137
|
+
responseModel: "gen_ai.response.model",
|
|
1138
|
+
inputTokens: "gen_ai.usage.input_tokens",
|
|
1139
|
+
outputTokens: "gen_ai.usage.output_tokens",
|
|
1140
|
+
reasoningTokens: "gen_ai.usage.reasoning_tokens",
|
|
1141
|
+
cacheReadInputTokens: "gen_ai.usage.cache_read_input_tokens",
|
|
1142
|
+
cacheWriteInputTokens: "gen_ai.usage.cache_write_input_tokens",
|
|
1143
|
+
nonCachedInputTokens: "raindrop.usage.input_tokens.non_cached",
|
|
1144
|
+
nonReasoningOutputTokens: "raindrop.usage.output_tokens.non_reasoning",
|
|
1145
|
+
reasoningOutputTokens: "raindrop.usage.output_tokens.reasoning",
|
|
1146
|
+
cacheReadTokens: "raindrop.usage.input_tokens.cache_read",
|
|
1147
|
+
cacheWriteTokens: "raindrop.usage.input_tokens.cache_write"
|
|
1148
|
+
};
|
|
1149
|
+
var MODEL_PROVIDER_NAMES = [
|
|
1150
|
+
["google.vertex", "google-vertex"],
|
|
1151
|
+
["vertex.anthropic", "google-vertex"],
|
|
1152
|
+
["amazon-bedrock", "amazon-bedrock"],
|
|
1153
|
+
["bedrock", "amazon-bedrock"],
|
|
1154
|
+
["anthropic", "anthropic"],
|
|
1155
|
+
["openai", "openai"],
|
|
1156
|
+
["google", "google"],
|
|
1157
|
+
["azure", "azure"],
|
|
1158
|
+
["openrouter", "openrouter"]
|
|
1159
|
+
];
|
|
1160
|
+
function canonicalModelProvider(provider) {
|
|
1161
|
+
var _a;
|
|
1162
|
+
const normalizedProvider = provider.trim().toLowerCase();
|
|
1163
|
+
if (normalizedProvider === "gateway") return "vercel";
|
|
1164
|
+
const match = MODEL_PROVIDER_NAMES.find(
|
|
1165
|
+
([family]) => normalizedProvider === family || normalizedProvider.startsWith(`${family}.`)
|
|
1166
|
+
);
|
|
1167
|
+
return (_a = match == null ? void 0 : match[1]) != null ? _a : provider;
|
|
1168
|
+
}
|
|
1169
|
+
function tokenCount(value) {
|
|
1170
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
1171
|
+
}
|
|
1172
|
+
function exclusiveTokens({
|
|
1173
|
+
explicit,
|
|
1174
|
+
total,
|
|
1175
|
+
parts,
|
|
1176
|
+
semantics
|
|
1177
|
+
}) {
|
|
1178
|
+
if (explicit !== void 0) return explicit;
|
|
1179
|
+
if (total === void 0) return void 0;
|
|
1180
|
+
if (semantics === "exclusive") return total;
|
|
1181
|
+
const observedParts = parts.filter((part) => part !== void 0 && part > 0);
|
|
1182
|
+
if (semantics === void 0 && observedParts.length > 0) return void 0;
|
|
1183
|
+
const exclusive = total - observedParts.reduce((sum, part) => sum + part, 0);
|
|
1184
|
+
return exclusive >= 0 ? exclusive : void 0;
|
|
1185
|
+
}
|
|
1186
|
+
function buildModelUsageAttributes(usage) {
|
|
1187
|
+
const inputTokens = tokenCount(usage.inputTokens);
|
|
1188
|
+
const outputTokens = tokenCount(usage.outputTokens);
|
|
1189
|
+
const explicitNonCachedInputTokens = tokenCount(usage.nonCachedInputTokens);
|
|
1190
|
+
const explicitNonReasoningOutputTokens = tokenCount(usage.nonReasoningOutputTokens);
|
|
1191
|
+
const reasoningTokens = tokenCount(usage.reasoningTokens);
|
|
1192
|
+
const cacheReadInputTokens = tokenCount(usage.cacheReadInputTokens);
|
|
1193
|
+
const cacheWriteInputTokens = tokenCount(usage.cacheWriteInputTokens);
|
|
1194
|
+
const nonCachedInputTokens = exclusiveTokens({
|
|
1195
|
+
explicit: explicitNonCachedInputTokens,
|
|
1196
|
+
total: inputTokens,
|
|
1197
|
+
parts: [cacheReadInputTokens, cacheWriteInputTokens],
|
|
1198
|
+
semantics: usage.inputTokenSemantics
|
|
1199
|
+
});
|
|
1200
|
+
const nonReasoningOutputTokens = exclusiveTokens({
|
|
1201
|
+
explicit: explicitNonReasoningOutputTokens,
|
|
1202
|
+
total: outputTokens,
|
|
1203
|
+
parts: [reasoningTokens],
|
|
1204
|
+
semantics: usage.outputTokenSemantics
|
|
1205
|
+
});
|
|
1206
|
+
const exclusivePoolAttributes = nonCachedInputTokens !== void 0 && nonReasoningOutputTokens !== void 0 ? [
|
|
1207
|
+
// backend consumes this complete raindrop.* set as one atomic billing-pool contract.
|
|
1208
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.nonCachedInputTokens, nonCachedInputTokens),
|
|
1209
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.nonReasoningOutputTokens, nonReasoningOutputTokens),
|
|
1210
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.reasoningOutputTokens, reasoningTokens),
|
|
1211
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.cacheReadTokens, cacheReadInputTokens),
|
|
1212
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.cacheWriteTokens, cacheWriteInputTokens)
|
|
1213
|
+
] : [];
|
|
1214
|
+
return [
|
|
1215
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.inputTokens, inputTokens),
|
|
1216
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.outputTokens, outputTokens),
|
|
1217
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.reasoningTokens, reasoningTokens),
|
|
1218
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens, cacheReadInputTokens),
|
|
1219
|
+
attrInt(MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens, cacheWriteInputTokens),
|
|
1220
|
+
...exclusivePoolAttributes
|
|
1221
|
+
].filter((attribute) => attribute !== void 0);
|
|
1222
|
+
}
|
|
1223
|
+
var STRING_ALIASES = {
|
|
1224
|
+
[MODEL_USAGE_ATTRIBUTES.requestModel]: ["ai.model.id", "ai.model"]
|
|
1225
|
+
};
|
|
1226
|
+
var NUMBER_ALIASES = {
|
|
1227
|
+
[MODEL_USAGE_ATTRIBUTES.inputTokens]: [
|
|
1228
|
+
"gen_ai.usage.prompt_tokens",
|
|
1229
|
+
"ai.usage.prompt_tokens",
|
|
1230
|
+
"ai.usage.promptTokens",
|
|
1231
|
+
"ai.usage.input_tokens",
|
|
1232
|
+
"ai.usage.inputTokens"
|
|
1233
|
+
],
|
|
1234
|
+
[MODEL_USAGE_ATTRIBUTES.outputTokens]: [
|
|
1235
|
+
"gen_ai.usage.completion_tokens",
|
|
1236
|
+
"ai.usage.completion_tokens",
|
|
1237
|
+
"ai.usage.completionTokens",
|
|
1238
|
+
"ai.usage.output_tokens",
|
|
1239
|
+
"ai.usage.outputTokens"
|
|
1240
|
+
],
|
|
1241
|
+
[MODEL_USAGE_ATTRIBUTES.reasoningTokens]: [
|
|
1242
|
+
"gen_ai.usage.reasoning.output_tokens",
|
|
1243
|
+
"ai.usage.reasoningTokens",
|
|
1244
|
+
"ai.usage.thoughts_tokens"
|
|
1245
|
+
],
|
|
1246
|
+
[MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens]: [
|
|
1247
|
+
"gen_ai.usage.cache_read_tokens",
|
|
1248
|
+
"gen_ai.usage.cache_read.input_tokens",
|
|
1249
|
+
"ai.usage.cachedInputTokens",
|
|
1250
|
+
"ai.usage.cached_tokens",
|
|
1251
|
+
"ai.usage.cache_read_tokens",
|
|
1252
|
+
"ai.usage.cache_read_input_tokens",
|
|
1253
|
+
"ai.usage.cacheReadInputTokens"
|
|
1254
|
+
],
|
|
1255
|
+
[MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens]: [
|
|
1256
|
+
"gen_ai.usage.cache_creation_input_tokens",
|
|
1257
|
+
"gen_ai.usage.cache_creation.input_tokens",
|
|
1258
|
+
"ai.usage.cacheWriteInputTokens",
|
|
1259
|
+
"ai.usage.cache_creation_input_tokens",
|
|
1260
|
+
"ai.usage.cacheCreationInputTokens"
|
|
1261
|
+
]
|
|
1262
|
+
};
|
|
1263
|
+
function hasAttribute(attributes, key) {
|
|
1264
|
+
return attributes.some((attribute) => attribute.key === key);
|
|
1265
|
+
}
|
|
1266
|
+
function findStringAttribute(attributes, keys) {
|
|
1267
|
+
return attributes.find(
|
|
1268
|
+
(attribute) => keys.includes(attribute.key) && typeof attribute.value.stringValue === "string" && attribute.value.stringValue.length > 0
|
|
1269
|
+
);
|
|
1270
|
+
}
|
|
1271
|
+
function findNumberAttribute(attributes, keys) {
|
|
1272
|
+
return attributes.find((attribute) => {
|
|
1273
|
+
if (!keys.includes(attribute.key)) return false;
|
|
1274
|
+
if (typeof attribute.value.doubleValue === "number" && Number.isSafeInteger(attribute.value.doubleValue) && attribute.value.doubleValue >= 0) {
|
|
1275
|
+
return true;
|
|
1276
|
+
}
|
|
1277
|
+
const intValue = attribute.value.intValue;
|
|
1278
|
+
return integerValue(intValue) !== void 0;
|
|
1279
|
+
});
|
|
1280
|
+
}
|
|
1281
|
+
function integerValue(value) {
|
|
1282
|
+
if (typeof value === "number") {
|
|
1283
|
+
return Number.isSafeInteger(value) && value >= 0 ? value : void 0;
|
|
1284
|
+
}
|
|
1285
|
+
if (typeof value !== "string") return void 0;
|
|
1286
|
+
const parsed = Number(value);
|
|
1287
|
+
return Number.isSafeInteger(parsed) && parsed >= 0 ? parsed : void 0;
|
|
1288
|
+
}
|
|
1289
|
+
function appendAlias(attributes, target, source) {
|
|
1290
|
+
if (!source || hasAttribute(attributes, target)) return attributes;
|
|
1291
|
+
return [...attributes, { key: target, value: { ...source.value } }];
|
|
1292
|
+
}
|
|
1293
|
+
function appendProviderAlias(attributes) {
|
|
1294
|
+
if (hasAttribute(attributes, MODEL_USAGE_ATTRIBUTES.providerName)) return attributes;
|
|
1295
|
+
const source = findStringAttribute(attributes, ["gen_ai.system", "ai.model.provider"]);
|
|
1296
|
+
if (!(source == null ? void 0 : source.value.stringValue)) return attributes;
|
|
1297
|
+
const attribute = attrString(
|
|
1298
|
+
MODEL_USAGE_ATTRIBUTES.providerName,
|
|
1299
|
+
canonicalModelProvider(source.value.stringValue)
|
|
1300
|
+
);
|
|
1301
|
+
return attribute ? [...attributes, attribute] : attributes;
|
|
1302
|
+
}
|
|
1303
|
+
function normalizeModelUsageSpan(span) {
|
|
1304
|
+
const original = span.attributes;
|
|
1305
|
+
if (!original || original.length === 0) return span;
|
|
1306
|
+
const responseModel = findStringAttribute(original, [
|
|
1307
|
+
MODEL_USAGE_ATTRIBUTES.responseModel,
|
|
1308
|
+
"ai.response.model"
|
|
1309
|
+
]);
|
|
1310
|
+
if (!responseModel) return span;
|
|
1311
|
+
let attributes = appendAlias(original, MODEL_USAGE_ATTRIBUTES.responseModel, responseModel);
|
|
1312
|
+
attributes = appendProviderAlias(attributes);
|
|
1313
|
+
for (const [target, aliases] of Object.entries(STRING_ALIASES)) {
|
|
1314
|
+
attributes = appendAlias(attributes, target, findStringAttribute(attributes, aliases));
|
|
1315
|
+
}
|
|
1316
|
+
for (const [target, aliases] of Object.entries(NUMBER_ALIASES)) {
|
|
1317
|
+
attributes = appendAlias(attributes, target, findNumberAttribute(attributes, aliases));
|
|
1318
|
+
}
|
|
1319
|
+
return attributes === original ? span : { ...span, attributes };
|
|
1320
|
+
}
|
|
829
1321
|
var DEFAULT_SECRET_KEY_NAMES = [
|
|
830
1322
|
"apikey",
|
|
831
1323
|
"apisecret",
|
|
@@ -1026,6 +1518,10 @@ var TraceShipper = class {
|
|
|
1026
1518
|
return null;
|
|
1027
1519
|
}
|
|
1028
1520
|
}
|
|
1521
|
+
try {
|
|
1522
|
+
current = normalizeModelUsageSpan(current);
|
|
1523
|
+
} catch (e) {
|
|
1524
|
+
}
|
|
1029
1525
|
if (!this.disableDefaultRedaction) {
|
|
1030
1526
|
current = defaultTransformSpan(current);
|
|
1031
1527
|
}
|
|
@@ -1359,7 +1855,7 @@ async function* asyncGeneratorWithCurrent(span, gen) {
|
|
|
1359
1855
|
// package.json
|
|
1360
1856
|
var package_default = {
|
|
1361
1857
|
name: "@raindrop-ai/ai-sdk",
|
|
1362
|
-
version: "0.
|
|
1858
|
+
version: "0.3.0"};
|
|
1363
1859
|
|
|
1364
1860
|
// src/internal/version.ts
|
|
1365
1861
|
var libraryName = package_default.name;
|
|
@@ -2056,6 +2552,15 @@ function attrsFromHeaders(headers) {
|
|
|
2056
2552
|
if (!isRecord(headers)) return [];
|
|
2057
2553
|
return Object.entries(headers).filter(([, v]) => typeof v === "string").map(([k, v]) => attrString(`ai.request.headers.${k}`, v));
|
|
2058
2554
|
}
|
|
2555
|
+
function attrsFromModelProvider(provider) {
|
|
2556
|
+
if (typeof provider !== "string" || provider.length === 0) return [];
|
|
2557
|
+
const providerName = canonicalModelProvider(provider);
|
|
2558
|
+
return [
|
|
2559
|
+
attrString("ai.model.provider", provider),
|
|
2560
|
+
attrString(MODEL_USAGE_ATTRIBUTES.providerName, providerName),
|
|
2561
|
+
attrString("gen_ai.system", provider)
|
|
2562
|
+
];
|
|
2563
|
+
}
|
|
2059
2564
|
function attrsFromSettings(args) {
|
|
2060
2565
|
if (!isRecord(args)) return [];
|
|
2061
2566
|
const result = [];
|
|
@@ -2238,6 +2743,473 @@ function runWithParentToolContext(ctx, fn) {
|
|
|
2238
2743
|
return getStorage2().run(ctx, fn);
|
|
2239
2744
|
}
|
|
2240
2745
|
|
|
2746
|
+
// src/internal/subagents.ts
|
|
2747
|
+
var SUBAGENT_CANCELLED_OUTPUT = "Cancelled before producing a result.";
|
|
2748
|
+
var SUBAGENT_ABORTED_OUTPUT = "Aborted before producing a result.";
|
|
2749
|
+
var SUBAGENT_FAILED_OPERATION_ID = SUBAGENT_ABORT_OPERATION_ID;
|
|
2750
|
+
var MAX_SETTLED_EVENT_IDS = 1024;
|
|
2751
|
+
function isTraceCarrier(value) {
|
|
2752
|
+
const candidate = value;
|
|
2753
|
+
return typeof candidate.traceId === "string" && typeof candidate.spanId === "string" && typeof candidate.eventId === "string";
|
|
2754
|
+
}
|
|
2755
|
+
function attrsFrom(metadata) {
|
|
2756
|
+
return Object.entries(withMetadataPrefix(metadata)).map(([key, value]) => attrString(key, value));
|
|
2757
|
+
}
|
|
2758
|
+
function attrsExact(attributes) {
|
|
2759
|
+
return Object.entries(attributes).map(([key, value]) => attrString(key, value));
|
|
2760
|
+
}
|
|
2761
|
+
function handoffSpanAttrs(link) {
|
|
2762
|
+
if (!link) return [];
|
|
2763
|
+
return attrsFrom(detachedChildMetadata(link));
|
|
2764
|
+
}
|
|
2765
|
+
function subagentNameAttrs(name, link) {
|
|
2766
|
+
if (!name || (link == null ? void 0 : link.name)) return [];
|
|
2767
|
+
return attrsFrom({ [HANDOFF_ATTRIBUTE_SUFFIXES.name]: name });
|
|
2768
|
+
}
|
|
2769
|
+
function cancelledSpanAttrs() {
|
|
2770
|
+
return attrsExact(cancelledTerminalAttributes());
|
|
2771
|
+
}
|
|
2772
|
+
function describeAbortReason(reason) {
|
|
2773
|
+
if (reason instanceof Error) return `Aborted: ${reason.message}`;
|
|
2774
|
+
if (typeof reason === "string" && reason.trim().length > 0) return reason;
|
|
2775
|
+
if (reason === void 0 || reason === null) return SUBAGENT_ABORTED_OUTPUT;
|
|
2776
|
+
const serialized = boundedStringify(reason);
|
|
2777
|
+
return serialized ? `Aborted: ${serialized}` : SUBAGENT_ABORTED_OUTPUT;
|
|
2778
|
+
}
|
|
2779
|
+
function stampOpenSpan(span, metadata) {
|
|
2780
|
+
if (span.endTimeUnixNano) return;
|
|
2781
|
+
span.attributes.push(...attrsFrom(metadata));
|
|
2782
|
+
}
|
|
2783
|
+
function stampOpenSpanExact(span, attributes) {
|
|
2784
|
+
if (span.endTimeUnixNano) return;
|
|
2785
|
+
span.attributes.push(...attrsExact(attributes));
|
|
2786
|
+
}
|
|
2787
|
+
var SubagentApi = class {
|
|
2788
|
+
constructor(opts) {
|
|
2789
|
+
var _a;
|
|
2790
|
+
this.opts = opts;
|
|
2791
|
+
this.settledEventIds = (_a = opts.settledEventIds) != null ? _a : /* @__PURE__ */ new Set();
|
|
2792
|
+
}
|
|
2793
|
+
/** True when this child's outcome has already been reported. */
|
|
2794
|
+
wasSettledExplicitly(eventId) {
|
|
2795
|
+
return this.settledEventIds.has(eventId);
|
|
2796
|
+
}
|
|
2797
|
+
/**
|
|
2798
|
+
* Record an outcome reported somewhere other than `cancel()` / `fail()`, so
|
|
2799
|
+
* first-outcome-wins holds across every path that can state one.
|
|
2800
|
+
*
|
|
2801
|
+
* An aborted generation is such a path: an AbortSignal cancellation IS the
|
|
2802
|
+
* run's outcome, and the `fail(err)` that a catch block around the aborted
|
|
2803
|
+
* call naturally reports would otherwise error the child's spans — which is
|
|
2804
|
+
* the only thing separating `failed` from `cancelled`.
|
|
2805
|
+
*/
|
|
2806
|
+
noteSettled(eventId) {
|
|
2807
|
+
this.remember(eventId);
|
|
2808
|
+
}
|
|
2809
|
+
remember(eventId) {
|
|
2810
|
+
if (this.settledEventIds.has(eventId)) return;
|
|
2811
|
+
if (this.settledEventIds.size >= MAX_SETTLED_EVENT_IDS) {
|
|
2812
|
+
const oldest = this.settledEventIds.values().next();
|
|
2813
|
+
if (!oldest.done) this.settledEventIds.delete(oldest.value);
|
|
2814
|
+
}
|
|
2815
|
+
this.settledEventIds.add(eventId);
|
|
2816
|
+
}
|
|
2817
|
+
/**
|
|
2818
|
+
* Record a detached sub-agent on this turn: allocate the child's event id,
|
|
2819
|
+
* stamp the dispatch, and return the headers to send with the job.
|
|
2820
|
+
*
|
|
2821
|
+
* This dispatches nothing — you do, moments later, with the returned headers.
|
|
2822
|
+
* Nothing here waits for the child either, or claims to know how it is doing.
|
|
2823
|
+
* Readers derive that from the child's own event.
|
|
2824
|
+
*/
|
|
2825
|
+
subagent(options = {}) {
|
|
2826
|
+
var _a;
|
|
2827
|
+
const childEventId = (_a = options.childEventId) != null ? _a : randomUUID();
|
|
2828
|
+
const name = options.name;
|
|
2829
|
+
try {
|
|
2830
|
+
return this.recordLaunch(childEventId, name, options);
|
|
2831
|
+
} catch (err) {
|
|
2832
|
+
if (this.opts.debug) {
|
|
2833
|
+
console.warn(
|
|
2834
|
+
`[raindrop-ai/ai-sdk] sub-agent dispatch not recorded: ${err instanceof Error ? err.message : err}`
|
|
2835
|
+
);
|
|
2836
|
+
}
|
|
2837
|
+
return { childEventId, name, headers: {}, carrier: null };
|
|
2838
|
+
}
|
|
2839
|
+
}
|
|
2840
|
+
recordLaunch(childEventId, name, options) {
|
|
2841
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
|
|
2842
|
+
const active = (_a = this.opts.spanSource) == null ? void 0 : _a.activeDispatch();
|
|
2843
|
+
const inherited = getContextManager().getParentSpanIds();
|
|
2844
|
+
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;
|
|
2845
|
+
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;
|
|
2846
|
+
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;
|
|
2847
|
+
if (!eventId) {
|
|
2848
|
+
return { childEventId, name, headers: {}, carrier: null };
|
|
2849
|
+
}
|
|
2850
|
+
const dispatch = detachedDispatchMetadata({ childEventId, name });
|
|
2851
|
+
const toolEvents = toolEventsAllowMetadata();
|
|
2852
|
+
for (const span of (_l = active == null ? void 0 : active.turnSpans) != null ? _l : []) {
|
|
2853
|
+
stampOpenSpan(span, toolEvents);
|
|
2854
|
+
}
|
|
2855
|
+
let dispatchIds;
|
|
2856
|
+
if (active == null ? void 0 : active.dispatchSpan) {
|
|
2857
|
+
stampOpenSpan(active.dispatchSpan, dispatch);
|
|
2858
|
+
dispatchIds = active.dispatchSpan.ids;
|
|
2859
|
+
} else if (this.opts.sendTraces) {
|
|
2860
|
+
dispatchIds = this.synthesizeDispatchSpan({
|
|
2861
|
+
childEventId,
|
|
2862
|
+
name,
|
|
2863
|
+
toolName: options.toolName,
|
|
2864
|
+
eventId,
|
|
2865
|
+
userId,
|
|
2866
|
+
convoId,
|
|
2867
|
+
input: options.input,
|
|
2868
|
+
// No active turn means no telemetry setting to honor: `input` is then
|
|
2869
|
+
// recorded on the explicit say-so of whoever passed it.
|
|
2870
|
+
recordInputs: (_m = active == null ? void 0 : active.recordInputs) != null ? _m : true,
|
|
2871
|
+
dispatch,
|
|
2872
|
+
parent: (inherited == null ? void 0 : inherited.eventId) === eventId ? inherited : void 0
|
|
2873
|
+
}).ids;
|
|
2874
|
+
}
|
|
2875
|
+
const traceId = base64ToHex((_o = (_n = dispatchIds == null ? void 0 : dispatchIds.traceIdB64) != null ? _n : inherited == null ? void 0 : inherited.traceIdB64) != null ? _o : "");
|
|
2876
|
+
const spanId = base64ToHex((_p = dispatchIds == null ? void 0 : dispatchIds.spanIdB64) != null ? _p : "");
|
|
2877
|
+
if (!traceId || !spanId) {
|
|
2878
|
+
if (this.opts.debug) {
|
|
2879
|
+
console.warn(
|
|
2880
|
+
"[raindrop-ai/ai-sdk] sub-agent dispatch recorded without a carrier: no dispatch span to reference (traces disabled?)"
|
|
2881
|
+
);
|
|
2882
|
+
}
|
|
2883
|
+
return { childEventId, name, headers: {}, carrier: null };
|
|
2884
|
+
}
|
|
2885
|
+
const carrier = {
|
|
2886
|
+
traceId,
|
|
2887
|
+
spanId,
|
|
2888
|
+
eventId,
|
|
2889
|
+
childEventId,
|
|
2890
|
+
...name ? { name } : {},
|
|
2891
|
+
...convoId ? { convoId } : {},
|
|
2892
|
+
...userId ? { userId } : {}
|
|
2893
|
+
};
|
|
2894
|
+
return { childEventId, name, headers: toHeaders(carrier), carrier };
|
|
2895
|
+
}
|
|
2896
|
+
/**
|
|
2897
|
+
* Record a dispatch span for a launch with no open tool-call span to decorate:
|
|
2898
|
+
* a launch from outside a tool's `execute`, or from a caller that is not an
|
|
2899
|
+
* LLM turn at all (an HTTP handler that enqueues jobs). Shaped as a tool call
|
|
2900
|
+
* so it reads identically to a model-issued launch.
|
|
2901
|
+
*/
|
|
2902
|
+
synthesizeDispatchSpan(args) {
|
|
2903
|
+
var _a;
|
|
2904
|
+
const spanName = (_a = args.toolName) != null ? _a : DEFAULT_DISPATCH_SPAN_NAME;
|
|
2905
|
+
const span = this.opts.traceShipper.startSpan({
|
|
2906
|
+
name: spanName,
|
|
2907
|
+
parent: args.parent,
|
|
2908
|
+
eventId: args.eventId,
|
|
2909
|
+
userId: args.userId,
|
|
2910
|
+
convoId: args.convoId,
|
|
2911
|
+
operationId: "ai.toolCall",
|
|
2912
|
+
attributes: [
|
|
2913
|
+
attrString("operation.name", "ai.toolCall"),
|
|
2914
|
+
attrString("resource.name", spanName),
|
|
2915
|
+
attrString("ai.toolCall.name", spanName),
|
|
2916
|
+
attrString("ai.toolCall.id", `call_${args.childEventId.replace(/-/g, "").slice(0, 12)}`),
|
|
2917
|
+
// Gated like every other input the turn's spans record: a caller that
|
|
2918
|
+
// disabled input capture must not leak the payload through the one
|
|
2919
|
+
// span this API synthesizes on its behalf.
|
|
2920
|
+
...args.recordInputs ? [attrString("ai.toolCall.args", boundedStringify(args.input))] : [],
|
|
2921
|
+
...attrsFrom(args.dispatch)
|
|
2922
|
+
]
|
|
2923
|
+
});
|
|
2924
|
+
this.opts.traceShipper.endSpan(span, {
|
|
2925
|
+
// A dispatch returns a handle, not an answer — the answer is the child's.
|
|
2926
|
+
attributes: [
|
|
2927
|
+
attrString(
|
|
2928
|
+
"ai.toolCall.result",
|
|
2929
|
+
boundedStringify({ jobId: args.childEventId, status: "accepted" })
|
|
2930
|
+
)
|
|
2931
|
+
]
|
|
2932
|
+
});
|
|
2933
|
+
return span;
|
|
2934
|
+
}
|
|
2935
|
+
/**
|
|
2936
|
+
* Adopt a carrier as the current run's parent reference.
|
|
2937
|
+
*
|
|
2938
|
+
* A missing carrier is a legitimate state — the child was invoked directly
|
|
2939
|
+
* rather than dispatched — so this always returns a usable run and leaves
|
|
2940
|
+
* `parent` null. Call sites stay unconditional.
|
|
2941
|
+
*/
|
|
2942
|
+
resume(carrierOrHeaders, options = {}) {
|
|
2943
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
2944
|
+
const carrier = carrierOrHeaders ? isTraceCarrier(carrierOrHeaders) ? carrierOrHeaders : this.readCarrier(carrierOrHeaders) : null;
|
|
2945
|
+
warnUnresolvedCarrier(carrierOrHeaders, carrier);
|
|
2946
|
+
const name = (_a = carrier == null ? void 0 : carrier.name) != null ? _a : options.name;
|
|
2947
|
+
const eventId = (_c = (_b = carrier == null ? void 0 : carrier.childEventId) != null ? _b : options.eventId) != null ? _c : randomUUID();
|
|
2948
|
+
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;
|
|
2949
|
+
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;
|
|
2950
|
+
const parent = carrier ? {
|
|
2951
|
+
parentEventId: carrier.eventId,
|
|
2952
|
+
...carrier.spanId ? { parentSpanId: carrier.spanId } : {},
|
|
2953
|
+
...name ? { name } : {}
|
|
2954
|
+
} : null;
|
|
2955
|
+
return {
|
|
2956
|
+
eventId,
|
|
2957
|
+
name,
|
|
2958
|
+
userId,
|
|
2959
|
+
convoId,
|
|
2960
|
+
parent,
|
|
2961
|
+
metadata: {
|
|
2962
|
+
eventId,
|
|
2963
|
+
...userId ? { userId } : {},
|
|
2964
|
+
...convoId ? { convoId } : {},
|
|
2965
|
+
...parent ? { subagent: parent } : {}
|
|
2966
|
+
},
|
|
2967
|
+
cancel: (reason) => this.settle(eventId, { userId, convoId, name, cancelled: true, output: reason }),
|
|
2968
|
+
fail: (reason) => this.settle(eventId, {
|
|
2969
|
+
userId,
|
|
2970
|
+
convoId,
|
|
2971
|
+
name,
|
|
2972
|
+
handoff: parent != null ? parent : void 0,
|
|
2973
|
+
cancelled: false,
|
|
2974
|
+
output: describeAbortReason(reason),
|
|
2975
|
+
error: reason
|
|
2976
|
+
})
|
|
2977
|
+
};
|
|
2978
|
+
}
|
|
2979
|
+
/**
|
|
2980
|
+
* A carrier arrives from outside this process, so a hostile or merely broken
|
|
2981
|
+
* header bag must cost the job its link, never its run.
|
|
2982
|
+
*/
|
|
2983
|
+
readCarrier(headers) {
|
|
2984
|
+
try {
|
|
2985
|
+
return fromHeaders(headers);
|
|
2986
|
+
} catch (err) {
|
|
2987
|
+
if (this.opts.debug) {
|
|
2988
|
+
console.warn(
|
|
2989
|
+
`[raindrop-ai/ai-sdk] sub-agent carrier ignored: ${err instanceof Error ? err.message : err}`
|
|
2990
|
+
);
|
|
2991
|
+
}
|
|
2992
|
+
return null;
|
|
2993
|
+
}
|
|
2994
|
+
}
|
|
2995
|
+
/**
|
|
2996
|
+
* Mark a failed child's own spans as errored.
|
|
2997
|
+
*
|
|
2998
|
+
* Reporting the reason as output is what gets the child an event at all, but
|
|
2999
|
+
* output alone is not enough: status is derived from span shape, and a child
|
|
3000
|
+
* with final output and no error spans derives `finished`. A failed job
|
|
3001
|
+
* reporting success is worse than one reporting nothing, so the failure has
|
|
3002
|
+
* to land on the telemetry too, not just in the text.
|
|
3003
|
+
*
|
|
3004
|
+
* This is the child describing its own run, not a caller writing a status it
|
|
3005
|
+
* cannot observe — the child's own spans are exactly where the contract puts
|
|
3006
|
+
* failure.
|
|
3007
|
+
*/
|
|
3008
|
+
recordFailureOnSpans(eventId, args, reason) {
|
|
3009
|
+
var _a, _b, _c;
|
|
3010
|
+
if (!this.opts.sendTraces) return;
|
|
3011
|
+
const failure = (_a = args.error) != null ? _a : reason;
|
|
3012
|
+
let marked = 0;
|
|
3013
|
+
for (const span2 of (_c = (_b = this.opts.spanSource) == null ? void 0 : _b.openSpansForEvent(eventId)) != null ? _c : []) {
|
|
3014
|
+
if (span2.endTimeUnixNano) continue;
|
|
3015
|
+
this.opts.traceShipper.endSpan(span2, { error: failure });
|
|
3016
|
+
marked++;
|
|
3017
|
+
}
|
|
3018
|
+
if (marked > 0) return;
|
|
3019
|
+
const spanName = SUBAGENT_ABORT_SPAN_NAME;
|
|
3020
|
+
const span = this.opts.traceShipper.startSpan({
|
|
3021
|
+
name: spanName,
|
|
3022
|
+
eventId,
|
|
3023
|
+
userId: args.userId,
|
|
3024
|
+
convoId: args.convoId,
|
|
3025
|
+
// Required, not decorative: ingest drops any span carrying no
|
|
3026
|
+
// `ai.operationId` (or traceloop / `gen_ai.*` key) and still answers 200,
|
|
3027
|
+
// so without this the failure disappears silently. The value is
|
|
3028
|
+
// deliberately none of the generate/stream/tool/embed forms, which is
|
|
3029
|
+
// what classifies the span as INTERNAL rather than mislabelling a failed
|
|
3030
|
+
// job as a model call or a tool call.
|
|
3031
|
+
operationId: SUBAGENT_FAILED_OPERATION_ID,
|
|
3032
|
+
// Carries the reverse reference like every other span the child emits:
|
|
3033
|
+
// this is often the child's ONLY span, and a span read on its own is the
|
|
3034
|
+
// whole reason the reference cannot live on the root alone. The name is
|
|
3035
|
+
// stamped even for an unlinked run, which has no caller to reference —
|
|
3036
|
+
// `span_name` no longer says which sub-agent this was, so the attribute
|
|
3037
|
+
// is the only thing that can.
|
|
3038
|
+
attributes: [
|
|
3039
|
+
attrString("resource.name", spanName),
|
|
3040
|
+
...handoffSpanAttrs(args.handoff),
|
|
3041
|
+
...subagentNameAttrs(args.name, args.handoff)
|
|
3042
|
+
]
|
|
3043
|
+
});
|
|
3044
|
+
this.opts.traceShipper.endSpan(span, { error: failure });
|
|
3045
|
+
}
|
|
3046
|
+
async settle(eventId, args) {
|
|
3047
|
+
var _a, _b;
|
|
3048
|
+
if (this.settledEventIds.has(eventId)) {
|
|
3049
|
+
if (this.opts.debug) {
|
|
3050
|
+
console.warn(
|
|
3051
|
+
`[raindrop-ai/ai-sdk] sub-agent ${eventId} already reported an outcome; ignoring the second one`
|
|
3052
|
+
);
|
|
3053
|
+
}
|
|
3054
|
+
return;
|
|
3055
|
+
}
|
|
3056
|
+
this.remember(eventId);
|
|
3057
|
+
const output = args.output && args.output.trim().length > 0 ? args.output : args.cancelled ? SUBAGENT_CANCELLED_OUTPUT : SUBAGENT_ABORTED_OUTPUT;
|
|
3058
|
+
try {
|
|
3059
|
+
if (args.cancelled) {
|
|
3060
|
+
for (const span of (_b = (_a = this.opts.spanSource) == null ? void 0 : _a.openSpansForEvent(eventId)) != null ? _b : []) {
|
|
3061
|
+
stampOpenSpanExact(span, cancelledTerminalAttributes());
|
|
3062
|
+
}
|
|
3063
|
+
} else {
|
|
3064
|
+
this.recordFailureOnSpans(eventId, args, output);
|
|
3065
|
+
}
|
|
3066
|
+
} catch (err) {
|
|
3067
|
+
if (this.opts.debug) {
|
|
3068
|
+
console.warn(
|
|
3069
|
+
`[raindrop-ai/ai-sdk] sub-agent outcome not recorded on spans: ${err instanceof Error ? err.message : err}`
|
|
3070
|
+
);
|
|
3071
|
+
}
|
|
3072
|
+
}
|
|
3073
|
+
if (!this.opts.sendEvents) return;
|
|
3074
|
+
await this.opts.eventShipper.patch(eventId, {
|
|
3075
|
+
userId: args.userId,
|
|
3076
|
+
convoId: args.convoId,
|
|
3077
|
+
// An event is only created from a run that reported something. A child
|
|
3078
|
+
// that dies silently produces no event at all, which pins the caller on
|
|
3079
|
+
// `queued` forever — indistinguishable from a job that never started.
|
|
3080
|
+
output,
|
|
3081
|
+
...args.cancelled ? { properties: { [HANDOFF_TERMINAL_PROPERTY_KEY]: HANDOFF_TERMINAL_CANCELLED } } : {},
|
|
3082
|
+
isPending: false
|
|
3083
|
+
}).catch((err) => {
|
|
3084
|
+
if (this.opts.debug) {
|
|
3085
|
+
console.warn(
|
|
3086
|
+
`[raindrop-ai/ai-sdk] sub-agent outcome patch failed: ${err instanceof Error ? err.message : err}`
|
|
3087
|
+
);
|
|
3088
|
+
}
|
|
3089
|
+
});
|
|
3090
|
+
}
|
|
3091
|
+
};
|
|
3092
|
+
|
|
3093
|
+
// src/internal/usage.ts
|
|
3094
|
+
function firstTokenCount(...values) {
|
|
3095
|
+
for (const value of values) {
|
|
3096
|
+
if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) {
|
|
3097
|
+
return value;
|
|
3098
|
+
}
|
|
3099
|
+
}
|
|
3100
|
+
return void 0;
|
|
3101
|
+
}
|
|
3102
|
+
function flatUsageSemantics(provider) {
|
|
3103
|
+
const normalizedProvider = typeof provider === "string" ? provider.trim().toLowerCase() : void 0;
|
|
3104
|
+
if (normalizedProvider === "anthropic" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("anthropic.")) || normalizedProvider === "vertex.anthropic" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("vertex.anthropic."))) {
|
|
3105
|
+
return {
|
|
3106
|
+
inputTokenSemantics: "exclusive",
|
|
3107
|
+
outputTokenSemantics: "total"
|
|
3108
|
+
};
|
|
3109
|
+
}
|
|
3110
|
+
if (normalizedProvider === "openai" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("openai.")) || normalizedProvider === "azure" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("azure."))) {
|
|
3111
|
+
return {
|
|
3112
|
+
inputTokenSemantics: "total",
|
|
3113
|
+
outputTokenSemantics: "total"
|
|
3114
|
+
};
|
|
3115
|
+
}
|
|
3116
|
+
if (normalizedProvider === "google" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("google."))) {
|
|
3117
|
+
return {
|
|
3118
|
+
inputTokenSemantics: "total",
|
|
3119
|
+
// Google v5 reports candidate output and thoughts separately.
|
|
3120
|
+
outputTokenSemantics: "exclusive"
|
|
3121
|
+
};
|
|
3122
|
+
}
|
|
3123
|
+
return {};
|
|
3124
|
+
}
|
|
3125
|
+
var CACHE_WRITE_METADATA_KEYS = [
|
|
3126
|
+
["anthropic", "cacheCreationInputTokens"],
|
|
3127
|
+
["openai", "cacheWriteTokens"],
|
|
3128
|
+
["bedrock", "cacheWriteInputTokens"]
|
|
3129
|
+
];
|
|
3130
|
+
function cacheWriteTokensFromProviderMetadata(providerMetadata) {
|
|
3131
|
+
if (!isRecord(providerMetadata)) return void 0;
|
|
3132
|
+
return firstTokenCount(
|
|
3133
|
+
...CACHE_WRITE_METADATA_KEYS.flatMap(([namespace, key]) => {
|
|
3134
|
+
const scope = providerMetadata[namespace];
|
|
3135
|
+
if (!isRecord(scope)) return [];
|
|
3136
|
+
const usage = scope["usage"];
|
|
3137
|
+
return [scope[key], isRecord(usage) ? usage[key] : void 0];
|
|
3138
|
+
})
|
|
3139
|
+
);
|
|
3140
|
+
}
|
|
3141
|
+
function extractUsageMetricsFromUsage(usage, provider, providerMetadata) {
|
|
3142
|
+
if (!isRecord(usage)) return {};
|
|
3143
|
+
const inputTokenValue = usage["inputTokens"];
|
|
3144
|
+
const outputTokenValue = usage["outputTokens"];
|
|
3145
|
+
const inputTokenDetails = usage["inputTokenDetails"];
|
|
3146
|
+
const outputTokenDetails = usage["outputTokenDetails"];
|
|
3147
|
+
const hasStructuredUsage = isRecord(inputTokenValue) || isRecord(outputTokenValue) || isRecord(inputTokenDetails) || isRecord(outputTokenDetails);
|
|
3148
|
+
const inputTokens = firstTokenCount(
|
|
3149
|
+
isRecord(inputTokenValue) ? inputTokenValue["total"] : void 0,
|
|
3150
|
+
inputTokenValue,
|
|
3151
|
+
usage["promptTokens"],
|
|
3152
|
+
usage["prompt_tokens"]
|
|
3153
|
+
);
|
|
3154
|
+
const outputTokens = firstTokenCount(
|
|
3155
|
+
isRecord(outputTokenValue) ? outputTokenValue["total"] : void 0,
|
|
3156
|
+
outputTokenValue,
|
|
3157
|
+
usage["completionTokens"],
|
|
3158
|
+
usage["completion_tokens"]
|
|
3159
|
+
);
|
|
3160
|
+
const reasoningTokens = firstTokenCount(
|
|
3161
|
+
isRecord(outputTokenValue) ? outputTokenValue["reasoning"] : void 0,
|
|
3162
|
+
isRecord(outputTokenDetails) ? outputTokenDetails["reasoningTokens"] : void 0,
|
|
3163
|
+
usage["reasoningTokens"],
|
|
3164
|
+
usage["completionReasoningTokens"],
|
|
3165
|
+
usage["completion_reasoning_tokens"],
|
|
3166
|
+
usage["reasoning_tokens"],
|
|
3167
|
+
usage["thinkingTokens"],
|
|
3168
|
+
usage["thinking_tokens"]
|
|
3169
|
+
);
|
|
3170
|
+
const cacheReadInputTokens = firstTokenCount(
|
|
3171
|
+
isRecord(inputTokenValue) ? inputTokenValue["cacheRead"] : void 0,
|
|
3172
|
+
isRecord(inputTokenDetails) ? inputTokenDetails["cacheReadTokens"] : void 0,
|
|
3173
|
+
usage["cachedInputTokens"],
|
|
3174
|
+
usage["promptCachedTokens"],
|
|
3175
|
+
usage["prompt_cached_tokens"]
|
|
3176
|
+
);
|
|
3177
|
+
const cacheWriteInputTokens = firstTokenCount(
|
|
3178
|
+
isRecord(inputTokenValue) ? inputTokenValue["cacheWrite"] : void 0,
|
|
3179
|
+
isRecord(inputTokenDetails) ? inputTokenDetails["cacheWriteTokens"] : void 0,
|
|
3180
|
+
usage["cacheWriteInputTokens"],
|
|
3181
|
+
usage["cacheCreationInputTokens"],
|
|
3182
|
+
usage["cache_creation_input_tokens"],
|
|
3183
|
+
cacheWriteTokensFromProviderMetadata(providerMetadata)
|
|
3184
|
+
);
|
|
3185
|
+
const nonCachedInputTokens = firstTokenCount(
|
|
3186
|
+
isRecord(inputTokenValue) ? inputTokenValue["noCache"] : void 0,
|
|
3187
|
+
isRecord(inputTokenDetails) ? inputTokenDetails["noCacheTokens"] : void 0
|
|
3188
|
+
);
|
|
3189
|
+
const nonReasoningOutputTokens = firstTokenCount(
|
|
3190
|
+
isRecord(outputTokenValue) ? outputTokenValue["text"] : void 0,
|
|
3191
|
+
isRecord(outputTokenDetails) ? outputTokenDetails["textTokens"] : void 0
|
|
3192
|
+
);
|
|
3193
|
+
const totalTokens = firstTokenCount(
|
|
3194
|
+
usage["totalTokens"],
|
|
3195
|
+
usage["tokens"],
|
|
3196
|
+
usage["total_tokens"],
|
|
3197
|
+
inputTokens !== void 0 && outputTokens !== void 0 ? inputTokens + outputTokens : void 0
|
|
3198
|
+
);
|
|
3199
|
+
return {
|
|
3200
|
+
inputTokens,
|
|
3201
|
+
outputTokens,
|
|
3202
|
+
totalTokens,
|
|
3203
|
+
nonCachedInputTokens,
|
|
3204
|
+
nonReasoningOutputTokens,
|
|
3205
|
+
reasoningTokens,
|
|
3206
|
+
cacheReadInputTokens,
|
|
3207
|
+
cachedInputTokens: cacheReadInputTokens,
|
|
3208
|
+
cacheWriteInputTokens,
|
|
3209
|
+
...hasStructuredUsage ? {} : flatUsageSemantics(provider)
|
|
3210
|
+
};
|
|
3211
|
+
}
|
|
3212
|
+
|
|
2241
3213
|
// src/internal/raindrop-telemetry-integration.ts
|
|
2242
3214
|
function hasUnresolvedToolApproval(event) {
|
|
2243
3215
|
var _a;
|
|
@@ -2310,6 +3282,7 @@ var RaindropTelemetryIntegration = class {
|
|
|
2310
3282
|
eventName: (_f = callMeta.eventName) != null ? _f : (_e = this.defaultContext) == null ? void 0 : _e.eventName
|
|
2311
3283
|
};
|
|
2312
3284
|
const inherited = getContextManager().getParentSpanIds();
|
|
3285
|
+
const handoff = readDetachedChildLink(metadata);
|
|
2313
3286
|
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;
|
|
2314
3287
|
const explicitEventId = callMeta.eventId && !eventIdGenerated ? callMeta.eventId : void 0;
|
|
2315
3288
|
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();
|
|
@@ -2339,7 +3312,10 @@ var RaindropTelemetryIntegration = class {
|
|
|
2339
3312
|
attrString("ai.toolCall.name", subagentName),
|
|
2340
3313
|
attrString("raindrop.subagent.name", subagentName),
|
|
2341
3314
|
attrString("raindrop.agent.role", "subagent"),
|
|
2342
|
-
...parentAttrs
|
|
3315
|
+
...parentAttrs,
|
|
3316
|
+
// Top of this child's tree, so the reverse reference matters as much
|
|
3317
|
+
// here as on the root: these are the spans a reader lands on first.
|
|
3318
|
+
...handoffSpanAttrs(handoff)
|
|
2343
3319
|
]
|
|
2344
3320
|
});
|
|
2345
3321
|
const subagentParentRef = this.spanParentRef(subagentToolCallSpan);
|
|
@@ -2352,7 +3328,8 @@ var RaindropTelemetryIntegration = class {
|
|
|
2352
3328
|
attributes: [
|
|
2353
3329
|
attrString("operation.name", "agent.subagent"),
|
|
2354
3330
|
attrString("raindrop.span.kind", "llm_call"),
|
|
2355
|
-
attrString("raindrop.subagent.name", subagentName)
|
|
3331
|
+
attrString("raindrop.subagent.name", subagentName),
|
|
3332
|
+
...handoffSpanAttrs(handoff)
|
|
2356
3333
|
]
|
|
2357
3334
|
});
|
|
2358
3335
|
this.traceShipper.endSpan(markerSpan);
|
|
@@ -2407,6 +3384,8 @@ var RaindropTelemetryIntegration = class {
|
|
|
2407
3384
|
rootParent: rootSpan ? this.spanParentRef(rootSpan) : rootParentOverride != null ? rootParentOverride : inheritedParent,
|
|
2408
3385
|
stepSpan: void 0,
|
|
2409
3386
|
stepParent: void 0,
|
|
3387
|
+
stepProvider: void 0,
|
|
3388
|
+
stepModelId: void 0,
|
|
2410
3389
|
toolSpans: /* @__PURE__ */ new Map(),
|
|
2411
3390
|
embedSpans: /* @__PURE__ */ new Map(),
|
|
2412
3391
|
parentContextToolCallIds: /* @__PURE__ */ new Set(),
|
|
@@ -2418,7 +3397,9 @@ var RaindropTelemetryIntegration = class {
|
|
|
2418
3397
|
inputText: isEmbed ? void 0 : this.extractInputText(event),
|
|
2419
3398
|
toolCallCount: 0,
|
|
2420
3399
|
subagentName,
|
|
2421
|
-
subagentToolCallSpan
|
|
3400
|
+
subagentToolCallSpan,
|
|
3401
|
+
handoff,
|
|
3402
|
+
nestedInEvent: inheritedParent !== void 0
|
|
2422
3403
|
});
|
|
2423
3404
|
};
|
|
2424
3405
|
// ── onStepStart ─────────────────────────────────────────────────────────
|
|
@@ -2460,15 +3441,17 @@ var RaindropTelemetryIntegration = class {
|
|
|
2460
3441
|
attrString("operation.name", operationName),
|
|
2461
3442
|
attrString("resource.name", resourceName),
|
|
2462
3443
|
attrString("ai.telemetry.functionId", state.functionId),
|
|
2463
|
-
|
|
3444
|
+
...attrsFromModelProvider(event.provider),
|
|
2464
3445
|
attrString("ai.model.id", event.modelId),
|
|
2465
|
-
attrString(
|
|
2466
|
-
|
|
2467
|
-
...
|
|
3446
|
+
attrString(MODEL_USAGE_ATTRIBUTES.requestModel, event.modelId),
|
|
3447
|
+
...inputAttrs,
|
|
3448
|
+
...handoffSpanAttrs(state.handoff)
|
|
2468
3449
|
]
|
|
2469
3450
|
});
|
|
2470
3451
|
state.stepSpan = stepSpan;
|
|
2471
3452
|
state.stepParent = this.spanParentRef(stepSpan);
|
|
3453
|
+
state.stepProvider = event.provider;
|
|
3454
|
+
state.stepModelId = event.modelId;
|
|
2472
3455
|
};
|
|
2473
3456
|
this.onToolExecutionStart = (event) => this.toolExecutionStart(event);
|
|
2474
3457
|
this.onToolExecutionEnd = (event) => this.toolExecutionEnd(event);
|
|
@@ -2519,23 +3502,24 @@ var RaindropTelemetryIntegration = class {
|
|
|
2519
3502
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
2520
3503
|
const state = this.getState(event.callId);
|
|
2521
3504
|
if (!(state == null ? void 0 : state.stepSpan)) return;
|
|
3505
|
+
const responseModelId = (_b = (_a = event.response) == null ? void 0 : _a.modelId) != null ? _b : state.stepModelId;
|
|
2522
3506
|
const outputAttrs = [];
|
|
2523
3507
|
if (state.recordOutputs) {
|
|
2524
3508
|
outputAttrs.push(
|
|
2525
3509
|
attrString("ai.response.finishReason", event.finishReason),
|
|
2526
|
-
attrString("ai.response.text", capText2((
|
|
2527
|
-
attrString("ai.response.id", (
|
|
2528
|
-
attrString("ai.response.model",
|
|
3510
|
+
attrString("ai.response.text", capText2((_c = event.text) != null ? _c : void 0)),
|
|
3511
|
+
attrString("ai.response.id", (_d = event.response) == null ? void 0 : _d.id),
|
|
3512
|
+
attrString("ai.response.model", responseModelId),
|
|
2529
3513
|
attrString(
|
|
2530
3514
|
"ai.response.timestamp",
|
|
2531
|
-
((
|
|
3515
|
+
((_e = event.response) == null ? void 0 : _e.timestamp) instanceof Date ? event.response.timestamp.toISOString() : (_f = event.response) == null ? void 0 : _f.timestamp
|
|
2532
3516
|
),
|
|
2533
3517
|
attrString(
|
|
2534
3518
|
"ai.response.providerMetadata",
|
|
2535
3519
|
event.providerMetadata ? safeJsonWithUint8(event.providerMetadata) : void 0
|
|
2536
3520
|
)
|
|
2537
3521
|
);
|
|
2538
|
-
if (((
|
|
3522
|
+
if (((_g = event.toolCalls) == null ? void 0 : _g.length) > 0) {
|
|
2539
3523
|
outputAttrs.push(
|
|
2540
3524
|
attrString(
|
|
2541
3525
|
"ai.response.toolCalls",
|
|
@@ -2549,7 +3533,7 @@ var RaindropTelemetryIntegration = class {
|
|
|
2549
3533
|
)
|
|
2550
3534
|
);
|
|
2551
3535
|
}
|
|
2552
|
-
if (((
|
|
3536
|
+
if (((_h = event.reasoning) == null ? void 0 : _h.length) > 0) {
|
|
2553
3537
|
const reasoningText = event.reasoning.filter((part) => "text" in part).map((part) => part.text).join("\n");
|
|
2554
3538
|
if (reasoningText) {
|
|
2555
3539
|
outputAttrs.push(attrString("ai.response.reasoning", capText2(reasoningText)));
|
|
@@ -2558,25 +3542,31 @@ var RaindropTelemetryIntegration = class {
|
|
|
2558
3542
|
}
|
|
2559
3543
|
outputAttrs.push(
|
|
2560
3544
|
attrStringArray("gen_ai.response.finish_reasons", [event.finishReason]),
|
|
2561
|
-
attrString("gen_ai.response.id", (
|
|
2562
|
-
attrString(
|
|
3545
|
+
attrString("gen_ai.response.id", (_i = event.response) == null ? void 0 : _i.id),
|
|
3546
|
+
attrString(MODEL_USAGE_ATTRIBUTES.responseModel, responseModelId)
|
|
2563
3547
|
);
|
|
2564
3548
|
const usage = event.usage;
|
|
2565
3549
|
if (usage) {
|
|
3550
|
+
const usageMetrics = extractUsageMetricsFromUsage(
|
|
3551
|
+
usage,
|
|
3552
|
+
state.stepProvider,
|
|
3553
|
+
event.providerMetadata
|
|
3554
|
+
);
|
|
2566
3555
|
outputAttrs.push(
|
|
2567
|
-
attrInt("ai.usage.inputTokens",
|
|
2568
|
-
attrInt("ai.usage.outputTokens",
|
|
2569
|
-
attrInt("ai.usage.totalTokens",
|
|
2570
|
-
attrInt("ai.usage.reasoningTokens",
|
|
2571
|
-
attrInt("ai.usage.cachedInputTokens",
|
|
2572
|
-
|
|
2573
|
-
attrInt("gen_ai.usage.output_tokens", usage.outputTokens)
|
|
3556
|
+
attrInt("ai.usage.inputTokens", usageMetrics.inputTokens),
|
|
3557
|
+
attrInt("ai.usage.outputTokens", usageMetrics.outputTokens),
|
|
3558
|
+
attrInt("ai.usage.totalTokens", usageMetrics.totalTokens),
|
|
3559
|
+
attrInt("ai.usage.reasoningTokens", usageMetrics.reasoningTokens),
|
|
3560
|
+
attrInt("ai.usage.cachedInputTokens", usageMetrics.cachedInputTokens),
|
|
3561
|
+
...buildModelUsageAttributes(usageMetrics)
|
|
2574
3562
|
);
|
|
2575
3563
|
}
|
|
2576
3564
|
this.emitProviderExecutedToolSpans(event, state);
|
|
2577
3565
|
this.traceShipper.endSpan(state.stepSpan, { attributes: outputAttrs });
|
|
2578
3566
|
state.stepSpan = void 0;
|
|
2579
3567
|
state.stepParent = void 0;
|
|
3568
|
+
state.stepProvider = void 0;
|
|
3569
|
+
state.stepModelId = void 0;
|
|
2580
3570
|
};
|
|
2581
3571
|
// ── onEmbedStart ────────────────────────────────────────────────────────
|
|
2582
3572
|
this.onEmbedStart = (event) => {
|
|
@@ -2594,7 +3584,8 @@ var RaindropTelemetryIntegration = class {
|
|
|
2594
3584
|
attrString("operation.name", operationName),
|
|
2595
3585
|
attrString("resource.name", resourceName),
|
|
2596
3586
|
attrString("ai.telemetry.functionId", state.functionId),
|
|
2597
|
-
...inputAttrs
|
|
3587
|
+
...inputAttrs,
|
|
3588
|
+
...handoffSpanAttrs(state.handoff)
|
|
2598
3589
|
]
|
|
2599
3590
|
});
|
|
2600
3591
|
state.embedSpans.set(event.embedCallId, embedSpan);
|
|
@@ -2651,6 +3642,8 @@ var RaindropTelemetryIntegration = class {
|
|
|
2651
3642
|
const actualError = (_a = event.error) != null ? _a : error;
|
|
2652
3643
|
if (state.stepSpan) {
|
|
2653
3644
|
this.traceShipper.endSpan(state.stepSpan, { error: actualError });
|
|
3645
|
+
state.stepProvider = void 0;
|
|
3646
|
+
state.stepModelId = void 0;
|
|
2654
3647
|
}
|
|
2655
3648
|
for (const embedSpan of state.embedSpans.values()) {
|
|
2656
3649
|
this.traceShipper.endSpan(embedSpan, { error: actualError });
|
|
@@ -2664,15 +3657,26 @@ var RaindropTelemetryIntegration = class {
|
|
|
2664
3657
|
this.traceShipper.endSpan(toolSpan, { error: actualError });
|
|
2665
3658
|
}
|
|
2666
3659
|
state.toolSpans.clear();
|
|
3660
|
+
const abortReason = describeAbortReason(actualError);
|
|
2667
3661
|
if (state.rootSpan) {
|
|
2668
|
-
this.traceShipper.endSpan(state.rootSpan, {
|
|
3662
|
+
this.traceShipper.endSpan(state.rootSpan, {
|
|
3663
|
+
error: actualError,
|
|
3664
|
+
attributes: this.abortOutcomeAttrs(state, abortReason, "error")
|
|
3665
|
+
});
|
|
2669
3666
|
}
|
|
2670
3667
|
if (state.subagentToolCallSpan) {
|
|
2671
3668
|
this.traceShipper.endSpan(state.subagentToolCallSpan, { error: actualError });
|
|
2672
3669
|
}
|
|
2673
3670
|
const isEmbed = state.operationId === "ai.embed" || state.operationId === "ai.embedMany";
|
|
2674
3671
|
if (!isEmbed) {
|
|
2675
|
-
|
|
3672
|
+
const errorIsTheRunsOutcome = state.handoff !== void 0 && !state.nestedInEvent;
|
|
3673
|
+
this.finalizeGenerateEvent(
|
|
3674
|
+
state,
|
|
3675
|
+
state.accumulatedText || void 0,
|
|
3676
|
+
void 0,
|
|
3677
|
+
false,
|
|
3678
|
+
errorIsTheRunsOutcome ? { fallbackOutput: abortReason } : void 0
|
|
3679
|
+
);
|
|
2676
3680
|
}
|
|
2677
3681
|
this.cleanup(event.callId);
|
|
2678
3682
|
};
|
|
@@ -2694,6 +3698,8 @@ var RaindropTelemetryIntegration = class {
|
|
|
2694
3698
|
this.traceShipper.endSpan(state.stepSpan, { attributes: [abortedAttr] });
|
|
2695
3699
|
state.stepSpan = void 0;
|
|
2696
3700
|
state.stepParent = void 0;
|
|
3701
|
+
state.stepProvider = void 0;
|
|
3702
|
+
state.stepModelId = void 0;
|
|
2697
3703
|
}
|
|
2698
3704
|
for (const embedSpan of state.embedSpans.values()) {
|
|
2699
3705
|
this.traceShipper.endSpan(embedSpan, { attributes: [abortedAttr] });
|
|
@@ -2707,9 +3713,19 @@ var RaindropTelemetryIntegration = class {
|
|
|
2707
3713
|
this.traceShipper.endSpan(toolSpan, { attributes: [abortedAttr] });
|
|
2708
3714
|
}
|
|
2709
3715
|
state.toolSpans.clear();
|
|
3716
|
+
const abortIsTheRunsOutcome = state.handoff !== void 0 && !state.nestedInEvent;
|
|
2710
3717
|
if (state.rootSpan) {
|
|
2711
3718
|
this.traceShipper.endSpan(state.rootSpan, {
|
|
2712
|
-
attributes: [
|
|
3719
|
+
attributes: [
|
|
3720
|
+
abortedAttr,
|
|
3721
|
+
attrInt("ai.toolCall.count", state.toolCallCount),
|
|
3722
|
+
// An aborted detached child IS a cancelled sub-agent, and a cancelled
|
|
3723
|
+
// run is span-for-span identical to a finished one — spans close,
|
|
3724
|
+
// nothing errors, there is just no answer. So it is the one outcome
|
|
3725
|
+
// that has to be stated, and the child states it on itself.
|
|
3726
|
+
...abortIsTheRunsOutcome ? cancelledSpanAttrs() : [],
|
|
3727
|
+
...abortIsTheRunsOutcome ? this.abortOutcomeAttrs(state, SUBAGENT_CANCELLED_OUTPUT, "stop") : []
|
|
3728
|
+
]
|
|
2713
3729
|
});
|
|
2714
3730
|
}
|
|
2715
3731
|
if (state.subagentToolCallSpan) {
|
|
@@ -2717,7 +3733,17 @@ var RaindropTelemetryIntegration = class {
|
|
|
2717
3733
|
attributes: [abortedAttr]
|
|
2718
3734
|
});
|
|
2719
3735
|
}
|
|
2720
|
-
this.finalizeGenerateEvent(
|
|
3736
|
+
this.finalizeGenerateEvent(
|
|
3737
|
+
state,
|
|
3738
|
+
state.accumulatedText || void 0,
|
|
3739
|
+
void 0,
|
|
3740
|
+
false,
|
|
3741
|
+
abortIsTheRunsOutcome ? {
|
|
3742
|
+
fallbackOutput: SUBAGENT_CANCELLED_OUTPUT,
|
|
3743
|
+
properties: { [HANDOFF_TERMINAL_PROPERTY_KEY]: HANDOFF_TERMINAL_CANCELLED }
|
|
3744
|
+
} : void 0
|
|
3745
|
+
);
|
|
3746
|
+
if (abortIsTheRunsOutcome) this.subagents.noteSettled(state.eventId);
|
|
2721
3747
|
this.cleanup(callId);
|
|
2722
3748
|
};
|
|
2723
3749
|
// ── executeTool ─────────────────────────────────────────────────────────
|
|
@@ -2745,6 +3771,97 @@ var RaindropTelemetryIntegration = class {
|
|
|
2745
3771
|
this.subagentWrapping = opts.subagentWrapping !== false;
|
|
2746
3772
|
this.debug = opts.debug === true;
|
|
2747
3773
|
this.defaultContext = opts.context;
|
|
3774
|
+
this.subagents = new SubagentApi({
|
|
3775
|
+
traceShipper: this.traceShipper,
|
|
3776
|
+
eventShipper: this.eventShipper,
|
|
3777
|
+
sendTraces: this.sendTraces,
|
|
3778
|
+
sendEvents: this.sendEvents,
|
|
3779
|
+
debug: this.debug,
|
|
3780
|
+
defaultContext: this.defaultContext,
|
|
3781
|
+
settledEventIds: opts.settledEventIds,
|
|
3782
|
+
spanSource: {
|
|
3783
|
+
activeDispatch: () => this.activeDispatch(),
|
|
3784
|
+
openSpansForEvent: (eventId) => this.openSpansForEvent(eventId)
|
|
3785
|
+
}
|
|
3786
|
+
});
|
|
3787
|
+
}
|
|
3788
|
+
/**
|
|
3789
|
+
* Record a detached sub-agent on the turn that is live right now.
|
|
3790
|
+
*
|
|
3791
|
+
* Returns the dispatch — the child's event id and the headers to send with
|
|
3792
|
+
* the job. Dispatching is still yours to do; this only states that you are
|
|
3793
|
+
* about to, so a reader can follow the link before the child exists.
|
|
3794
|
+
*/
|
|
3795
|
+
subagent(options = {}) {
|
|
3796
|
+
return this.subagents.subagent(options);
|
|
3797
|
+
}
|
|
3798
|
+
// ── detached sub-agent hand-offs ─────────────────────────────────────────
|
|
3799
|
+
/**
|
|
3800
|
+
* The turn a `subagent()` dispatch is happening inside.
|
|
3801
|
+
*
|
|
3802
|
+
* Resolved from the parent-tool context first, which is the only way to reach
|
|
3803
|
+
* the EXACT span that dispatched: the tool call the model itself issued, still
|
|
3804
|
+
* open while its `execute` runs. Falling back to the event id lets a launch
|
|
3805
|
+
* from elsewhere in the turn (a queue producer called mid-generation) still
|
|
3806
|
+
* find the turn's spans, which is where the tool-events opt-in has to land.
|
|
3807
|
+
*/
|
|
3808
|
+
activeDispatch() {
|
|
3809
|
+
var _a;
|
|
3810
|
+
const parentTool = getCurrentParentToolContext();
|
|
3811
|
+
let state = parentTool ? this.getState(parentTool.parentCallId) : void 0;
|
|
3812
|
+
const inheritedEventId = (_a = getContextManager().getParentSpanIds()) == null ? void 0 : _a.eventId;
|
|
3813
|
+
if (!state && inheritedEventId) {
|
|
3814
|
+
for (const candidate of this.callStates.values()) {
|
|
3815
|
+
if (candidate.eventId === inheritedEventId) {
|
|
3816
|
+
state = candidate;
|
|
3817
|
+
break;
|
|
3818
|
+
}
|
|
3819
|
+
}
|
|
3820
|
+
}
|
|
3821
|
+
if (!state) return void 0;
|
|
3822
|
+
return {
|
|
3823
|
+
eventId: state.eventId,
|
|
3824
|
+
userId: state.identity.userId,
|
|
3825
|
+
convoId: state.identity.convoId,
|
|
3826
|
+
dispatchSpan: parentTool ? state.toolSpans.get(parentTool.toolCallId) : void 0,
|
|
3827
|
+
turnSpans: [state.rootSpan, state.stepSpan].filter(
|
|
3828
|
+
(span) => span !== void 0
|
|
3829
|
+
),
|
|
3830
|
+
recordInputs: state.recordInputs
|
|
3831
|
+
};
|
|
3832
|
+
}
|
|
3833
|
+
/** Spans still open for an event, so a late outcome can still be stated. */
|
|
3834
|
+
openSpansForEvent(eventId) {
|
|
3835
|
+
const spans = [];
|
|
3836
|
+
for (const state of this.callStates.values()) {
|
|
3837
|
+
if (state.eventId !== eventId) continue;
|
|
3838
|
+
if (state.rootSpan) spans.push(state.rootSpan);
|
|
3839
|
+
if (state.stepSpan) spans.push(state.stepSpan);
|
|
3840
|
+
}
|
|
3841
|
+
return spans;
|
|
3842
|
+
}
|
|
3843
|
+
/**
|
|
3844
|
+
* End-attributes that keep a detached child legible when it ends without an
|
|
3845
|
+
* answer — an error, an abort, a cancellation.
|
|
3846
|
+
*
|
|
3847
|
+
* An event is created from an LLM span only when it has a finish reason and
|
|
3848
|
+
* non-empty output, so a child that dies silently produces NO event, and the
|
|
3849
|
+
* caller's hand-off pill stays on `queued` forever — indistinguishable from a
|
|
3850
|
+
* job that never started. Reporting the abort reason as the run's output is
|
|
3851
|
+
* what makes the outcome visible. Only detached children get this: an inline
|
|
3852
|
+
* generation's failure is already legible from its caller's own event.
|
|
3853
|
+
*
|
|
3854
|
+
* And only the run's OUTERMOST generation gets it (see `nestedInEvent`): an
|
|
3855
|
+
* inner sub-call ending badly is not the run ending, and since an event is
|
|
3856
|
+
* created from an LLM span with output, `ai.response.text` here would state
|
|
3857
|
+
* the run's outcome through the span while the turn is still working.
|
|
3858
|
+
*/
|
|
3859
|
+
abortOutcomeAttrs(state, reason, finishReason) {
|
|
3860
|
+
if (!state.handoff || state.nestedInEvent) return [];
|
|
3861
|
+
return [
|
|
3862
|
+
attrString("ai.response.text", capText2(state.accumulatedText || reason)),
|
|
3863
|
+
attrString("ai.response.finishReason", finishReason)
|
|
3864
|
+
];
|
|
2748
3865
|
}
|
|
2749
3866
|
// ── helpers ──────────────────────────────────────────────────────────────
|
|
2750
3867
|
getState(callId) {
|
|
@@ -2863,7 +3980,8 @@ var RaindropTelemetryIntegration = class {
|
|
|
2863
3980
|
attrString("ai.telemetry.functionId", state.functionId),
|
|
2864
3981
|
attrString("ai.toolCall.name", toolCall.toolName),
|
|
2865
3982
|
attrString("ai.toolCall.id", toolCall.toolCallId),
|
|
2866
|
-
...inputAttrs
|
|
3983
|
+
...inputAttrs,
|
|
3984
|
+
...handoffSpanAttrs(state.handoff)
|
|
2867
3985
|
]
|
|
2868
3986
|
});
|
|
2869
3987
|
state.toolSpans.set(toolCall.toolCallId, toolSpan);
|
|
@@ -2942,7 +4060,8 @@ var RaindropTelemetryIntegration = class {
|
|
|
2942
4060
|
attrString("ai.toolCall.name", call.toolName),
|
|
2943
4061
|
attrString("ai.toolCall.id", call.toolCallId),
|
|
2944
4062
|
attrString("ai.toolCall.providerExecuted", "true"),
|
|
2945
|
-
...inputAttrs
|
|
4063
|
+
...inputAttrs,
|
|
4064
|
+
...handoffSpanAttrs(state.handoff)
|
|
2946
4065
|
]
|
|
2947
4066
|
});
|
|
2948
4067
|
state.toolCallCount += 1;
|
|
@@ -2993,12 +4112,13 @@ var RaindropTelemetryIntegration = class {
|
|
|
2993
4112
|
}
|
|
2994
4113
|
const usage = (_d = event.totalUsage) != null ? _d : event.usage;
|
|
2995
4114
|
if (usage) {
|
|
4115
|
+
const usageMetrics = extractUsageMetricsFromUsage(usage);
|
|
2996
4116
|
outputAttrs.push(
|
|
2997
|
-
attrInt("ai.usage.inputTokens",
|
|
2998
|
-
attrInt("ai.usage.outputTokens",
|
|
2999
|
-
attrInt("ai.usage.totalTokens",
|
|
3000
|
-
attrInt("ai.usage.reasoningTokens",
|
|
3001
|
-
attrInt("ai.usage.cachedInputTokens",
|
|
4117
|
+
attrInt("ai.usage.inputTokens", usageMetrics.inputTokens),
|
|
4118
|
+
attrInt("ai.usage.outputTokens", usageMetrics.outputTokens),
|
|
4119
|
+
attrInt("ai.usage.totalTokens", usageMetrics.totalTokens),
|
|
4120
|
+
attrInt("ai.usage.reasoningTokens", usageMetrics.reasoningTokens),
|
|
4121
|
+
attrInt("ai.usage.cachedInputTokens", usageMetrics.cachedInputTokens)
|
|
3002
4122
|
);
|
|
3003
4123
|
}
|
|
3004
4124
|
outputAttrs.push(attrInt("ai.toolCall.count", state.toolCallCount));
|
|
@@ -3022,19 +4142,22 @@ var RaindropTelemetryIntegration = class {
|
|
|
3022
4142
|
* is finalized by that resume — otherwise each execution would finalize the
|
|
3023
4143
|
* same event ID into a separate canonical row.
|
|
3024
4144
|
*/
|
|
3025
|
-
finalizeGenerateEvent(state, output, model, keepPending = false) {
|
|
4145
|
+
finalizeGenerateEvent(state, output, model, keepPending = false, detachedOutcome) {
|
|
3026
4146
|
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
|
3027
4147
|
const suppressSubagentEvent = state.subagentName !== void 0 && state.subagentToolCallSpan !== void 0;
|
|
3028
4148
|
if (!this.sendEvents || suppressSubagentEvent) return;
|
|
4149
|
+
if (this.subagents.wasSettledExplicitly(state.eventId)) return;
|
|
3029
4150
|
const callMeta = this.extractRaindropMetadata(state.metadata);
|
|
3030
4151
|
const userId = (_b = callMeta.userId) != null ? _b : (_a = this.defaultContext) == null ? void 0 : _a.userId;
|
|
3031
4152
|
if (!userId) return;
|
|
3032
4153
|
const eventName = (_e = (_d = callMeta.eventName) != null ? _d : (_c = this.defaultContext) == null ? void 0 : _c.eventName) != null ? _e : state.operationId;
|
|
3033
4154
|
const cappedOutput = capText2(output);
|
|
4155
|
+
const reportedOutput = state.handoff && detachedOutcome && !(cappedOutput == null ? void 0 : cappedOutput.trim()) ? detachedOutcome.fallbackOutput : cappedOutput;
|
|
3034
4156
|
const input = capText2(state.inputText);
|
|
3035
4157
|
const properties = {
|
|
3036
4158
|
...(_f = this.defaultContext) == null ? void 0 : _f.properties,
|
|
3037
|
-
...callMeta.properties
|
|
4159
|
+
...callMeta.properties,
|
|
4160
|
+
...state.handoff ? detachedOutcome == null ? void 0 : detachedOutcome.properties : void 0
|
|
3038
4161
|
};
|
|
3039
4162
|
const featureFlags = {
|
|
3040
4163
|
...((_g = this.defaultContext) == null ? void 0 : _g.featureFlags) ? normalizeFeatureFlags(this.defaultContext.featureFlags) : {},
|
|
@@ -3046,7 +4169,7 @@ var RaindropTelemetryIntegration = class {
|
|
|
3046
4169
|
userId,
|
|
3047
4170
|
convoId,
|
|
3048
4171
|
input,
|
|
3049
|
-
output:
|
|
4172
|
+
output: reportedOutput,
|
|
3050
4173
|
model,
|
|
3051
4174
|
properties: Object.keys(properties).length > 0 ? properties : void 0,
|
|
3052
4175
|
featureFlags: Object.keys(featureFlags).length > 0 ? featureFlags : void 0,
|
|
@@ -3451,14 +4574,6 @@ function runWithParentSpanContextSync(ctx, fn) {
|
|
|
3451
4574
|
function isAsyncIterable(value) {
|
|
3452
4575
|
return value !== null && typeof value === "object" && Symbol.asyncIterator in value;
|
|
3453
4576
|
}
|
|
3454
|
-
function firstFiniteNumber(...values) {
|
|
3455
|
-
for (const value of values) {
|
|
3456
|
-
if (typeof value === "number" && Number.isFinite(value)) {
|
|
3457
|
-
return value;
|
|
3458
|
-
}
|
|
3459
|
-
}
|
|
3460
|
-
return void 0;
|
|
3461
|
-
}
|
|
3462
4577
|
function resolveUsageRecord(result) {
|
|
3463
4578
|
if (!isRecord(result)) return void 0;
|
|
3464
4579
|
let usage;
|
|
@@ -3474,50 +4589,7 @@ function resolveUsageRecord(result) {
|
|
|
3474
4589
|
return isRecord(usage) ? usage : void 0;
|
|
3475
4590
|
}
|
|
3476
4591
|
function extractUsageMetrics(result) {
|
|
3477
|
-
|
|
3478
|
-
if (!usage) return {};
|
|
3479
|
-
const inputTokenValue = usage["inputTokens"];
|
|
3480
|
-
const outputTokenValue = usage["outputTokens"];
|
|
3481
|
-
const inputTokens = firstFiniteNumber(
|
|
3482
|
-
isRecord(inputTokenValue) ? inputTokenValue["total"] : void 0,
|
|
3483
|
-
inputTokenValue,
|
|
3484
|
-
usage["promptTokens"],
|
|
3485
|
-
usage["prompt_tokens"]
|
|
3486
|
-
);
|
|
3487
|
-
const outputTokens = firstFiniteNumber(
|
|
3488
|
-
isRecord(outputTokenValue) ? outputTokenValue["total"] : void 0,
|
|
3489
|
-
outputTokenValue,
|
|
3490
|
-
usage["completionTokens"],
|
|
3491
|
-
usage["completion_tokens"]
|
|
3492
|
-
);
|
|
3493
|
-
const totalTokens = firstFiniteNumber(
|
|
3494
|
-
usage["totalTokens"],
|
|
3495
|
-
usage["tokens"],
|
|
3496
|
-
usage["total_tokens"],
|
|
3497
|
-
inputTokens !== void 0 && outputTokens !== void 0 ? inputTokens + outputTokens : void 0
|
|
3498
|
-
);
|
|
3499
|
-
const reasoningTokens = firstFiniteNumber(
|
|
3500
|
-
isRecord(outputTokenValue) ? outputTokenValue["reasoning"] : void 0,
|
|
3501
|
-
usage["reasoningTokens"],
|
|
3502
|
-
usage["completionReasoningTokens"],
|
|
3503
|
-
usage["completion_reasoning_tokens"],
|
|
3504
|
-
usage["reasoning_tokens"],
|
|
3505
|
-
usage["thinkingTokens"],
|
|
3506
|
-
usage["thinking_tokens"]
|
|
3507
|
-
);
|
|
3508
|
-
const cachedInputTokens = firstFiniteNumber(
|
|
3509
|
-
isRecord(inputTokenValue) ? inputTokenValue["cacheRead"] : void 0,
|
|
3510
|
-
usage["cachedInputTokens"],
|
|
3511
|
-
usage["promptCachedTokens"],
|
|
3512
|
-
usage["prompt_cached_tokens"]
|
|
3513
|
-
);
|
|
3514
|
-
return {
|
|
3515
|
-
inputTokens,
|
|
3516
|
-
outputTokens,
|
|
3517
|
-
totalTokens,
|
|
3518
|
-
reasoningTokens,
|
|
3519
|
-
cachedInputTokens
|
|
3520
|
-
};
|
|
4592
|
+
return extractUsageMetricsFromUsage(resolveUsageRecord(result));
|
|
3521
4593
|
}
|
|
3522
4594
|
function isObjectOperation(operation) {
|
|
3523
4595
|
return operation === "generateObject" || operation === "streamObject";
|
|
@@ -4009,6 +5081,7 @@ function wrapAISDK(aiSDK, deps) {
|
|
|
4009
5081
|
sendTraces: ((_a = deps.options.send) == null ? void 0 : _a.traces) !== false,
|
|
4010
5082
|
sendEvents: ((_b = deps.options.send) == null ? void 0 : _b.events) !== false,
|
|
4011
5083
|
debug,
|
|
5084
|
+
settledEventIds: deps.settledEventIds,
|
|
4012
5085
|
context: {
|
|
4013
5086
|
userId: wrapTimeCtx.userId,
|
|
4014
5087
|
eventId: wrapTimeCtx.eventId,
|
|
@@ -4908,8 +5981,13 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
|
|
|
4908
5981
|
ended = true;
|
|
4909
5982
|
const msToFirstChunk = firstChunkMs !== void 0 ? firstChunkMs - startMs : void 0;
|
|
4910
5983
|
const msToFinish = finishMs !== void 0 ? finishMs - startMs : void 0;
|
|
4911
|
-
const
|
|
4912
|
-
|
|
5984
|
+
const usageMetrics = extractUsageMetricsFromUsage(
|
|
5985
|
+
usage,
|
|
5986
|
+
modelInfo.provider,
|
|
5987
|
+
providerMetadata
|
|
5988
|
+
);
|
|
5989
|
+
const finalResponseModelId = responseModelId != null ? responseModelId : modelInfo.modelId;
|
|
5990
|
+
const { inputTokens, outputTokens } = usageMetrics;
|
|
4913
5991
|
const avgOutTokensPerSecond = msToFinish && outputTokens !== void 0 && msToFinish > 0 ? 1e3 * outputTokens / msToFinish : void 0;
|
|
4914
5992
|
ctx.traceShipper.endSpan(span, {
|
|
4915
5993
|
attributes: [
|
|
@@ -4921,7 +5999,7 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
|
|
|
4921
5999
|
safeJsonWithUint8(toolCallsLocal.length ? toolCallsLocal : void 0)
|
|
4922
6000
|
),
|
|
4923
6001
|
attrString("ai.response.id", responseId),
|
|
4924
|
-
attrString("ai.response.model",
|
|
6002
|
+
attrString("ai.response.model", finalResponseModelId),
|
|
4925
6003
|
attrString("ai.response.timestamp", responseTimestampIso),
|
|
4926
6004
|
attrString(
|
|
4927
6005
|
"ai.response.providerMetadata",
|
|
@@ -4932,9 +6010,8 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
|
|
|
4932
6010
|
attrInt("ai.usage.outputTokens", outputTokens),
|
|
4933
6011
|
...finishReason ? [attrStringArray("gen_ai.response.finish_reasons", [finishReason])] : [],
|
|
4934
6012
|
attrString("gen_ai.response.id", responseId),
|
|
4935
|
-
attrString(
|
|
4936
|
-
|
|
4937
|
-
attrInt("gen_ai.usage.output_tokens", outputTokens),
|
|
6013
|
+
attrString(MODEL_USAGE_ATTRIBUTES.responseModel, finalResponseModelId),
|
|
6014
|
+
...buildModelUsageAttributes(usageMetrics),
|
|
4938
6015
|
...msToFirstChunk !== void 0 ? [attrInt("ai.stream.msToFirstChunk", msToFirstChunk)] : [],
|
|
4939
6016
|
...msToFinish !== void 0 ? [attrInt("ai.stream.msToFinish", msToFinish)] : [],
|
|
4940
6017
|
...avgOutTokensPerSecond !== void 0 ? [attrDouble("ai.stream.avgOutputTokensPerSecond", avgOutTokensPerSecond)] : [],
|
|
@@ -5040,15 +6117,14 @@ function startDoGenerateSpan(operationId, options, modelInfo, parent, ctx) {
|
|
|
5040
6117
|
attrString("operation.name", operationName),
|
|
5041
6118
|
attrString("resource.name", resourceName),
|
|
5042
6119
|
attrString("ai.telemetry.functionId", (_b = ctx.telemetry) == null ? void 0 : _b.functionId),
|
|
5043
|
-
|
|
6120
|
+
...attrsFromModelProvider(modelInfo.provider),
|
|
5044
6121
|
attrString("ai.model.id", modelInfo.modelId),
|
|
5045
6122
|
...((_c = ctx.telemetry) == null ? void 0 : _c.recordInputs) === false ? [] : [
|
|
5046
6123
|
attrString("ai.prompt.messages", promptJson),
|
|
5047
6124
|
attrStringArray("ai.prompt.tools", toolsJson),
|
|
5048
6125
|
attrString("ai.prompt.toolChoice", toolChoiceJson)
|
|
5049
6126
|
],
|
|
5050
|
-
attrString(
|
|
5051
|
-
attrString("gen_ai.request.model", modelInfo.modelId),
|
|
6127
|
+
attrString(MODEL_USAGE_ATTRIBUTES.requestModel, modelInfo.modelId),
|
|
5052
6128
|
...attrsFromGenAiRequest(options),
|
|
5053
6129
|
attrProviderOptions(options)
|
|
5054
6130
|
]
|
|
@@ -5081,8 +6157,12 @@ function endDoGenerateSpan(span, result, modelInfo, ctx) {
|
|
|
5081
6157
|
} else {
|
|
5082
6158
|
responseTimestampIso = (/* @__PURE__ */ new Date()).toISOString();
|
|
5083
6159
|
}
|
|
5084
|
-
const
|
|
5085
|
-
|
|
6160
|
+
const usageMetrics = extractUsageMetricsFromUsage(
|
|
6161
|
+
usage,
|
|
6162
|
+
modelInfo.provider,
|
|
6163
|
+
providerMetadata
|
|
6164
|
+
);
|
|
6165
|
+
const { inputTokens, outputTokens } = usageMetrics;
|
|
5086
6166
|
ctx.traceShipper.endSpan(span, {
|
|
5087
6167
|
attributes: [
|
|
5088
6168
|
...((_a = ctx.telemetry) == null ? void 0 : _a.recordOutputs) === false ? [] : [
|
|
@@ -5101,9 +6181,8 @@ function endDoGenerateSpan(span, result, modelInfo, ctx) {
|
|
|
5101
6181
|
attrInt("ai.usage.completionTokens", outputTokens),
|
|
5102
6182
|
...finishReason ? [attrStringArray("gen_ai.response.finish_reasons", [finishReason])] : [],
|
|
5103
6183
|
attrString("gen_ai.response.id", responseId),
|
|
5104
|
-
attrString(
|
|
5105
|
-
|
|
5106
|
-
attrInt("gen_ai.usage.output_tokens", outputTokens)
|
|
6184
|
+
attrString(MODEL_USAGE_ATTRIBUTES.responseModel, responseModelId),
|
|
6185
|
+
...buildModelUsageAttributes(usageMetrics)
|
|
5107
6186
|
]
|
|
5108
6187
|
});
|
|
5109
6188
|
}
|
|
@@ -5124,15 +6203,14 @@ function startDoStreamSpan(operationId, options, modelInfo, parent, ctx) {
|
|
|
5124
6203
|
attrString("operation.name", operationName),
|
|
5125
6204
|
attrString("resource.name", resourceName),
|
|
5126
6205
|
attrString("ai.telemetry.functionId", (_b = ctx.telemetry) == null ? void 0 : _b.functionId),
|
|
5127
|
-
|
|
6206
|
+
...attrsFromModelProvider(modelInfo.provider),
|
|
5128
6207
|
attrString("ai.model.id", modelInfo.modelId),
|
|
5129
6208
|
...((_c = ctx.telemetry) == null ? void 0 : _c.recordInputs) === false ? [] : [
|
|
5130
6209
|
attrString("ai.prompt.messages", promptJson),
|
|
5131
6210
|
attrStringArray("ai.prompt.tools", toolsJson),
|
|
5132
6211
|
attrString("ai.prompt.toolChoice", toolChoiceJson)
|
|
5133
6212
|
],
|
|
5134
|
-
attrString(
|
|
5135
|
-
attrString("gen_ai.request.model", modelInfo.modelId),
|
|
6213
|
+
attrString(MODEL_USAGE_ATTRIBUTES.requestModel, modelInfo.modelId),
|
|
5136
6214
|
...attrsFromGenAiRequest(options),
|
|
5137
6215
|
attrProviderOptions(options)
|
|
5138
6216
|
]
|
|
@@ -5197,13 +6275,6 @@ function mergeAttachments(...groups) {
|
|
|
5197
6275
|
}
|
|
5198
6276
|
return merged.length ? merged : void 0;
|
|
5199
6277
|
}
|
|
5200
|
-
function extractNestedTokens(usage, key) {
|
|
5201
|
-
if (!isRecord(usage)) return void 0;
|
|
5202
|
-
const val = usage[key];
|
|
5203
|
-
if (typeof val === "number") return val;
|
|
5204
|
-
if (isRecord(val) && typeof val["total"] === "number") return val["total"];
|
|
5205
|
-
return void 0;
|
|
5206
|
-
}
|
|
5207
6278
|
|
|
5208
6279
|
// src/index.ts
|
|
5209
6280
|
function eventMetadata(options) {
|
|
@@ -5220,6 +6291,8 @@ function eventMetadata(options) {
|
|
|
5220
6291
|
if (options.properties) result["raindrop.properties"] = JSON.stringify(options.properties);
|
|
5221
6292
|
if (options.featureFlags)
|
|
5222
6293
|
result["raindrop.featureFlags"] = JSON.stringify(normalizeFeatureFlags(options.featureFlags));
|
|
6294
|
+
if (options.subagent) Object.assign(result, detachedChildMetadata(options.subagent));
|
|
6295
|
+
if (options.toolEvents) result[TOOL_EVENTS_SUFFIX] = options.toolEvents;
|
|
5223
6296
|
return result;
|
|
5224
6297
|
}
|
|
5225
6298
|
function deriveChatTurnMessageId(request) {
|
|
@@ -5302,12 +6375,22 @@ function createRaindropAISDK(opts) {
|
|
|
5302
6375
|
transformSpan: (_j = opts.traces) == null ? void 0 : _j.transformSpan,
|
|
5303
6376
|
disableDefaultRedaction: (_k = opts.traces) == null ? void 0 : _k.disableDefaultRedaction
|
|
5304
6377
|
});
|
|
6378
|
+
const settledEventIds = /* @__PURE__ */ new Set();
|
|
6379
|
+
const subagentApi = new SubagentApi({
|
|
6380
|
+
traceShipper,
|
|
6381
|
+
eventShipper,
|
|
6382
|
+
sendTraces: tracesEnabled,
|
|
6383
|
+
sendEvents: eventsEnabled,
|
|
6384
|
+
debug: envDebug,
|
|
6385
|
+
settledEventIds
|
|
6386
|
+
});
|
|
5305
6387
|
return {
|
|
5306
6388
|
wrap(aiSDK, options) {
|
|
5307
6389
|
return wrapAISDK(aiSDK, {
|
|
5308
6390
|
options: options != null ? options : {},
|
|
5309
6391
|
eventShipper,
|
|
5310
|
-
traceShipper
|
|
6392
|
+
traceShipper,
|
|
6393
|
+
settledEventIds
|
|
5311
6394
|
});
|
|
5312
6395
|
},
|
|
5313
6396
|
createSelfDiagnosticsTool(options = {}) {
|
|
@@ -5344,9 +6427,14 @@ function createRaindropAISDK(opts) {
|
|
|
5344
6427
|
sendEvents: eventsEnabled,
|
|
5345
6428
|
subagentWrapping,
|
|
5346
6429
|
debug: envDebug,
|
|
6430
|
+
settledEventIds,
|
|
5347
6431
|
context
|
|
5348
6432
|
});
|
|
5349
6433
|
},
|
|
6434
|
+
subagents: subagentApi,
|
|
6435
|
+
subagent(options = {}) {
|
|
6436
|
+
return subagentApi.subagent(options);
|
|
6437
|
+
},
|
|
5350
6438
|
events: {
|
|
5351
6439
|
async patch(eventId, patch) {
|
|
5352
6440
|
await eventShipper.patch(eventId, patch);
|
|
@@ -5469,8 +6557,17 @@ function raindrop(options = {}) {
|
|
|
5469
6557
|
exports.DEFAULT_MAX_TEXT_FIELD_CHARS = DEFAULT_MAX_TEXT_FIELD_CHARS2;
|
|
5470
6558
|
exports.DEFAULT_REDACT_ATTRIBUTE_KEYS = DEFAULT_REDACT_ATTRIBUTE_KEYS;
|
|
5471
6559
|
exports.DEFAULT_SECRET_KEY_NAMES = DEFAULT_SECRET_KEY_NAMES;
|
|
6560
|
+
exports.DETACHED_MODE = DETACHED_MODE;
|
|
6561
|
+
exports.HANDOFF_ATTRIBUTE_PREFIXES = HANDOFF_ATTRIBUTE_PREFIXES;
|
|
6562
|
+
exports.HANDOFF_ATTRIBUTE_SUFFIXES = HANDOFF_ATTRIBUTE_SUFFIXES;
|
|
6563
|
+
exports.HANDOFF_TERMINAL_CANCELLED = HANDOFF_TERMINAL_CANCELLED;
|
|
6564
|
+
exports.HANDOFF_TERMINAL_PROPERTY_KEY = HANDOFF_TERMINAL_PROPERTY_KEY;
|
|
5472
6565
|
exports.REDACTED_PLACEHOLDER = REDACTED_PLACEHOLDER;
|
|
5473
6566
|
exports.RaindropTelemetryIntegration = RaindropTelemetryIntegration;
|
|
6567
|
+
exports.SUBAGENT_ABORTED_OUTPUT = SUBAGENT_ABORTED_OUTPUT;
|
|
6568
|
+
exports.SUBAGENT_AGENT_ROLE = SUBAGENT_AGENT_ROLE;
|
|
6569
|
+
exports.SUBAGENT_CANCELLED_OUTPUT = SUBAGENT_CANCELLED_OUTPUT;
|
|
6570
|
+
exports.TOOL_EVENTS_ALLOW = TOOL_EVENTS_ALLOW;
|
|
5474
6571
|
exports.TRUNCATION_MARKER = TRUNCATION_MARKER2;
|
|
5475
6572
|
exports._resetParentToolContextStorage = _resetParentToolContextStorage;
|
|
5476
6573
|
exports._resetRaindropCallMetadataStorage = _resetRaindropCallMetadataStorage;
|
|
@@ -5484,6 +6581,7 @@ exports.defaultTransformSpan = defaultTransformSpan;
|
|
|
5484
6581
|
exports.enterParentToolContext = enterParentToolContext;
|
|
5485
6582
|
exports.eventMetadata = eventMetadata;
|
|
5486
6583
|
exports.eventMetadataFromChatRequest = eventMetadataFromChatRequest;
|
|
6584
|
+
exports.fromHeaders = fromHeaders;
|
|
5487
6585
|
exports.getContextManager = getContextManager;
|
|
5488
6586
|
exports.getCurrentParentToolContext = getCurrentParentToolContext;
|
|
5489
6587
|
exports.getCurrentRaindropCallMetadata = getCurrentRaindropCallMetadata;
|
|
@@ -5492,6 +6590,9 @@ exports.raindrop = raindrop;
|
|
|
5492
6590
|
exports.readRaindropCallMetadataFromArgs = readRaindropCallMetadataFromArgs;
|
|
5493
6591
|
exports.redactJsonAttributeValue = redactJsonAttributeValue;
|
|
5494
6592
|
exports.redactSecretsInObject = redactSecretsInObject;
|
|
6593
|
+
exports.resetUnresolvedCarrierWarning = resetUnresolvedCarrierWarning;
|
|
5495
6594
|
exports.runWithParentToolContext = runWithParentToolContext;
|
|
5496
6595
|
exports.runWithRaindropCallMetadata = runWithRaindropCallMetadata;
|
|
6596
|
+
exports.toHeaders = toHeaders;
|
|
6597
|
+
exports.toLangSmithHeaders = toLangSmithHeaders;
|
|
5497
6598
|
exports.withCurrent = withCurrent;
|