@raindrop-ai/ai-sdk 0.2.1 → 0.3.1

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.
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- // ../core/dist/chunk-QNWZIOOY.js
3
+ // ../core/dist/chunk-3V4MIA75.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();
@@ -827,6 +1132,7 @@ var EventShipper = class {
827
1132
  }
828
1133
  };
829
1134
  var MODEL_USAGE_ATTRIBUTES = {
1135
+ usageSource: "raindrop.usage.source",
830
1136
  providerName: "gen_ai.provider.name",
831
1137
  requestModel: "gen_ai.request.model",
832
1138
  responseModel: "gen_ai.response.model",
@@ -835,20 +1141,22 @@ var MODEL_USAGE_ATTRIBUTES = {
835
1141
  reasoningTokens: "gen_ai.usage.reasoning_tokens",
836
1142
  cacheReadInputTokens: "gen_ai.usage.cache_read_input_tokens",
837
1143
  cacheWriteInputTokens: "gen_ai.usage.cache_write_input_tokens",
838
- nonCachedInputTokens: "raindrop.usage.input_tokens.non_cached",
839
- nonReasoningOutputTokens: "raindrop.usage.output_tokens.non_reasoning",
840
- reasoningOutputTokens: "raindrop.usage.output_tokens.reasoning",
841
- cacheReadTokens: "raindrop.usage.input_tokens.cache_read",
842
- cacheWriteTokens: "raindrop.usage.input_tokens.cache_write"
843
- };
1144
+ providerReportedCost: "gen_ai.usage.provider_reported_cost"};
844
1145
  var MODEL_PROVIDER_NAMES = [
1146
+ ["google.vertex.anthropic", "google-vertex"],
1147
+ ["google.vertex_ai", "google-vertex"],
845
1148
  ["google.vertex", "google-vertex"],
1149
+ ["gcp.vertex_ai", "google-vertex"],
1150
+ ["gcp.gemini", "google"],
1151
+ ["google_vertexai", "google-vertex"],
846
1152
  ["vertex.anthropic", "google-vertex"],
847
1153
  ["amazon-bedrock", "amazon-bedrock"],
1154
+ ["aws.bedrock", "amazon-bedrock"],
848
1155
  ["bedrock", "amazon-bedrock"],
849
1156
  ["anthropic", "anthropic"],
850
1157
  ["openai", "openai"],
851
1158
  ["google", "google"],
1159
+ ["az.ai.openai", "azure"],
852
1160
  ["azure", "azure"],
853
1161
  ["openrouter", "openrouter"]
854
1162
  ];
@@ -859,60 +1167,20 @@ function canonicalModelProvider(provider) {
859
1167
  const match = MODEL_PROVIDER_NAMES.find(
860
1168
  ([family]) => normalizedProvider === family || normalizedProvider.startsWith(`${family}.`)
861
1169
  );
862
- return (_a = match == null ? void 0 : match[1]) != null ? _a : provider;
1170
+ return (_a = match == null ? void 0 : match[1]) != null ? _a : normalizedProvider;
863
1171
  }
864
1172
  function tokenCount(value) {
865
1173
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
866
1174
  }
867
- function exclusiveTokens({
868
- explicit,
869
- total,
870
- parts,
871
- semantics
872
- }) {
873
- if (explicit !== void 0) return explicit;
874
- if (total === void 0) return void 0;
875
- if (semantics === "exclusive") return total;
876
- const observedParts = parts.filter((part) => part !== void 0 && part > 0);
877
- if (semantics === void 0 && observedParts.length > 0) return void 0;
878
- const exclusive = total - observedParts.reduce((sum, part) => sum + part, 0);
879
- return exclusive >= 0 ? exclusive : void 0;
880
- }
881
- function buildModelUsageAttributes(usage) {
882
- const inputTokens = tokenCount(usage.inputTokens);
883
- const outputTokens = tokenCount(usage.outputTokens);
884
- const explicitNonCachedInputTokens = tokenCount(usage.nonCachedInputTokens);
885
- const explicitNonReasoningOutputTokens = tokenCount(usage.nonReasoningOutputTokens);
886
- const reasoningTokens = tokenCount(usage.reasoningTokens);
887
- const cacheReadInputTokens = tokenCount(usage.cacheReadInputTokens);
888
- const cacheWriteInputTokens = tokenCount(usage.cacheWriteInputTokens);
889
- const nonCachedInputTokens = exclusiveTokens({
890
- explicit: explicitNonCachedInputTokens,
891
- total: inputTokens,
892
- parts: [cacheReadInputTokens, cacheWriteInputTokens],
893
- semantics: usage.inputTokenSemantics
894
- });
895
- const nonReasoningOutputTokens = exclusiveTokens({
896
- explicit: explicitNonReasoningOutputTokens,
897
- total: outputTokens,
898
- parts: [reasoningTokens],
899
- semantics: usage.outputTokenSemantics
900
- });
901
- const exclusivePoolAttributes = nonCachedInputTokens !== void 0 && nonReasoningOutputTokens !== void 0 ? [
902
- // backend consumes this complete raindrop.* set as one atomic billing-pool contract.
903
- attrInt(MODEL_USAGE_ATTRIBUTES.nonCachedInputTokens, nonCachedInputTokens),
904
- attrInt(MODEL_USAGE_ATTRIBUTES.nonReasoningOutputTokens, nonReasoningOutputTokens),
905
- attrInt(MODEL_USAGE_ATTRIBUTES.reasoningOutputTokens, reasoningTokens),
906
- attrInt(MODEL_USAGE_ATTRIBUTES.cacheReadTokens, cacheReadInputTokens),
907
- attrInt(MODEL_USAGE_ATTRIBUTES.cacheWriteTokens, cacheWriteInputTokens)
908
- ] : [];
1175
+ function buildRawModelUsageAttributes(usage) {
1176
+ const providerReportedCost = typeof usage.providerReportedCost === "number" && Number.isFinite(usage.providerReportedCost) && usage.providerReportedCost >= 0 ? usage.providerReportedCost : void 0;
909
1177
  return [
910
- attrInt(MODEL_USAGE_ATTRIBUTES.inputTokens, inputTokens),
911
- attrInt(MODEL_USAGE_ATTRIBUTES.outputTokens, outputTokens),
912
- attrInt(MODEL_USAGE_ATTRIBUTES.reasoningTokens, reasoningTokens),
913
- attrInt(MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens, cacheReadInputTokens),
914
- attrInt(MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens, cacheWriteInputTokens),
915
- ...exclusivePoolAttributes
1178
+ attrInt(MODEL_USAGE_ATTRIBUTES.inputTokens, tokenCount(usage.inputTokens)),
1179
+ attrInt(MODEL_USAGE_ATTRIBUTES.outputTokens, tokenCount(usage.outputTokens)),
1180
+ attrInt(MODEL_USAGE_ATTRIBUTES.reasoningTokens, tokenCount(usage.reasoningTokens)),
1181
+ attrInt(MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens, tokenCount(usage.cacheReadInputTokens)),
1182
+ attrInt(MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens, tokenCount(usage.cacheWriteInputTokens)),
1183
+ attrDouble(MODEL_USAGE_ATTRIBUTES.providerReportedCost, providerReportedCost)
916
1184
  ].filter((attribute) => attribute !== void 0);
917
1185
  }
918
1186
  var STRING_ALIASES = {
@@ -1550,7 +1818,7 @@ async function* asyncGeneratorWithCurrent(span, gen) {
1550
1818
  // package.json
1551
1819
  var package_default = {
1552
1820
  name: "@raindrop-ai/ai-sdk",
1553
- version: "0.2.1"};
1821
+ version: "0.3.1"};
1554
1822
 
1555
1823
  // src/internal/version.ts
1556
1824
  var libraryName = package_default.name;
@@ -2438,37 +2706,361 @@ function runWithParentToolContext(ctx, fn) {
2438
2706
  return getStorage2().run(ctx, fn);
2439
2707
  }
2440
2708
 
2441
- // src/internal/usage.ts
2442
- function firstTokenCount(...values) {
2443
- for (const value of values) {
2444
- if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) {
2445
- return value;
2709
+ // src/internal/subagents.ts
2710
+ var SUBAGENT_CANCELLED_OUTPUT = "Cancelled before producing a result.";
2711
+ var SUBAGENT_ABORTED_OUTPUT = "Aborted before producing a result.";
2712
+ var SUBAGENT_FAILED_OPERATION_ID = SUBAGENT_ABORT_OPERATION_ID;
2713
+ var MAX_SETTLED_EVENT_IDS = 1024;
2714
+ function isTraceCarrier(value) {
2715
+ const candidate = value;
2716
+ return typeof candidate.traceId === "string" && typeof candidate.spanId === "string" && typeof candidate.eventId === "string";
2717
+ }
2718
+ function attrsFrom(metadata) {
2719
+ return Object.entries(withMetadataPrefix(metadata)).map(([key, value]) => attrString(key, value));
2720
+ }
2721
+ function attrsExact(attributes) {
2722
+ return Object.entries(attributes).map(([key, value]) => attrString(key, value));
2723
+ }
2724
+ function handoffSpanAttrs(link) {
2725
+ if (!link) return [];
2726
+ return attrsFrom(detachedChildMetadata(link));
2727
+ }
2728
+ function subagentNameAttrs(name, link) {
2729
+ if (!name || (link == null ? void 0 : link.name)) return [];
2730
+ return attrsFrom({ [HANDOFF_ATTRIBUTE_SUFFIXES.name]: name });
2731
+ }
2732
+ function cancelledSpanAttrs() {
2733
+ return attrsExact(cancelledTerminalAttributes());
2734
+ }
2735
+ function describeAbortReason(reason) {
2736
+ if (reason instanceof Error) return `Aborted: ${reason.message}`;
2737
+ if (typeof reason === "string" && reason.trim().length > 0) return reason;
2738
+ if (reason === void 0 || reason === null) return SUBAGENT_ABORTED_OUTPUT;
2739
+ const serialized = boundedStringify(reason);
2740
+ return serialized ? `Aborted: ${serialized}` : SUBAGENT_ABORTED_OUTPUT;
2741
+ }
2742
+ function stampOpenSpan(span, metadata) {
2743
+ if (span.endTimeUnixNano) return;
2744
+ span.attributes.push(...attrsFrom(metadata));
2745
+ }
2746
+ function stampOpenSpanExact(span, attributes) {
2747
+ if (span.endTimeUnixNano) return;
2748
+ span.attributes.push(...attrsExact(attributes));
2749
+ }
2750
+ var SubagentApi = class {
2751
+ constructor(opts) {
2752
+ var _a;
2753
+ this.opts = opts;
2754
+ this.settledEventIds = (_a = opts.settledEventIds) != null ? _a : /* @__PURE__ */ new Set();
2755
+ }
2756
+ /** True when this child's outcome has already been reported. */
2757
+ wasSettledExplicitly(eventId) {
2758
+ return this.settledEventIds.has(eventId);
2759
+ }
2760
+ /**
2761
+ * Record an outcome reported somewhere other than `cancel()` / `fail()`, so
2762
+ * first-outcome-wins holds across every path that can state one.
2763
+ *
2764
+ * An aborted generation is such a path: an AbortSignal cancellation IS the
2765
+ * run's outcome, and the `fail(err)` that a catch block around the aborted
2766
+ * call naturally reports would otherwise error the child's spans — which is
2767
+ * the only thing separating `failed` from `cancelled`.
2768
+ */
2769
+ noteSettled(eventId) {
2770
+ this.remember(eventId);
2771
+ }
2772
+ remember(eventId) {
2773
+ if (this.settledEventIds.has(eventId)) return;
2774
+ if (this.settledEventIds.size >= MAX_SETTLED_EVENT_IDS) {
2775
+ const oldest = this.settledEventIds.values().next();
2776
+ if (!oldest.done) this.settledEventIds.delete(oldest.value);
2446
2777
  }
2778
+ this.settledEventIds.add(eventId);
2447
2779
  }
2448
- return void 0;
2449
- }
2450
- function flatUsageSemantics(provider) {
2451
- const normalizedProvider = typeof provider === "string" ? provider.trim().toLowerCase() : void 0;
2452
- if (normalizedProvider === "anthropic" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("anthropic.")) || normalizedProvider === "vertex.anthropic" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("vertex.anthropic."))) {
2453
- return {
2454
- inputTokenSemantics: "exclusive",
2455
- outputTokenSemantics: "total"
2456
- };
2780
+ /**
2781
+ * Record a detached sub-agent on this turn: allocate the child's event id,
2782
+ * stamp the dispatch, and return the headers to send with the job.
2783
+ *
2784
+ * This dispatches nothing — you do, moments later, with the returned headers.
2785
+ * Nothing here waits for the child either, or claims to know how it is doing.
2786
+ * Readers derive that from the child's own event.
2787
+ */
2788
+ subagent(options = {}) {
2789
+ var _a;
2790
+ const childEventId = (_a = options.childEventId) != null ? _a : randomUUID();
2791
+ const name = options.name;
2792
+ try {
2793
+ return this.recordLaunch(childEventId, name, options);
2794
+ } catch (err) {
2795
+ if (this.opts.debug) {
2796
+ console.warn(
2797
+ `[raindrop-ai/ai-sdk] sub-agent dispatch not recorded: ${err instanceof Error ? err.message : err}`
2798
+ );
2799
+ }
2800
+ return { childEventId, name, headers: {}, carrier: null };
2801
+ }
2457
2802
  }
2458
- if (normalizedProvider === "openai" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("openai.")) || normalizedProvider === "azure" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("azure."))) {
2459
- return {
2460
- inputTokenSemantics: "total",
2461
- outputTokenSemantics: "total"
2803
+ recordLaunch(childEventId, name, options) {
2804
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
2805
+ const active = (_a = this.opts.spanSource) == null ? void 0 : _a.activeDispatch();
2806
+ const inherited = getContextManager().getParentSpanIds();
2807
+ 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;
2808
+ 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;
2809
+ 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;
2810
+ if (!eventId) {
2811
+ return { childEventId, name, headers: {}, carrier: null };
2812
+ }
2813
+ const dispatch = detachedDispatchMetadata({ childEventId, name });
2814
+ const toolEvents = toolEventsAllowMetadata();
2815
+ for (const span of (_l = active == null ? void 0 : active.turnSpans) != null ? _l : []) {
2816
+ stampOpenSpan(span, toolEvents);
2817
+ }
2818
+ let dispatchIds;
2819
+ if (active == null ? void 0 : active.dispatchSpan) {
2820
+ stampOpenSpan(active.dispatchSpan, dispatch);
2821
+ dispatchIds = active.dispatchSpan.ids;
2822
+ } else if (this.opts.sendTraces) {
2823
+ dispatchIds = this.synthesizeDispatchSpan({
2824
+ childEventId,
2825
+ name,
2826
+ toolName: options.toolName,
2827
+ eventId,
2828
+ userId,
2829
+ convoId,
2830
+ input: options.input,
2831
+ // No active turn means no telemetry setting to honor: `input` is then
2832
+ // recorded on the explicit say-so of whoever passed it.
2833
+ recordInputs: (_m = active == null ? void 0 : active.recordInputs) != null ? _m : true,
2834
+ dispatch,
2835
+ parent: (inherited == null ? void 0 : inherited.eventId) === eventId ? inherited : void 0
2836
+ }).ids;
2837
+ }
2838
+ const traceId = base64ToHex((_o = (_n = dispatchIds == null ? void 0 : dispatchIds.traceIdB64) != null ? _n : inherited == null ? void 0 : inherited.traceIdB64) != null ? _o : "");
2839
+ const spanId = base64ToHex((_p = dispatchIds == null ? void 0 : dispatchIds.spanIdB64) != null ? _p : "");
2840
+ if (!traceId || !spanId) {
2841
+ if (this.opts.debug) {
2842
+ console.warn(
2843
+ "[raindrop-ai/ai-sdk] sub-agent dispatch recorded without a carrier: no dispatch span to reference (traces disabled?)"
2844
+ );
2845
+ }
2846
+ return { childEventId, name, headers: {}, carrier: null };
2847
+ }
2848
+ const carrier = {
2849
+ traceId,
2850
+ spanId,
2851
+ eventId,
2852
+ childEventId,
2853
+ ...name ? { name } : {},
2854
+ ...convoId ? { convoId } : {},
2855
+ ...userId ? { userId } : {}
2462
2856
  };
2857
+ return { childEventId, name, headers: toHeaders(carrier), carrier };
2463
2858
  }
2464
- if (normalizedProvider === "google" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("google."))) {
2859
+ /**
2860
+ * Record a dispatch span for a launch with no open tool-call span to decorate:
2861
+ * a launch from outside a tool's `execute`, or from a caller that is not an
2862
+ * LLM turn at all (an HTTP handler that enqueues jobs). Shaped as a tool call
2863
+ * so it reads identically to a model-issued launch.
2864
+ */
2865
+ synthesizeDispatchSpan(args) {
2866
+ var _a;
2867
+ const spanName = (_a = args.toolName) != null ? _a : DEFAULT_DISPATCH_SPAN_NAME;
2868
+ const span = this.opts.traceShipper.startSpan({
2869
+ name: spanName,
2870
+ parent: args.parent,
2871
+ eventId: args.eventId,
2872
+ userId: args.userId,
2873
+ convoId: args.convoId,
2874
+ operationId: "ai.toolCall",
2875
+ attributes: [
2876
+ attrString("operation.name", "ai.toolCall"),
2877
+ attrString("resource.name", spanName),
2878
+ attrString("ai.toolCall.name", spanName),
2879
+ attrString("ai.toolCall.id", `call_${args.childEventId.replace(/-/g, "").slice(0, 12)}`),
2880
+ // Gated like every other input the turn's spans record: a caller that
2881
+ // disabled input capture must not leak the payload through the one
2882
+ // span this API synthesizes on its behalf.
2883
+ ...args.recordInputs ? [attrString("ai.toolCall.args", boundedStringify(args.input))] : [],
2884
+ ...attrsFrom(args.dispatch)
2885
+ ]
2886
+ });
2887
+ this.opts.traceShipper.endSpan(span, {
2888
+ // A dispatch returns a handle, not an answer — the answer is the child's.
2889
+ attributes: [
2890
+ attrString(
2891
+ "ai.toolCall.result",
2892
+ boundedStringify({ jobId: args.childEventId, status: "accepted" })
2893
+ )
2894
+ ]
2895
+ });
2896
+ return span;
2897
+ }
2898
+ /**
2899
+ * Adopt a carrier as the current run's parent reference.
2900
+ *
2901
+ * A missing carrier is a legitimate state — the child was invoked directly
2902
+ * rather than dispatched — so this always returns a usable run and leaves
2903
+ * `parent` null. Call sites stay unconditional.
2904
+ */
2905
+ resume(carrierOrHeaders, options = {}) {
2906
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
2907
+ const carrier = carrierOrHeaders ? isTraceCarrier(carrierOrHeaders) ? carrierOrHeaders : this.readCarrier(carrierOrHeaders) : null;
2908
+ warnUnresolvedCarrier(carrierOrHeaders, carrier);
2909
+ const name = (_a = carrier == null ? void 0 : carrier.name) != null ? _a : options.name;
2910
+ const eventId = (_c = (_b = carrier == null ? void 0 : carrier.childEventId) != null ? _b : options.eventId) != null ? _c : randomUUID();
2911
+ 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;
2912
+ 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;
2913
+ const parent = carrier ? {
2914
+ parentEventId: carrier.eventId,
2915
+ ...carrier.spanId ? { parentSpanId: carrier.spanId } : {},
2916
+ ...name ? { name } : {}
2917
+ } : null;
2465
2918
  return {
2466
- inputTokenSemantics: "total",
2467
- // Google v5 reports candidate output and thoughts separately.
2468
- outputTokenSemantics: "exclusive"
2919
+ eventId,
2920
+ name,
2921
+ userId,
2922
+ convoId,
2923
+ parent,
2924
+ metadata: {
2925
+ eventId,
2926
+ ...userId ? { userId } : {},
2927
+ ...convoId ? { convoId } : {},
2928
+ ...parent ? { subagent: parent } : {}
2929
+ },
2930
+ cancel: (reason) => this.settle(eventId, { userId, convoId, name, cancelled: true, output: reason }),
2931
+ fail: (reason) => this.settle(eventId, {
2932
+ userId,
2933
+ convoId,
2934
+ name,
2935
+ handoff: parent != null ? parent : void 0,
2936
+ cancelled: false,
2937
+ output: describeAbortReason(reason),
2938
+ error: reason
2939
+ })
2469
2940
  };
2470
2941
  }
2471
- return {};
2942
+ /**
2943
+ * A carrier arrives from outside this process, so a hostile or merely broken
2944
+ * header bag must cost the job its link, never its run.
2945
+ */
2946
+ readCarrier(headers) {
2947
+ try {
2948
+ return fromHeaders(headers);
2949
+ } catch (err) {
2950
+ if (this.opts.debug) {
2951
+ console.warn(
2952
+ `[raindrop-ai/ai-sdk] sub-agent carrier ignored: ${err instanceof Error ? err.message : err}`
2953
+ );
2954
+ }
2955
+ return null;
2956
+ }
2957
+ }
2958
+ /**
2959
+ * Mark a failed child's own spans as errored.
2960
+ *
2961
+ * Reporting the reason as output is what gets the child an event at all, but
2962
+ * output alone is not enough: status is derived from span shape, and a child
2963
+ * with final output and no error spans derives `finished`. A failed job
2964
+ * reporting success is worse than one reporting nothing, so the failure has
2965
+ * to land on the telemetry too, not just in the text.
2966
+ *
2967
+ * This is the child describing its own run, not a caller writing a status it
2968
+ * cannot observe — the child's own spans are exactly where the contract puts
2969
+ * failure.
2970
+ */
2971
+ recordFailureOnSpans(eventId, args, reason) {
2972
+ var _a, _b, _c;
2973
+ if (!this.opts.sendTraces) return;
2974
+ const failure = (_a = args.error) != null ? _a : reason;
2975
+ let marked = 0;
2976
+ for (const span2 of (_c = (_b = this.opts.spanSource) == null ? void 0 : _b.openSpansForEvent(eventId)) != null ? _c : []) {
2977
+ if (span2.endTimeUnixNano) continue;
2978
+ this.opts.traceShipper.endSpan(span2, { error: failure });
2979
+ marked++;
2980
+ }
2981
+ if (marked > 0) return;
2982
+ const spanName = SUBAGENT_ABORT_SPAN_NAME;
2983
+ const span = this.opts.traceShipper.startSpan({
2984
+ name: spanName,
2985
+ eventId,
2986
+ userId: args.userId,
2987
+ convoId: args.convoId,
2988
+ // Required, not decorative: ingest drops any span carrying no
2989
+ // `ai.operationId` (or traceloop / `gen_ai.*` key) and still answers 200,
2990
+ // so without this the failure disappears silently. The value is
2991
+ // deliberately none of the generate/stream/tool/embed forms, which is
2992
+ // what classifies the span as INTERNAL rather than mislabelling a failed
2993
+ // job as a model call or a tool call.
2994
+ operationId: SUBAGENT_FAILED_OPERATION_ID,
2995
+ // Carries the reverse reference like every other span the child emits:
2996
+ // this is often the child's ONLY span, and a span read on its own is the
2997
+ // whole reason the reference cannot live on the root alone. The name is
2998
+ // stamped even for an unlinked run, which has no caller to reference —
2999
+ // `span_name` no longer says which sub-agent this was, so the attribute
3000
+ // is the only thing that can.
3001
+ attributes: [
3002
+ attrString("resource.name", spanName),
3003
+ ...handoffSpanAttrs(args.handoff),
3004
+ ...subagentNameAttrs(args.name, args.handoff)
3005
+ ]
3006
+ });
3007
+ this.opts.traceShipper.endSpan(span, { error: failure });
3008
+ }
3009
+ async settle(eventId, args) {
3010
+ var _a, _b;
3011
+ if (this.settledEventIds.has(eventId)) {
3012
+ if (this.opts.debug) {
3013
+ console.warn(
3014
+ `[raindrop-ai/ai-sdk] sub-agent ${eventId} already reported an outcome; ignoring the second one`
3015
+ );
3016
+ }
3017
+ return;
3018
+ }
3019
+ this.remember(eventId);
3020
+ const output = args.output && args.output.trim().length > 0 ? args.output : args.cancelled ? SUBAGENT_CANCELLED_OUTPUT : SUBAGENT_ABORTED_OUTPUT;
3021
+ try {
3022
+ if (args.cancelled) {
3023
+ for (const span of (_b = (_a = this.opts.spanSource) == null ? void 0 : _a.openSpansForEvent(eventId)) != null ? _b : []) {
3024
+ stampOpenSpanExact(span, cancelledTerminalAttributes());
3025
+ }
3026
+ } else {
3027
+ this.recordFailureOnSpans(eventId, args, output);
3028
+ }
3029
+ } catch (err) {
3030
+ if (this.opts.debug) {
3031
+ console.warn(
3032
+ `[raindrop-ai/ai-sdk] sub-agent outcome not recorded on spans: ${err instanceof Error ? err.message : err}`
3033
+ );
3034
+ }
3035
+ }
3036
+ if (!this.opts.sendEvents) return;
3037
+ await this.opts.eventShipper.patch(eventId, {
3038
+ userId: args.userId,
3039
+ convoId: args.convoId,
3040
+ // An event is only created from a run that reported something. A child
3041
+ // that dies silently produces no event at all, which pins the caller on
3042
+ // `queued` forever — indistinguishable from a job that never started.
3043
+ output,
3044
+ ...args.cancelled ? { properties: { [HANDOFF_TERMINAL_PROPERTY_KEY]: HANDOFF_TERMINAL_CANCELLED } } : {},
3045
+ isPending: false
3046
+ }).catch((err) => {
3047
+ if (this.opts.debug) {
3048
+ console.warn(
3049
+ `[raindrop-ai/ai-sdk] sub-agent outcome patch failed: ${err instanceof Error ? err.message : err}`
3050
+ );
3051
+ }
3052
+ });
3053
+ }
3054
+ };
3055
+
3056
+ // src/internal/usage.ts
3057
+ function firstTokenCount(...values) {
3058
+ for (const value of values) {
3059
+ if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) {
3060
+ return value;
3061
+ }
3062
+ }
3063
+ return void 0;
2472
3064
  }
2473
3065
  var CACHE_WRITE_METADATA_KEYS = [
2474
3066
  ["anthropic", "cacheCreationInputTokens"],
@@ -2486,7 +3078,7 @@ function cacheWriteTokensFromProviderMetadata(providerMetadata) {
2486
3078
  })
2487
3079
  );
2488
3080
  }
2489
- function extractUsageMetricsFromUsage(usage, provider, providerMetadata) {
3081
+ function extractUsageMetricsFromUsage(usage, _provider, providerMetadata) {
2490
3082
  if (!isRecord(usage)) return {};
2491
3083
  const inputTokenValue = usage["inputTokens"];
2492
3084
  const outputTokenValue = usage["outputTokens"];
@@ -2554,7 +3146,7 @@ function extractUsageMetricsFromUsage(usage, provider, providerMetadata) {
2554
3146
  cacheReadInputTokens,
2555
3147
  cachedInputTokens: cacheReadInputTokens,
2556
3148
  cacheWriteInputTokens,
2557
- ...hasStructuredUsage ? {} : flatUsageSemantics(provider)
3149
+ ...hasStructuredUsage ? { usageSource: "ai-sdk-structured" } : {}
2558
3150
  };
2559
3151
  }
2560
3152
 
@@ -2630,6 +3222,7 @@ var RaindropTelemetryIntegration = class {
2630
3222
  eventName: (_f = callMeta.eventName) != null ? _f : (_e = this.defaultContext) == null ? void 0 : _e.eventName
2631
3223
  };
2632
3224
  const inherited = getContextManager().getParentSpanIds();
3225
+ const handoff = readDetachedChildLink(metadata);
2633
3226
  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;
2634
3227
  const explicitEventId = callMeta.eventId && !eventIdGenerated ? callMeta.eventId : void 0;
2635
3228
  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();
@@ -2659,7 +3252,10 @@ var RaindropTelemetryIntegration = class {
2659
3252
  attrString("ai.toolCall.name", subagentName),
2660
3253
  attrString("raindrop.subagent.name", subagentName),
2661
3254
  attrString("raindrop.agent.role", "subagent"),
2662
- ...parentAttrs
3255
+ ...parentAttrs,
3256
+ // Top of this child's tree, so the reverse reference matters as much
3257
+ // here as on the root: these are the spans a reader lands on first.
3258
+ ...handoffSpanAttrs(handoff)
2663
3259
  ]
2664
3260
  });
2665
3261
  const subagentParentRef = this.spanParentRef(subagentToolCallSpan);
@@ -2672,7 +3268,8 @@ var RaindropTelemetryIntegration = class {
2672
3268
  attributes: [
2673
3269
  attrString("operation.name", "agent.subagent"),
2674
3270
  attrString("raindrop.span.kind", "llm_call"),
2675
- attrString("raindrop.subagent.name", subagentName)
3271
+ attrString("raindrop.subagent.name", subagentName),
3272
+ ...handoffSpanAttrs(handoff)
2676
3273
  ]
2677
3274
  });
2678
3275
  this.traceShipper.endSpan(markerSpan);
@@ -2740,7 +3337,9 @@ var RaindropTelemetryIntegration = class {
2740
3337
  inputText: isEmbed ? void 0 : this.extractInputText(event),
2741
3338
  toolCallCount: 0,
2742
3339
  subagentName,
2743
- subagentToolCallSpan
3340
+ subagentToolCallSpan,
3341
+ handoff,
3342
+ nestedInEvent: inheritedParent !== void 0
2744
3343
  });
2745
3344
  };
2746
3345
  // ── onStepStart ─────────────────────────────────────────────────────────
@@ -2785,7 +3384,8 @@ var RaindropTelemetryIntegration = class {
2785
3384
  ...attrsFromModelProvider(event.provider),
2786
3385
  attrString("ai.model.id", event.modelId),
2787
3386
  attrString(MODEL_USAGE_ATTRIBUTES.requestModel, event.modelId),
2788
- ...inputAttrs
3387
+ ...inputAttrs,
3388
+ ...handoffSpanAttrs(state.handoff)
2789
3389
  ]
2790
3390
  });
2791
3391
  state.stepSpan = stepSpan;
@@ -2898,7 +3498,8 @@ var RaindropTelemetryIntegration = class {
2898
3498
  attrInt("ai.usage.totalTokens", usageMetrics.totalTokens),
2899
3499
  attrInt("ai.usage.reasoningTokens", usageMetrics.reasoningTokens),
2900
3500
  attrInt("ai.usage.cachedInputTokens", usageMetrics.cachedInputTokens),
2901
- ...buildModelUsageAttributes(usageMetrics)
3501
+ attrString(MODEL_USAGE_ATTRIBUTES.usageSource, usageMetrics.usageSource),
3502
+ ...buildRawModelUsageAttributes(usageMetrics)
2902
3503
  );
2903
3504
  }
2904
3505
  this.emitProviderExecutedToolSpans(event, state);
@@ -2924,7 +3525,8 @@ var RaindropTelemetryIntegration = class {
2924
3525
  attrString("operation.name", operationName),
2925
3526
  attrString("resource.name", resourceName),
2926
3527
  attrString("ai.telemetry.functionId", state.functionId),
2927
- ...inputAttrs
3528
+ ...inputAttrs,
3529
+ ...handoffSpanAttrs(state.handoff)
2928
3530
  ]
2929
3531
  });
2930
3532
  state.embedSpans.set(event.embedCallId, embedSpan);
@@ -2996,15 +3598,26 @@ var RaindropTelemetryIntegration = class {
2996
3598
  this.traceShipper.endSpan(toolSpan, { error: actualError });
2997
3599
  }
2998
3600
  state.toolSpans.clear();
3601
+ const abortReason = describeAbortReason(actualError);
2999
3602
  if (state.rootSpan) {
3000
- this.traceShipper.endSpan(state.rootSpan, { error: actualError });
3603
+ this.traceShipper.endSpan(state.rootSpan, {
3604
+ error: actualError,
3605
+ attributes: this.abortOutcomeAttrs(state, abortReason, "error")
3606
+ });
3001
3607
  }
3002
3608
  if (state.subagentToolCallSpan) {
3003
3609
  this.traceShipper.endSpan(state.subagentToolCallSpan, { error: actualError });
3004
3610
  }
3005
3611
  const isEmbed = state.operationId === "ai.embed" || state.operationId === "ai.embedMany";
3006
3612
  if (!isEmbed) {
3007
- this.finalizeGenerateEvent(state, state.accumulatedText || void 0, void 0);
3613
+ const errorIsTheRunsOutcome = state.handoff !== void 0 && !state.nestedInEvent;
3614
+ this.finalizeGenerateEvent(
3615
+ state,
3616
+ state.accumulatedText || void 0,
3617
+ void 0,
3618
+ false,
3619
+ errorIsTheRunsOutcome ? { fallbackOutput: abortReason } : void 0
3620
+ );
3008
3621
  }
3009
3622
  this.cleanup(event.callId);
3010
3623
  };
@@ -3041,9 +3654,19 @@ var RaindropTelemetryIntegration = class {
3041
3654
  this.traceShipper.endSpan(toolSpan, { attributes: [abortedAttr] });
3042
3655
  }
3043
3656
  state.toolSpans.clear();
3657
+ const abortIsTheRunsOutcome = state.handoff !== void 0 && !state.nestedInEvent;
3044
3658
  if (state.rootSpan) {
3045
3659
  this.traceShipper.endSpan(state.rootSpan, {
3046
- attributes: [abortedAttr, attrInt("ai.toolCall.count", state.toolCallCount)]
3660
+ attributes: [
3661
+ abortedAttr,
3662
+ attrInt("ai.toolCall.count", state.toolCallCount),
3663
+ // An aborted detached child IS a cancelled sub-agent, and a cancelled
3664
+ // run is span-for-span identical to a finished one — spans close,
3665
+ // nothing errors, there is just no answer. So it is the one outcome
3666
+ // that has to be stated, and the child states it on itself.
3667
+ ...abortIsTheRunsOutcome ? cancelledSpanAttrs() : [],
3668
+ ...abortIsTheRunsOutcome ? this.abortOutcomeAttrs(state, SUBAGENT_CANCELLED_OUTPUT, "stop") : []
3669
+ ]
3047
3670
  });
3048
3671
  }
3049
3672
  if (state.subagentToolCallSpan) {
@@ -3051,7 +3674,17 @@ var RaindropTelemetryIntegration = class {
3051
3674
  attributes: [abortedAttr]
3052
3675
  });
3053
3676
  }
3054
- this.finalizeGenerateEvent(state, state.accumulatedText || void 0, void 0);
3677
+ this.finalizeGenerateEvent(
3678
+ state,
3679
+ state.accumulatedText || void 0,
3680
+ void 0,
3681
+ false,
3682
+ abortIsTheRunsOutcome ? {
3683
+ fallbackOutput: SUBAGENT_CANCELLED_OUTPUT,
3684
+ properties: { [HANDOFF_TERMINAL_PROPERTY_KEY]: HANDOFF_TERMINAL_CANCELLED }
3685
+ } : void 0
3686
+ );
3687
+ if (abortIsTheRunsOutcome) this.subagents.noteSettled(state.eventId);
3055
3688
  this.cleanup(callId);
3056
3689
  };
3057
3690
  // ── executeTool ─────────────────────────────────────────────────────────
@@ -3079,6 +3712,97 @@ var RaindropTelemetryIntegration = class {
3079
3712
  this.subagentWrapping = opts.subagentWrapping !== false;
3080
3713
  this.debug = opts.debug === true;
3081
3714
  this.defaultContext = opts.context;
3715
+ this.subagents = new SubagentApi({
3716
+ traceShipper: this.traceShipper,
3717
+ eventShipper: this.eventShipper,
3718
+ sendTraces: this.sendTraces,
3719
+ sendEvents: this.sendEvents,
3720
+ debug: this.debug,
3721
+ defaultContext: this.defaultContext,
3722
+ settledEventIds: opts.settledEventIds,
3723
+ spanSource: {
3724
+ activeDispatch: () => this.activeDispatch(),
3725
+ openSpansForEvent: (eventId) => this.openSpansForEvent(eventId)
3726
+ }
3727
+ });
3728
+ }
3729
+ /**
3730
+ * Record a detached sub-agent on the turn that is live right now.
3731
+ *
3732
+ * Returns the dispatch — the child's event id and the headers to send with
3733
+ * the job. Dispatching is still yours to do; this only states that you are
3734
+ * about to, so a reader can follow the link before the child exists.
3735
+ */
3736
+ subagent(options = {}) {
3737
+ return this.subagents.subagent(options);
3738
+ }
3739
+ // ── detached sub-agent hand-offs ─────────────────────────────────────────
3740
+ /**
3741
+ * The turn a `subagent()` dispatch is happening inside.
3742
+ *
3743
+ * Resolved from the parent-tool context first, which is the only way to reach
3744
+ * the EXACT span that dispatched: the tool call the model itself issued, still
3745
+ * open while its `execute` runs. Falling back to the event id lets a launch
3746
+ * from elsewhere in the turn (a queue producer called mid-generation) still
3747
+ * find the turn's spans, which is where the tool-events opt-in has to land.
3748
+ */
3749
+ activeDispatch() {
3750
+ var _a;
3751
+ const parentTool = getCurrentParentToolContext();
3752
+ let state = parentTool ? this.getState(parentTool.parentCallId) : void 0;
3753
+ const inheritedEventId = (_a = getContextManager().getParentSpanIds()) == null ? void 0 : _a.eventId;
3754
+ if (!state && inheritedEventId) {
3755
+ for (const candidate of this.callStates.values()) {
3756
+ if (candidate.eventId === inheritedEventId) {
3757
+ state = candidate;
3758
+ break;
3759
+ }
3760
+ }
3761
+ }
3762
+ if (!state) return void 0;
3763
+ return {
3764
+ eventId: state.eventId,
3765
+ userId: state.identity.userId,
3766
+ convoId: state.identity.convoId,
3767
+ dispatchSpan: parentTool ? state.toolSpans.get(parentTool.toolCallId) : void 0,
3768
+ turnSpans: [state.rootSpan, state.stepSpan].filter(
3769
+ (span) => span !== void 0
3770
+ ),
3771
+ recordInputs: state.recordInputs
3772
+ };
3773
+ }
3774
+ /** Spans still open for an event, so a late outcome can still be stated. */
3775
+ openSpansForEvent(eventId) {
3776
+ const spans = [];
3777
+ for (const state of this.callStates.values()) {
3778
+ if (state.eventId !== eventId) continue;
3779
+ if (state.rootSpan) spans.push(state.rootSpan);
3780
+ if (state.stepSpan) spans.push(state.stepSpan);
3781
+ }
3782
+ return spans;
3783
+ }
3784
+ /**
3785
+ * End-attributes that keep a detached child legible when it ends without an
3786
+ * answer — an error, an abort, a cancellation.
3787
+ *
3788
+ * An event is created from an LLM span only when it has a finish reason and
3789
+ * non-empty output, so a child that dies silently produces NO event, and the
3790
+ * caller's hand-off pill stays on `queued` forever — indistinguishable from a
3791
+ * job that never started. Reporting the abort reason as the run's output is
3792
+ * what makes the outcome visible. Only detached children get this: an inline
3793
+ * generation's failure is already legible from its caller's own event.
3794
+ *
3795
+ * And only the run's OUTERMOST generation gets it (see `nestedInEvent`): an
3796
+ * inner sub-call ending badly is not the run ending, and since an event is
3797
+ * created from an LLM span with output, `ai.response.text` here would state
3798
+ * the run's outcome through the span while the turn is still working.
3799
+ */
3800
+ abortOutcomeAttrs(state, reason, finishReason) {
3801
+ if (!state.handoff || state.nestedInEvent) return [];
3802
+ return [
3803
+ attrString("ai.response.text", capText2(state.accumulatedText || reason)),
3804
+ attrString("ai.response.finishReason", finishReason)
3805
+ ];
3082
3806
  }
3083
3807
  // ── helpers ──────────────────────────────────────────────────────────────
3084
3808
  getState(callId) {
@@ -3197,7 +3921,8 @@ var RaindropTelemetryIntegration = class {
3197
3921
  attrString("ai.telemetry.functionId", state.functionId),
3198
3922
  attrString("ai.toolCall.name", toolCall.toolName),
3199
3923
  attrString("ai.toolCall.id", toolCall.toolCallId),
3200
- ...inputAttrs
3924
+ ...inputAttrs,
3925
+ ...handoffSpanAttrs(state.handoff)
3201
3926
  ]
3202
3927
  });
3203
3928
  state.toolSpans.set(toolCall.toolCallId, toolSpan);
@@ -3276,7 +4001,8 @@ var RaindropTelemetryIntegration = class {
3276
4001
  attrString("ai.toolCall.name", call.toolName),
3277
4002
  attrString("ai.toolCall.id", call.toolCallId),
3278
4003
  attrString("ai.toolCall.providerExecuted", "true"),
3279
- ...inputAttrs
4004
+ ...inputAttrs,
4005
+ ...handoffSpanAttrs(state.handoff)
3280
4006
  ]
3281
4007
  });
3282
4008
  state.toolCallCount += 1;
@@ -3357,19 +4083,22 @@ var RaindropTelemetryIntegration = class {
3357
4083
  * is finalized by that resume — otherwise each execution would finalize the
3358
4084
  * same event ID into a separate canonical row.
3359
4085
  */
3360
- finalizeGenerateEvent(state, output, model, keepPending = false) {
4086
+ finalizeGenerateEvent(state, output, model, keepPending = false, detachedOutcome) {
3361
4087
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
3362
4088
  const suppressSubagentEvent = state.subagentName !== void 0 && state.subagentToolCallSpan !== void 0;
3363
4089
  if (!this.sendEvents || suppressSubagentEvent) return;
4090
+ if (this.subagents.wasSettledExplicitly(state.eventId)) return;
3364
4091
  const callMeta = this.extractRaindropMetadata(state.metadata);
3365
4092
  const userId = (_b = callMeta.userId) != null ? _b : (_a = this.defaultContext) == null ? void 0 : _a.userId;
3366
4093
  if (!userId) return;
3367
4094
  const eventName = (_e = (_d = callMeta.eventName) != null ? _d : (_c = this.defaultContext) == null ? void 0 : _c.eventName) != null ? _e : state.operationId;
3368
4095
  const cappedOutput = capText2(output);
4096
+ const reportedOutput = state.handoff && detachedOutcome && !(cappedOutput == null ? void 0 : cappedOutput.trim()) ? detachedOutcome.fallbackOutput : cappedOutput;
3369
4097
  const input = capText2(state.inputText);
3370
4098
  const properties = {
3371
4099
  ...(_f = this.defaultContext) == null ? void 0 : _f.properties,
3372
- ...callMeta.properties
4100
+ ...callMeta.properties,
4101
+ ...state.handoff ? detachedOutcome == null ? void 0 : detachedOutcome.properties : void 0
3373
4102
  };
3374
4103
  const featureFlags = {
3375
4104
  ...((_g = this.defaultContext) == null ? void 0 : _g.featureFlags) ? normalizeFeatureFlags(this.defaultContext.featureFlags) : {},
@@ -3381,7 +4110,7 @@ var RaindropTelemetryIntegration = class {
3381
4110
  userId,
3382
4111
  convoId,
3383
4112
  input,
3384
- output: cappedOutput,
4113
+ output: reportedOutput,
3385
4114
  model,
3386
4115
  properties: Object.keys(properties).length > 0 ? properties : void 0,
3387
4116
  featureFlags: Object.keys(featureFlags).length > 0 ? featureFlags : void 0,
@@ -3718,9 +4447,7 @@ function extractRaindropMetadata(metadata) {
3718
4447
  } catch (e) {
3719
4448
  }
3720
4449
  } else if (featureFlags && typeof featureFlags === "object") {
3721
- result.featureFlags = normalizeFeatureFlags(
3722
- featureFlags
3723
- );
4450
+ result.featureFlags = normalizeFeatureFlags(featureFlags);
3724
4451
  }
3725
4452
  return result;
3726
4453
  }
@@ -3931,12 +4658,7 @@ function setupOperation(params) {
3931
4658
  ...attrsFromTelemetryMetadata(telemetry == null ? void 0 : telemetry.metadata),
3932
4659
  ...attrsFromHeaders(isRecord(arg) ? arg["headers"] : void 0),
3933
4660
  ...attrsFromSettings(arg),
3934
- ...(telemetry == null ? void 0 : telemetry.recordInputs) === false ? [] : [
3935
- attrString(
3936
- "ai.prompt",
3937
- safeJsonWithUint8(normalizePromptAttr(arg))
3938
- )
3939
- ]
4661
+ ...(telemetry == null ? void 0 : telemetry.recordInputs) === false ? [] : [attrString("ai.prompt", safeJsonWithUint8(normalizePromptAttr(arg)))]
3940
4662
  ]
3941
4663
  }) : void 0;
3942
4664
  const rootParentForChildren = rootSpan ? { traceIdB64: rootSpan.ids.traceIdB64, spanIdB64: rootSpan.ids.spanIdB64 } : inheritedParent;
@@ -4286,13 +5008,17 @@ function wrapAISDK(aiSDK, deps) {
4286
5008
  }
4287
5009
  const useNative = deps.options.nativeTelemetry === true;
4288
5010
  if (useNative) {
4289
- const wrapTimeCtx = resolveContext(deps.options.context, { operation: "wrap", args: void 0 });
5011
+ const wrapTimeCtx = resolveContext(deps.options.context, {
5012
+ operation: "wrap",
5013
+ args: void 0
5014
+ });
4290
5015
  const integration = new RaindropTelemetryIntegration({
4291
5016
  traceShipper: deps.traceShipper,
4292
5017
  eventShipper: deps.eventShipper,
4293
5018
  sendTraces: ((_a = deps.options.send) == null ? void 0 : _a.traces) !== false,
4294
5019
  sendEvents: ((_b = deps.options.send) == null ? void 0 : _b.events) !== false,
4295
5020
  debug,
5021
+ settledEventIds: deps.settledEventIds,
4296
5022
  context: {
4297
5023
  userId: wrapTimeCtx.userId,
4298
5024
  eventId: wrapTimeCtx.eventId,
@@ -4530,7 +5256,13 @@ function wrapAgentGenerate(generate, instance, agentSettings, className, aiSDK,
4530
5256
  ...(telemetry == null ? void 0 : telemetry.recordInputs) === false ? [] : [
4531
5257
  attrString(
4532
5258
  "ai.prompt",
4533
- safeJsonWithUint8(normalizePromptAttr({ system: (_d = mergedArgs["system"]) != null ? _d : mergedArgs["instructions"], prompt: mergedArgs["prompt"], messages: mergedArgs["messages"] }))
5259
+ safeJsonWithUint8(
5260
+ normalizePromptAttr({
5261
+ system: (_d = mergedArgs["system"]) != null ? _d : mergedArgs["instructions"],
5262
+ prompt: mergedArgs["prompt"],
5263
+ messages: mergedArgs["messages"]
5264
+ })
5265
+ )
4534
5266
  )
4535
5267
  ]
4536
5268
  ]
@@ -4744,7 +5476,13 @@ function wrapAgentStream(stream, instance, agentSettings, className, aiSDK, deps
4744
5476
  ...(telemetry == null ? void 0 : telemetry.recordInputs) === false ? [] : [
4745
5477
  attrString(
4746
5478
  "ai.prompt",
4747
- safeJsonWithUint8(normalizePromptAttr({ system: (_d = mergedArgs["system"]) != null ? _d : mergedArgs["instructions"], prompt: mergedArgs["prompt"], messages: mergedArgs["messages"] }))
5479
+ safeJsonWithUint8(
5480
+ normalizePromptAttr({
5481
+ system: (_d = mergedArgs["system"]) != null ? _d : mergedArgs["instructions"],
5482
+ prompt: mergedArgs["prompt"],
5483
+ messages: mergedArgs["messages"]
5484
+ })
5485
+ )
4748
5486
  )
4749
5487
  ]
4750
5488
  ]
@@ -5121,9 +5859,19 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
5121
5859
  for (const part of content) {
5122
5860
  if (isRecord(part)) {
5123
5861
  if ((part["type"] === "reasoning" || part["type"] === "thinking") && typeof ((_a = part["text"]) != null ? _a : part["thinking"]) === "string") {
5124
- sendLocalDebuggerLiveEvent({ traceId, type: "reasoning_delta", content: (_b = part["text"]) != null ? _b : part["thinking"], metadata: liveMeta });
5862
+ sendLocalDebuggerLiveEvent({
5863
+ traceId,
5864
+ type: "reasoning_delta",
5865
+ content: (_b = part["text"]) != null ? _b : part["thinking"],
5866
+ metadata: liveMeta
5867
+ });
5125
5868
  } else if (part["type"] === "text" && typeof part["text"] === "string") {
5126
- sendLocalDebuggerLiveEvent({ traceId, type: "text_delta", content: part["text"], metadata: liveMeta });
5869
+ sendLocalDebuggerLiveEvent({
5870
+ traceId,
5871
+ type: "text_delta",
5872
+ content: part["text"],
5873
+ metadata: liveMeta
5874
+ });
5127
5875
  }
5128
5876
  }
5129
5877
  }
@@ -5204,7 +5952,10 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
5204
5952
  attributes: [
5205
5953
  ...((_a = ctx.telemetry) == null ? void 0 : _a.recordOutputs) === false ? [] : [
5206
5954
  attrString("ai.response.finishReason", finishReason),
5207
- attrString("ai.response.text", activeText.length ? capText2(activeText) : void 0),
5955
+ attrString(
5956
+ "ai.response.text",
5957
+ activeText.length ? capText2(activeText) : void 0
5958
+ ),
5208
5959
  attrString(
5209
5960
  "ai.response.toolCalls",
5210
5961
  safeJsonWithUint8(toolCallsLocal.length ? toolCallsLocal : void 0)
@@ -5222,7 +5973,8 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
5222
5973
  ...finishReason ? [attrStringArray("gen_ai.response.finish_reasons", [finishReason])] : [],
5223
5974
  attrString("gen_ai.response.id", responseId),
5224
5975
  attrString(MODEL_USAGE_ATTRIBUTES.responseModel, finalResponseModelId),
5225
- ...buildModelUsageAttributes(usageMetrics),
5976
+ attrString(MODEL_USAGE_ATTRIBUTES.usageSource, usageMetrics.usageSource),
5977
+ ...buildRawModelUsageAttributes(usageMetrics),
5226
5978
  ...msToFirstChunk !== void 0 ? [attrInt("ai.stream.msToFirstChunk", msToFirstChunk)] : [],
5227
5979
  ...msToFinish !== void 0 ? [attrInt("ai.stream.msToFinish", msToFinish)] : [],
5228
5980
  ...avgOutTokensPerSecond !== void 0 ? [attrDouble("ai.stream.avgOutputTokensPerSecond", avgOutTokensPerSecond)] : [],
@@ -5276,19 +6028,44 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
5276
6028
  if ("providerMetadata" in value) providerMetadata = value["providerMetadata"];
5277
6029
  if (localDebuggerEnabled() && ctx.rootParentForChildren) {
5278
6030
  const traceId = ctx.rootParentForChildren.traceIdB64;
5279
- const liveMeta = getLocalDebuggerMetadata({ ...ctx.context, eventId: ctx.eventId });
6031
+ const liveMeta = getLocalDebuggerMetadata({
6032
+ ...ctx.context,
6033
+ eventId: ctx.eventId
6034
+ });
5280
6035
  if (type === "text-delta") {
5281
6036
  const text = typeof value["delta"] === "string" ? value["delta"] : typeof value["textDelta"] === "string" ? value["textDelta"] : typeof value["text"] === "string" ? value["text"] : void 0;
5282
- if (typeof text === "string" && text) sendLocalDebuggerLiveEvent({ traceId, type: "text_delta", content: text, metadata: liveMeta });
6037
+ if (typeof text === "string" && text)
6038
+ sendLocalDebuggerLiveEvent({
6039
+ traceId,
6040
+ type: "text_delta",
6041
+ content: text,
6042
+ metadata: liveMeta
6043
+ });
5283
6044
  } else if (type === "reasoning" || type === "reasoning-delta") {
5284
6045
  const text = typeof value["delta"] === "string" ? value["delta"] : typeof value["text"] === "string" ? value["text"] : typeof value["thinking"] === "string" ? value["thinking"] : void 0;
5285
- if (typeof text === "string" && text) sendLocalDebuggerLiveEvent({ traceId, type: "reasoning_delta", content: text, metadata: liveMeta });
6046
+ if (typeof text === "string" && text)
6047
+ sendLocalDebuggerLiveEvent({
6048
+ traceId,
6049
+ type: "reasoning_delta",
6050
+ content: text,
6051
+ metadata: liveMeta
6052
+ });
5286
6053
  } else if (type === "tool-call") {
5287
6054
  const toolName = typeof value["toolName"] === "string" ? value["toolName"] : "tool";
5288
- sendLocalDebuggerLiveEvent({ traceId, type: "tool_start", content: toolName, metadata: { ...liveMeta, args: value["args"] } });
6055
+ sendLocalDebuggerLiveEvent({
6056
+ traceId,
6057
+ type: "tool_start",
6058
+ content: toolName,
6059
+ metadata: { ...liveMeta, args: value["args"] }
6060
+ });
5289
6061
  } else if (type === "tool-result") {
5290
6062
  const toolName = typeof value["toolName"] === "string" ? value["toolName"] : "tool";
5291
- sendLocalDebuggerLiveEvent({ traceId, type: "tool_result", content: toolName, metadata: { ...liveMeta, result: value["result"] } });
6063
+ sendLocalDebuggerLiveEvent({
6064
+ traceId,
6065
+ type: "tool_result",
6066
+ content: toolName,
6067
+ metadata: { ...liveMeta, result: value["result"] }
6068
+ });
5292
6069
  }
5293
6070
  }
5294
6071
  }
@@ -5368,11 +6145,7 @@ function endDoGenerateSpan(span, result, modelInfo, ctx) {
5368
6145
  } else {
5369
6146
  responseTimestampIso = (/* @__PURE__ */ new Date()).toISOString();
5370
6147
  }
5371
- const usageMetrics = extractUsageMetricsFromUsage(
5372
- usage,
5373
- modelInfo.provider,
5374
- providerMetadata
5375
- );
6148
+ const usageMetrics = extractUsageMetricsFromUsage(usage, modelInfo.provider, providerMetadata);
5376
6149
  const { inputTokens, outputTokens } = usageMetrics;
5377
6150
  ctx.traceShipper.endSpan(span, {
5378
6151
  attributes: [
@@ -5393,7 +6166,8 @@ function endDoGenerateSpan(span, result, modelInfo, ctx) {
5393
6166
  ...finishReason ? [attrStringArray("gen_ai.response.finish_reasons", [finishReason])] : [],
5394
6167
  attrString("gen_ai.response.id", responseId),
5395
6168
  attrString(MODEL_USAGE_ATTRIBUTES.responseModel, responseModelId),
5396
- ...buildModelUsageAttributes(usageMetrics)
6169
+ attrString(MODEL_USAGE_ATTRIBUTES.usageSource, usageMetrics.usageSource),
6170
+ ...buildRawModelUsageAttributes(usageMetrics)
5397
6171
  ]
5398
6172
  });
5399
6173
  }
@@ -5502,6 +6276,8 @@ function eventMetadata(options) {
5502
6276
  if (options.properties) result["raindrop.properties"] = JSON.stringify(options.properties);
5503
6277
  if (options.featureFlags)
5504
6278
  result["raindrop.featureFlags"] = JSON.stringify(normalizeFeatureFlags(options.featureFlags));
6279
+ if (options.subagent) Object.assign(result, detachedChildMetadata(options.subagent));
6280
+ if (options.toolEvents) result[TOOL_EVENTS_SUFFIX] = options.toolEvents;
5505
6281
  return result;
5506
6282
  }
5507
6283
  function deriveChatTurnMessageId(request) {
@@ -5584,12 +6360,22 @@ function createRaindropAISDK(opts) {
5584
6360
  transformSpan: (_j = opts.traces) == null ? void 0 : _j.transformSpan,
5585
6361
  disableDefaultRedaction: (_k = opts.traces) == null ? void 0 : _k.disableDefaultRedaction
5586
6362
  });
6363
+ const settledEventIds = /* @__PURE__ */ new Set();
6364
+ const subagentApi = new SubagentApi({
6365
+ traceShipper,
6366
+ eventShipper,
6367
+ sendTraces: tracesEnabled,
6368
+ sendEvents: eventsEnabled,
6369
+ debug: envDebug,
6370
+ settledEventIds
6371
+ });
5587
6372
  return {
5588
6373
  wrap(aiSDK, options) {
5589
6374
  return wrapAISDK(aiSDK, {
5590
6375
  options: options != null ? options : {},
5591
6376
  eventShipper,
5592
- traceShipper
6377
+ traceShipper,
6378
+ settledEventIds
5593
6379
  });
5594
6380
  },
5595
6381
  createSelfDiagnosticsTool(options = {}) {
@@ -5626,9 +6412,14 @@ function createRaindropAISDK(opts) {
5626
6412
  sendEvents: eventsEnabled,
5627
6413
  subagentWrapping,
5628
6414
  debug: envDebug,
6415
+ settledEventIds,
5629
6416
  context
5630
6417
  });
5631
6418
  },
6419
+ subagents: subagentApi,
6420
+ subagent(options = {}) {
6421
+ return subagentApi.subagent(options);
6422
+ },
5632
6423
  events: {
5633
6424
  async patch(eventId, patch) {
5634
6425
  await eventShipper.patch(eventId, patch);
@@ -5751,8 +6542,17 @@ function raindrop(options = {}) {
5751
6542
  exports.DEFAULT_MAX_TEXT_FIELD_CHARS = DEFAULT_MAX_TEXT_FIELD_CHARS2;
5752
6543
  exports.DEFAULT_REDACT_ATTRIBUTE_KEYS = DEFAULT_REDACT_ATTRIBUTE_KEYS;
5753
6544
  exports.DEFAULT_SECRET_KEY_NAMES = DEFAULT_SECRET_KEY_NAMES;
6545
+ exports.DETACHED_MODE = DETACHED_MODE;
6546
+ exports.HANDOFF_ATTRIBUTE_PREFIXES = HANDOFF_ATTRIBUTE_PREFIXES;
6547
+ exports.HANDOFF_ATTRIBUTE_SUFFIXES = HANDOFF_ATTRIBUTE_SUFFIXES;
6548
+ exports.HANDOFF_TERMINAL_CANCELLED = HANDOFF_TERMINAL_CANCELLED;
6549
+ exports.HANDOFF_TERMINAL_PROPERTY_KEY = HANDOFF_TERMINAL_PROPERTY_KEY;
5754
6550
  exports.REDACTED_PLACEHOLDER = REDACTED_PLACEHOLDER;
5755
6551
  exports.RaindropTelemetryIntegration = RaindropTelemetryIntegration;
6552
+ exports.SUBAGENT_ABORTED_OUTPUT = SUBAGENT_ABORTED_OUTPUT;
6553
+ exports.SUBAGENT_AGENT_ROLE = SUBAGENT_AGENT_ROLE;
6554
+ exports.SUBAGENT_CANCELLED_OUTPUT = SUBAGENT_CANCELLED_OUTPUT;
6555
+ exports.TOOL_EVENTS_ALLOW = TOOL_EVENTS_ALLOW;
5756
6556
  exports.TRUNCATION_MARKER = TRUNCATION_MARKER2;
5757
6557
  exports._resetParentToolContextStorage = _resetParentToolContextStorage;
5758
6558
  exports._resetRaindropCallMetadataStorage = _resetRaindropCallMetadataStorage;
@@ -5766,6 +6566,7 @@ exports.defaultTransformSpan = defaultTransformSpan;
5766
6566
  exports.enterParentToolContext = enterParentToolContext;
5767
6567
  exports.eventMetadata = eventMetadata;
5768
6568
  exports.eventMetadataFromChatRequest = eventMetadataFromChatRequest;
6569
+ exports.fromHeaders = fromHeaders;
5769
6570
  exports.getContextManager = getContextManager;
5770
6571
  exports.getCurrentParentToolContext = getCurrentParentToolContext;
5771
6572
  exports.getCurrentRaindropCallMetadata = getCurrentRaindropCallMetadata;
@@ -5774,6 +6575,9 @@ exports.raindrop = raindrop;
5774
6575
  exports.readRaindropCallMetadataFromArgs = readRaindropCallMetadataFromArgs;
5775
6576
  exports.redactJsonAttributeValue = redactJsonAttributeValue;
5776
6577
  exports.redactSecretsInObject = redactSecretsInObject;
6578
+ exports.resetUnresolvedCarrierWarning = resetUnresolvedCarrierWarning;
5777
6579
  exports.runWithParentToolContext = runWithParentToolContext;
5778
6580
  exports.runWithRaindropCallMetadata = runWithRaindropCallMetadata;
6581
+ exports.toHeaders = toHeaders;
6582
+ exports.toLangSmithHeaders = toLangSmithHeaders;
5779
6583
  exports.withCurrent = withCurrent;