@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.
@@ -4,7 +4,7 @@ var async_hooks = require('async_hooks');
4
4
 
5
5
  // src/index.node.ts
6
6
 
7
- // ../core/dist/chunk-QNWZIOOY.js
7
+ // ../core/dist/chunk-3V4MIA75.js
8
8
  function normalizeFeatureFlags(input) {
9
9
  if (Array.isArray(input)) {
10
10
  return Object.fromEntries(input.map((name) => [name, "true"]));
@@ -67,6 +67,311 @@ function base64Encode(bytes) {
67
67
  }
68
68
  return out;
69
69
  }
70
+ function base64ToHex(value) {
71
+ if (!value) return "";
72
+ const maybeBuffer = globalThis.Buffer;
73
+ if (maybeBuffer) {
74
+ return maybeBuffer.from(value, "base64").toString("hex");
75
+ }
76
+ const atobFn = globalThis.atob;
77
+ if (typeof atobFn !== "function") return "";
78
+ try {
79
+ const binary = atobFn(value);
80
+ let hex = "";
81
+ for (let i = 0; i < binary.length; i++) {
82
+ hex += (binary.charCodeAt(i) & 255).toString(16).padStart(2, "0");
83
+ }
84
+ return hex;
85
+ } catch (e) {
86
+ return "";
87
+ }
88
+ }
89
+ var HANDOFF_ATTRIBUTE_SUFFIXES = {
90
+ mode: "raindrop.handoff.mode",
91
+ childEventId: "raindrop.handoff.childEventId",
92
+ parentEventId: "raindrop.handoff.parentEventId",
93
+ parentSpanId: "raindrop.handoff.parentSpanId",
94
+ name: "raindrop.handoff.name",
95
+ terminal: "raindrop.handoff.terminal",
96
+ agentRole: "raindrop.agent.role"
97
+ };
98
+ var HANDOFF_ATTRIBUTE_PREFIXES = [
99
+ "ai.telemetry.metadata.",
100
+ "ai.settings.context.",
101
+ ""
102
+ ];
103
+ var AI_SDK_METADATA_PREFIX = "ai.telemetry.metadata.";
104
+ var DETACHED_MODE = "detached";
105
+ var SUBAGENT_AGENT_ROLE = "subagent";
106
+ var HANDOFF_TERMINAL_CANCELLED = "cancelled";
107
+ var TOOL_EVENTS_SUFFIX = "raindrop.toolEvents";
108
+ var TOOL_EVENTS_ALLOW = "allow";
109
+ var SUBAGENT_ABORT_OPERATION_ID = "ai.subagent.failed";
110
+ var SUBAGENT_ABORT_SPAN_NAME = SUBAGENT_ABORT_OPERATION_ID;
111
+ var DEFAULT_DISPATCH_SPAN_NAME = "launch_subagent";
112
+ var HANDOFF_TERMINAL_PROPERTY_KEY = HANDOFF_ATTRIBUTE_SUFFIXES.terminal;
113
+ function defined(entries) {
114
+ const out = {};
115
+ for (const [key, value] of Object.entries(entries)) {
116
+ if (typeof value === "string" && value.trim().length > 0) out[key] = value;
117
+ }
118
+ return out;
119
+ }
120
+ function detachedDispatchMetadata(dispatch) {
121
+ return defined({
122
+ [HANDOFF_ATTRIBUTE_SUFFIXES.mode]: DETACHED_MODE,
123
+ [HANDOFF_ATTRIBUTE_SUFFIXES.childEventId]: dispatch.childEventId,
124
+ [HANDOFF_ATTRIBUTE_SUFFIXES.name]: dispatch.name
125
+ });
126
+ }
127
+ function detachedChildMetadata(link) {
128
+ return defined({
129
+ [HANDOFF_ATTRIBUTE_SUFFIXES.parentEventId]: link.parentEventId,
130
+ [HANDOFF_ATTRIBUTE_SUFFIXES.parentSpanId]: link.parentSpanId,
131
+ [HANDOFF_ATTRIBUTE_SUFFIXES.name]: link.name,
132
+ [HANDOFF_ATTRIBUTE_SUFFIXES.agentRole]: SUBAGENT_AGENT_ROLE
133
+ });
134
+ }
135
+ function cancelledTerminalMetadata() {
136
+ return { [HANDOFF_ATTRIBUTE_SUFFIXES.terminal]: HANDOFF_TERMINAL_CANCELLED };
137
+ }
138
+ function cancelledTerminalAttributes() {
139
+ const bare = cancelledTerminalMetadata();
140
+ return { ...bare, ...withMetadataPrefix(bare) };
141
+ }
142
+ function toolEventsAllowMetadata() {
143
+ return { [TOOL_EVENTS_SUFFIX]: TOOL_EVENTS_ALLOW };
144
+ }
145
+ function withMetadataPrefix(metadata) {
146
+ const out = {};
147
+ for (const [key, value] of Object.entries(metadata)) {
148
+ out[key.startsWith(AI_SDK_METADATA_PREFIX) ? key : `${AI_SDK_METADATA_PREFIX}${key}`] = value;
149
+ }
150
+ return out;
151
+ }
152
+ function readHandoffField(metadata, suffix) {
153
+ for (const prefix of HANDOFF_ATTRIBUTE_PREFIXES) {
154
+ const value = metadata[`${prefix}${suffix}`];
155
+ if (typeof value === "string" && value.trim().length > 0) return value.trim();
156
+ }
157
+ return void 0;
158
+ }
159
+ function readDetachedChildLink(metadata) {
160
+ if (!metadata) return void 0;
161
+ const parentEventId = readHandoffField(metadata, HANDOFF_ATTRIBUTE_SUFFIXES.parentEventId);
162
+ if (!parentEventId) return void 0;
163
+ return {
164
+ parentEventId,
165
+ parentSpanId: readHandoffField(metadata, HANDOFF_ATTRIBUTE_SUFFIXES.parentSpanId),
166
+ name: readHandoffField(metadata, HANDOFF_ATTRIBUTE_SUFFIXES.name)
167
+ };
168
+ }
169
+ var BAGGAGE_KEYS = {
170
+ eventId: "raindrop-event-id",
171
+ childEventId: "raindrop-child-event-id",
172
+ name: "raindrop-handoff-name",
173
+ convoId: "raindrop-convo-id",
174
+ userId: "raindrop-user-id",
175
+ // The dispatch span and its trace, carried as fields as well as in
176
+ // `traceparent`. Not redundant: OTel's HTTP instrumentations rewrite
177
+ // `traceparent` from whatever span is current as the request goes out, so by
178
+ // the time the child reads it the ids name the HTTP client span and its trace
179
+ // instead of the dispatch. The child would then point its reverse reference at
180
+ // a span the launcher's UI does not know as a dispatch. A field states which
181
+ // span it means rather than meaning "whoever wrote this header last".
182
+ dispatchSpanId: "raindrop-dispatch-span-id",
183
+ traceId: "raindrop-trace-id"
184
+ };
185
+ var TRACEPARENT_HEADER = "traceparent";
186
+ var BAGGAGE_HEADER = "baggage";
187
+ var W3C_TRACE_ID = /^[0-9a-f]{32}$/;
188
+ var W3C_SPAN_ID = /^[0-9a-f]{16}$/;
189
+ function isW3CTraceId(value) {
190
+ return value !== void 0 && W3C_TRACE_ID.test(value);
191
+ }
192
+ function isW3CSpanId(value) {
193
+ return value !== void 0 && W3C_SPAN_ID.test(value);
194
+ }
195
+ var warnedNonConformantIds = false;
196
+ function warnNonConformantIdsOnce(traceId, spanId) {
197
+ if (warnedNonConformantIds) return;
198
+ warnedNonConformantIds = true;
199
+ console.warn(
200
+ `[raindrop] hand-off carrier ids are not W3C-shaped (traceId="${traceId}", spanId="${spanId}"). The child still reports as its own event, but its reverse reference names a span id the backend does not store, so the link back to the launcher will not resolve. A LangSmith carrier reads this way \u2014 its run ids are UUIDs; propagate Raindrop's own carrier (toHeaders) to link.`
201
+ );
202
+ }
203
+ var HANDOFF_HEADER = "x-raindrop-handoff";
204
+ var LANGSMITH_TRACE_HEADER = "langsmith-trace";
205
+ var LANGSMITH_METADATA_BAGGAGE_KEY = "langsmith-metadata";
206
+ function encodeBaggage(entries) {
207
+ return Object.entries(entries).filter((entry) => Boolean(entry[1])).map(([key, value]) => `${key}=${encodeURIComponent(value)}`).join(",");
208
+ }
209
+ function decodeBaggage(header) {
210
+ if (!header) return {};
211
+ const parsed = {};
212
+ for (const part of header.split(",")) {
213
+ const [rawKey, ...rest] = part.split("=");
214
+ if (!rawKey || rest.length === 0) continue;
215
+ const key = rawKey.trim();
216
+ let value;
217
+ try {
218
+ value = decodeURIComponent(rest.join("=").trim());
219
+ } catch (e) {
220
+ value = rest.join("=").trim();
221
+ }
222
+ if (key in parsed && parsed[key] !== value) throw new ConflictingCarrierError(key);
223
+ parsed[key] = value;
224
+ }
225
+ return parsed;
226
+ }
227
+ function carrierBaggage(carrier) {
228
+ return {
229
+ [BAGGAGE_KEYS.eventId]: carrier.eventId,
230
+ [BAGGAGE_KEYS.childEventId]: carrier.childEventId,
231
+ [BAGGAGE_KEYS.name]: carrier.name,
232
+ [BAGGAGE_KEYS.convoId]: carrier.convoId,
233
+ [BAGGAGE_KEYS.userId]: carrier.userId,
234
+ [BAGGAGE_KEYS.dispatchSpanId]: carrier.spanId,
235
+ [BAGGAGE_KEYS.traceId]: carrier.traceId
236
+ };
237
+ }
238
+ function toHeaders(carrier) {
239
+ const fields = encodeBaggage(carrierBaggage(carrier));
240
+ const headers = {
241
+ [BAGGAGE_HEADER]: fields,
242
+ [HANDOFF_HEADER]: fields
243
+ };
244
+ if (isW3CTraceId(carrier.traceId) && isW3CSpanId(carrier.spanId)) {
245
+ headers[TRACEPARENT_HEADER] = `00-${carrier.traceId}-${carrier.spanId}-01`;
246
+ }
247
+ return headers;
248
+ }
249
+ function langsmithStamp() {
250
+ return (/* @__PURE__ */ new Date()).toISOString().replace(/[-:]/g, "").replace(/\.\d+Z$/, "000000");
251
+ }
252
+ function toLangSmithHeaders(carrier) {
253
+ const stamp = langsmithStamp();
254
+ const dottedOrder = `${stamp}Z${carrier.traceId}.${stamp}Z${carrier.spanId}`;
255
+ return {
256
+ [LANGSMITH_TRACE_HEADER]: dottedOrder,
257
+ [BAGGAGE_HEADER]: encodeBaggage({
258
+ [LANGSMITH_METADATA_BAGGAGE_KEY]: JSON.stringify(carrierBaggage(carrier))
259
+ }),
260
+ // Carried here too: a LangSmith-shaped carrier is rewritten in transit
261
+ // exactly like the native one, and an injected `traceparent` is preferred
262
+ // over the dotted order on read.
263
+ [HANDOFF_HEADER]: encodeBaggage(carrierBaggage(carrier))
264
+ };
265
+ }
266
+ function isHeaderLookup(headers) {
267
+ return "get" in headers && typeof headers.get === "function";
268
+ }
269
+ var ConflictingCarrierError = class extends Error {
270
+ };
271
+ function readHeader(headers, name) {
272
+ var _a, _b, _c;
273
+ if (isHeaderLookup(headers)) return (_a = headers.get(name)) != null ? _a : void 0;
274
+ const value = (_c = headers[name]) != null ? _c : (_b = Object.entries(headers).find(([key]) => key.toLowerCase() === name)) == null ? void 0 : _b[1];
275
+ if (!Array.isArray(value)) return value;
276
+ const distinct = new Set(value);
277
+ if (distinct.size > 1) throw new ConflictingCarrierError(name);
278
+ return value[0];
279
+ }
280
+ function readTraceHeader(headers, name) {
281
+ const value = readHeader(headers, name);
282
+ if (!(value == null ? void 0 : value.includes(","))) return value;
283
+ const copies = value.split(",").map((copy) => copy.trim());
284
+ if (new Set(copies).size > 1) throw new ConflictingCarrierError(name);
285
+ return copies[0];
286
+ }
287
+ function fromHeaders(headers) {
288
+ var _a, _b;
289
+ let baggage;
290
+ let handoff;
291
+ let traceparent;
292
+ let langsmithTrace;
293
+ try {
294
+ baggage = decodeBaggage(readHeader(headers, BAGGAGE_HEADER));
295
+ handoff = decodeBaggage(readHeader(headers, HANDOFF_HEADER));
296
+ traceparent = readTraceHeader(headers, TRACEPARENT_HEADER);
297
+ langsmithTrace = readTraceHeader(headers, LANGSMITH_TRACE_HEADER);
298
+ } catch (error) {
299
+ if (error instanceof ConflictingCarrierError) return null;
300
+ throw error;
301
+ }
302
+ const langsmithMetadata = baggage[LANGSMITH_METADATA_BAGGAGE_KEY];
303
+ const nested = langsmithMetadata ? safeParseStringRecord(langsmithMetadata) : {};
304
+ for (const [key, value] of Object.entries(nested)) {
305
+ if (key in baggage && baggage[key] !== value) return null;
306
+ }
307
+ const fields = {
308
+ ...baggage,
309
+ ...nested,
310
+ // Last, so it wins: the standard headers may have been rewritten in transit
311
+ // by a propagator, this one is only ever written by us.
312
+ ...handoff
313
+ };
314
+ let traceId;
315
+ let spanId;
316
+ if (traceparent) {
317
+ const [, parsedTraceId, parsedSpanId] = traceparent.split("-");
318
+ if (isW3CTraceId(parsedTraceId) && isW3CSpanId(parsedSpanId)) {
319
+ traceId = parsedTraceId;
320
+ spanId = parsedSpanId;
321
+ }
322
+ }
323
+ if (!traceId && !spanId && langsmithTrace) {
324
+ const segments = langsmithTrace.split(".");
325
+ traceId = (_a = segments[0]) == null ? void 0 : _a.split("Z").pop();
326
+ spanId = (_b = segments[segments.length - 1]) == null ? void 0 : _b.split("Z").pop();
327
+ }
328
+ traceId = fields[BAGGAGE_KEYS.traceId] || traceId;
329
+ spanId = fields[BAGGAGE_KEYS.dispatchSpanId] || spanId;
330
+ const eventId = fields[BAGGAGE_KEYS.eventId];
331
+ if (!traceId || !spanId || !eventId) return null;
332
+ if (!isW3CTraceId(traceId) || !isW3CSpanId(spanId)) {
333
+ warnNonConformantIdsOnce(traceId, spanId);
334
+ }
335
+ const carrier = { traceId, spanId, eventId };
336
+ const childEventId = fields[BAGGAGE_KEYS.childEventId];
337
+ if (childEventId) carrier.childEventId = childEventId;
338
+ const name = fields[BAGGAGE_KEYS.name];
339
+ if (name) carrier.name = name;
340
+ const convoId = fields[BAGGAGE_KEYS.convoId];
341
+ if (convoId) carrier.convoId = convoId;
342
+ const userId = fields[BAGGAGE_KEYS.userId];
343
+ if (userId) carrier.userId = userId;
344
+ return carrier;
345
+ }
346
+ var UNRESOLVED_CARRIER_WARNING = `[raindrop] resume: headers were supplied but no hand-off carrier was found on them (searched ${HANDOFF_HEADER}, ${TRACEPARENT_HEADER}, ${BAGGAGE_HEADER}). This run reports as an UNLINKED event, and the launcher that dispatched it will stay on "queued" forever because nothing ever references its child. Passing headers means a parent handed off, so no carrier on them is almost certainly a defect: a gateway or proxy stripping ${HANDOFF_HEADER}, a middleware overwriting ${BAGGAGE_HEADER}, a request forwarded without its headers, or a hand-built carrier whose field names do not match. Send every header the launcher's dispatch returned. Logged once per process; pass no headers for a directly-invoked sub-agent to silence it.`;
347
+ var UNRESOLVED_CARRIER_WARNED_KEY = /* @__PURE__ */ Symbol.for("raindrop.handoff.warnedUnresolvedCarrier");
348
+ function warnedHolder() {
349
+ return globalThis;
350
+ }
351
+ function resetUnresolvedCarrierWarning() {
352
+ warnedHolder()[UNRESOLVED_CARRIER_WARNED_KEY] = false;
353
+ }
354
+ function warnUnresolvedCarrier(headers, carrier) {
355
+ if (carrier) return;
356
+ if (!headers) return;
357
+ const holder = warnedHolder();
358
+ if (holder[UNRESOLVED_CARRIER_WARNED_KEY]) return;
359
+ holder[UNRESOLVED_CARRIER_WARNED_KEY] = true;
360
+ console.warn(UNRESOLVED_CARRIER_WARNING);
361
+ }
362
+ function safeParseStringRecord(raw) {
363
+ try {
364
+ const parsed = JSON.parse(raw);
365
+ if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) return {};
366
+ const result = {};
367
+ for (const [key, value] of Object.entries(parsed)) {
368
+ if (typeof value === "string") result[key] = value;
369
+ }
370
+ return result;
371
+ } catch (e) {
372
+ return {};
373
+ }
374
+ }
70
375
  function runWithTracingSuppressed(fn) {
71
376
  const hook = globalThis.RAINDROP_SUPPRESS_TRACING;
72
377
  if (typeof hook !== "function") return fn();
@@ -831,6 +1136,7 @@ var EventShipper = class {
831
1136
  }
832
1137
  };
833
1138
  var MODEL_USAGE_ATTRIBUTES = {
1139
+ usageSource: "raindrop.usage.source",
834
1140
  providerName: "gen_ai.provider.name",
835
1141
  requestModel: "gen_ai.request.model",
836
1142
  responseModel: "gen_ai.response.model",
@@ -839,20 +1145,22 @@ var MODEL_USAGE_ATTRIBUTES = {
839
1145
  reasoningTokens: "gen_ai.usage.reasoning_tokens",
840
1146
  cacheReadInputTokens: "gen_ai.usage.cache_read_input_tokens",
841
1147
  cacheWriteInputTokens: "gen_ai.usage.cache_write_input_tokens",
842
- nonCachedInputTokens: "raindrop.usage.input_tokens.non_cached",
843
- nonReasoningOutputTokens: "raindrop.usage.output_tokens.non_reasoning",
844
- reasoningOutputTokens: "raindrop.usage.output_tokens.reasoning",
845
- cacheReadTokens: "raindrop.usage.input_tokens.cache_read",
846
- cacheWriteTokens: "raindrop.usage.input_tokens.cache_write"
847
- };
1148
+ providerReportedCost: "gen_ai.usage.provider_reported_cost"};
848
1149
  var MODEL_PROVIDER_NAMES = [
1150
+ ["google.vertex.anthropic", "google-vertex"],
1151
+ ["google.vertex_ai", "google-vertex"],
849
1152
  ["google.vertex", "google-vertex"],
1153
+ ["gcp.vertex_ai", "google-vertex"],
1154
+ ["gcp.gemini", "google"],
1155
+ ["google_vertexai", "google-vertex"],
850
1156
  ["vertex.anthropic", "google-vertex"],
851
1157
  ["amazon-bedrock", "amazon-bedrock"],
1158
+ ["aws.bedrock", "amazon-bedrock"],
852
1159
  ["bedrock", "amazon-bedrock"],
853
1160
  ["anthropic", "anthropic"],
854
1161
  ["openai", "openai"],
855
1162
  ["google", "google"],
1163
+ ["az.ai.openai", "azure"],
856
1164
  ["azure", "azure"],
857
1165
  ["openrouter", "openrouter"]
858
1166
  ];
@@ -863,60 +1171,20 @@ function canonicalModelProvider(provider) {
863
1171
  const match = MODEL_PROVIDER_NAMES.find(
864
1172
  ([family]) => normalizedProvider === family || normalizedProvider.startsWith(`${family}.`)
865
1173
  );
866
- return (_a = match == null ? void 0 : match[1]) != null ? _a : provider;
1174
+ return (_a = match == null ? void 0 : match[1]) != null ? _a : normalizedProvider;
867
1175
  }
868
1176
  function tokenCount(value) {
869
1177
  return typeof value === "number" && Number.isSafeInteger(value) && value >= 0 ? value : void 0;
870
1178
  }
871
- function exclusiveTokens({
872
- explicit,
873
- total,
874
- parts,
875
- semantics
876
- }) {
877
- if (explicit !== void 0) return explicit;
878
- if (total === void 0) return void 0;
879
- if (semantics === "exclusive") return total;
880
- const observedParts = parts.filter((part) => part !== void 0 && part > 0);
881
- if (semantics === void 0 && observedParts.length > 0) return void 0;
882
- const exclusive = total - observedParts.reduce((sum, part) => sum + part, 0);
883
- return exclusive >= 0 ? exclusive : void 0;
884
- }
885
- function buildModelUsageAttributes(usage) {
886
- const inputTokens = tokenCount(usage.inputTokens);
887
- const outputTokens = tokenCount(usage.outputTokens);
888
- const explicitNonCachedInputTokens = tokenCount(usage.nonCachedInputTokens);
889
- const explicitNonReasoningOutputTokens = tokenCount(usage.nonReasoningOutputTokens);
890
- const reasoningTokens = tokenCount(usage.reasoningTokens);
891
- const cacheReadInputTokens = tokenCount(usage.cacheReadInputTokens);
892
- const cacheWriteInputTokens = tokenCount(usage.cacheWriteInputTokens);
893
- const nonCachedInputTokens = exclusiveTokens({
894
- explicit: explicitNonCachedInputTokens,
895
- total: inputTokens,
896
- parts: [cacheReadInputTokens, cacheWriteInputTokens],
897
- semantics: usage.inputTokenSemantics
898
- });
899
- const nonReasoningOutputTokens = exclusiveTokens({
900
- explicit: explicitNonReasoningOutputTokens,
901
- total: outputTokens,
902
- parts: [reasoningTokens],
903
- semantics: usage.outputTokenSemantics
904
- });
905
- const exclusivePoolAttributes = nonCachedInputTokens !== void 0 && nonReasoningOutputTokens !== void 0 ? [
906
- // backend consumes this complete raindrop.* set as one atomic billing-pool contract.
907
- attrInt(MODEL_USAGE_ATTRIBUTES.nonCachedInputTokens, nonCachedInputTokens),
908
- attrInt(MODEL_USAGE_ATTRIBUTES.nonReasoningOutputTokens, nonReasoningOutputTokens),
909
- attrInt(MODEL_USAGE_ATTRIBUTES.reasoningOutputTokens, reasoningTokens),
910
- attrInt(MODEL_USAGE_ATTRIBUTES.cacheReadTokens, cacheReadInputTokens),
911
- attrInt(MODEL_USAGE_ATTRIBUTES.cacheWriteTokens, cacheWriteInputTokens)
912
- ] : [];
1179
+ function buildRawModelUsageAttributes(usage) {
1180
+ const providerReportedCost = typeof usage.providerReportedCost === "number" && Number.isFinite(usage.providerReportedCost) && usage.providerReportedCost >= 0 ? usage.providerReportedCost : void 0;
913
1181
  return [
914
- attrInt(MODEL_USAGE_ATTRIBUTES.inputTokens, inputTokens),
915
- attrInt(MODEL_USAGE_ATTRIBUTES.outputTokens, outputTokens),
916
- attrInt(MODEL_USAGE_ATTRIBUTES.reasoningTokens, reasoningTokens),
917
- attrInt(MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens, cacheReadInputTokens),
918
- attrInt(MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens, cacheWriteInputTokens),
919
- ...exclusivePoolAttributes
1182
+ attrInt(MODEL_USAGE_ATTRIBUTES.inputTokens, tokenCount(usage.inputTokens)),
1183
+ attrInt(MODEL_USAGE_ATTRIBUTES.outputTokens, tokenCount(usage.outputTokens)),
1184
+ attrInt(MODEL_USAGE_ATTRIBUTES.reasoningTokens, tokenCount(usage.reasoningTokens)),
1185
+ attrInt(MODEL_USAGE_ATTRIBUTES.cacheReadInputTokens, tokenCount(usage.cacheReadInputTokens)),
1186
+ attrInt(MODEL_USAGE_ATTRIBUTES.cacheWriteInputTokens, tokenCount(usage.cacheWriteInputTokens)),
1187
+ attrDouble(MODEL_USAGE_ATTRIBUTES.providerReportedCost, providerReportedCost)
920
1188
  ].filter((attribute) => attribute !== void 0);
921
1189
  }
922
1190
  var STRING_ALIASES = {
@@ -1580,7 +1848,7 @@ installTracingSuppressionHook();
1580
1848
  // package.json
1581
1849
  var package_default = {
1582
1850
  name: "@raindrop-ai/ai-sdk",
1583
- version: "0.2.1"};
1851
+ version: "0.3.1"};
1584
1852
 
1585
1853
  // src/internal/version.ts
1586
1854
  var libraryName = package_default.name;
@@ -2468,37 +2736,361 @@ function runWithParentToolContext(ctx, fn) {
2468
2736
  return getStorage2().run(ctx, fn);
2469
2737
  }
2470
2738
 
2471
- // src/internal/usage.ts
2472
- function firstTokenCount(...values) {
2473
- for (const value of values) {
2474
- if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) {
2475
- return value;
2739
+ // src/internal/subagents.ts
2740
+ var SUBAGENT_CANCELLED_OUTPUT = "Cancelled before producing a result.";
2741
+ var SUBAGENT_ABORTED_OUTPUT = "Aborted before producing a result.";
2742
+ var SUBAGENT_FAILED_OPERATION_ID = SUBAGENT_ABORT_OPERATION_ID;
2743
+ var MAX_SETTLED_EVENT_IDS = 1024;
2744
+ function isTraceCarrier(value) {
2745
+ const candidate = value;
2746
+ return typeof candidate.traceId === "string" && typeof candidate.spanId === "string" && typeof candidate.eventId === "string";
2747
+ }
2748
+ function attrsFrom(metadata) {
2749
+ return Object.entries(withMetadataPrefix(metadata)).map(([key, value]) => attrString(key, value));
2750
+ }
2751
+ function attrsExact(attributes) {
2752
+ return Object.entries(attributes).map(([key, value]) => attrString(key, value));
2753
+ }
2754
+ function handoffSpanAttrs(link) {
2755
+ if (!link) return [];
2756
+ return attrsFrom(detachedChildMetadata(link));
2757
+ }
2758
+ function subagentNameAttrs(name, link) {
2759
+ if (!name || (link == null ? void 0 : link.name)) return [];
2760
+ return attrsFrom({ [HANDOFF_ATTRIBUTE_SUFFIXES.name]: name });
2761
+ }
2762
+ function cancelledSpanAttrs() {
2763
+ return attrsExact(cancelledTerminalAttributes());
2764
+ }
2765
+ function describeAbortReason(reason) {
2766
+ if (reason instanceof Error) return `Aborted: ${reason.message}`;
2767
+ if (typeof reason === "string" && reason.trim().length > 0) return reason;
2768
+ if (reason === void 0 || reason === null) return SUBAGENT_ABORTED_OUTPUT;
2769
+ const serialized = boundedStringify(reason);
2770
+ return serialized ? `Aborted: ${serialized}` : SUBAGENT_ABORTED_OUTPUT;
2771
+ }
2772
+ function stampOpenSpan(span, metadata) {
2773
+ if (span.endTimeUnixNano) return;
2774
+ span.attributes.push(...attrsFrom(metadata));
2775
+ }
2776
+ function stampOpenSpanExact(span, attributes) {
2777
+ if (span.endTimeUnixNano) return;
2778
+ span.attributes.push(...attrsExact(attributes));
2779
+ }
2780
+ var SubagentApi = class {
2781
+ constructor(opts) {
2782
+ var _a;
2783
+ this.opts = opts;
2784
+ this.settledEventIds = (_a = opts.settledEventIds) != null ? _a : /* @__PURE__ */ new Set();
2785
+ }
2786
+ /** True when this child's outcome has already been reported. */
2787
+ wasSettledExplicitly(eventId) {
2788
+ return this.settledEventIds.has(eventId);
2789
+ }
2790
+ /**
2791
+ * Record an outcome reported somewhere other than `cancel()` / `fail()`, so
2792
+ * first-outcome-wins holds across every path that can state one.
2793
+ *
2794
+ * An aborted generation is such a path: an AbortSignal cancellation IS the
2795
+ * run's outcome, and the `fail(err)` that a catch block around the aborted
2796
+ * call naturally reports would otherwise error the child's spans — which is
2797
+ * the only thing separating `failed` from `cancelled`.
2798
+ */
2799
+ noteSettled(eventId) {
2800
+ this.remember(eventId);
2801
+ }
2802
+ remember(eventId) {
2803
+ if (this.settledEventIds.has(eventId)) return;
2804
+ if (this.settledEventIds.size >= MAX_SETTLED_EVENT_IDS) {
2805
+ const oldest = this.settledEventIds.values().next();
2806
+ if (!oldest.done) this.settledEventIds.delete(oldest.value);
2476
2807
  }
2808
+ this.settledEventIds.add(eventId);
2477
2809
  }
2478
- return void 0;
2479
- }
2480
- function flatUsageSemantics(provider) {
2481
- const normalizedProvider = typeof provider === "string" ? provider.trim().toLowerCase() : void 0;
2482
- if (normalizedProvider === "anthropic" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("anthropic.")) || normalizedProvider === "vertex.anthropic" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("vertex.anthropic."))) {
2483
- return {
2484
- inputTokenSemantics: "exclusive",
2485
- outputTokenSemantics: "total"
2486
- };
2810
+ /**
2811
+ * Record a detached sub-agent on this turn: allocate the child's event id,
2812
+ * stamp the dispatch, and return the headers to send with the job.
2813
+ *
2814
+ * This dispatches nothing — you do, moments later, with the returned headers.
2815
+ * Nothing here waits for the child either, or claims to know how it is doing.
2816
+ * Readers derive that from the child's own event.
2817
+ */
2818
+ subagent(options = {}) {
2819
+ var _a;
2820
+ const childEventId = (_a = options.childEventId) != null ? _a : randomUUID();
2821
+ const name = options.name;
2822
+ try {
2823
+ return this.recordLaunch(childEventId, name, options);
2824
+ } catch (err) {
2825
+ if (this.opts.debug) {
2826
+ console.warn(
2827
+ `[raindrop-ai/ai-sdk] sub-agent dispatch not recorded: ${err instanceof Error ? err.message : err}`
2828
+ );
2829
+ }
2830
+ return { childEventId, name, headers: {}, carrier: null };
2831
+ }
2487
2832
  }
2488
- if (normalizedProvider === "openai" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("openai.")) || normalizedProvider === "azure" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("azure."))) {
2489
- return {
2490
- inputTokenSemantics: "total",
2491
- outputTokenSemantics: "total"
2833
+ recordLaunch(childEventId, name, options) {
2834
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p;
2835
+ const active = (_a = this.opts.spanSource) == null ? void 0 : _a.activeDispatch();
2836
+ const inherited = getContextManager().getParentSpanIds();
2837
+ 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;
2838
+ 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;
2839
+ 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;
2840
+ if (!eventId) {
2841
+ return { childEventId, name, headers: {}, carrier: null };
2842
+ }
2843
+ const dispatch = detachedDispatchMetadata({ childEventId, name });
2844
+ const toolEvents = toolEventsAllowMetadata();
2845
+ for (const span of (_l = active == null ? void 0 : active.turnSpans) != null ? _l : []) {
2846
+ stampOpenSpan(span, toolEvents);
2847
+ }
2848
+ let dispatchIds;
2849
+ if (active == null ? void 0 : active.dispatchSpan) {
2850
+ stampOpenSpan(active.dispatchSpan, dispatch);
2851
+ dispatchIds = active.dispatchSpan.ids;
2852
+ } else if (this.opts.sendTraces) {
2853
+ dispatchIds = this.synthesizeDispatchSpan({
2854
+ childEventId,
2855
+ name,
2856
+ toolName: options.toolName,
2857
+ eventId,
2858
+ userId,
2859
+ convoId,
2860
+ input: options.input,
2861
+ // No active turn means no telemetry setting to honor: `input` is then
2862
+ // recorded on the explicit say-so of whoever passed it.
2863
+ recordInputs: (_m = active == null ? void 0 : active.recordInputs) != null ? _m : true,
2864
+ dispatch,
2865
+ parent: (inherited == null ? void 0 : inherited.eventId) === eventId ? inherited : void 0
2866
+ }).ids;
2867
+ }
2868
+ const traceId = base64ToHex((_o = (_n = dispatchIds == null ? void 0 : dispatchIds.traceIdB64) != null ? _n : inherited == null ? void 0 : inherited.traceIdB64) != null ? _o : "");
2869
+ const spanId = base64ToHex((_p = dispatchIds == null ? void 0 : dispatchIds.spanIdB64) != null ? _p : "");
2870
+ if (!traceId || !spanId) {
2871
+ if (this.opts.debug) {
2872
+ console.warn(
2873
+ "[raindrop-ai/ai-sdk] sub-agent dispatch recorded without a carrier: no dispatch span to reference (traces disabled?)"
2874
+ );
2875
+ }
2876
+ return { childEventId, name, headers: {}, carrier: null };
2877
+ }
2878
+ const carrier = {
2879
+ traceId,
2880
+ spanId,
2881
+ eventId,
2882
+ childEventId,
2883
+ ...name ? { name } : {},
2884
+ ...convoId ? { convoId } : {},
2885
+ ...userId ? { userId } : {}
2492
2886
  };
2887
+ return { childEventId, name, headers: toHeaders(carrier), carrier };
2493
2888
  }
2494
- if (normalizedProvider === "google" || (normalizedProvider == null ? void 0 : normalizedProvider.startsWith("google."))) {
2889
+ /**
2890
+ * Record a dispatch span for a launch with no open tool-call span to decorate:
2891
+ * a launch from outside a tool's `execute`, or from a caller that is not an
2892
+ * LLM turn at all (an HTTP handler that enqueues jobs). Shaped as a tool call
2893
+ * so it reads identically to a model-issued launch.
2894
+ */
2895
+ synthesizeDispatchSpan(args) {
2896
+ var _a;
2897
+ const spanName = (_a = args.toolName) != null ? _a : DEFAULT_DISPATCH_SPAN_NAME;
2898
+ const span = this.opts.traceShipper.startSpan({
2899
+ name: spanName,
2900
+ parent: args.parent,
2901
+ eventId: args.eventId,
2902
+ userId: args.userId,
2903
+ convoId: args.convoId,
2904
+ operationId: "ai.toolCall",
2905
+ attributes: [
2906
+ attrString("operation.name", "ai.toolCall"),
2907
+ attrString("resource.name", spanName),
2908
+ attrString("ai.toolCall.name", spanName),
2909
+ attrString("ai.toolCall.id", `call_${args.childEventId.replace(/-/g, "").slice(0, 12)}`),
2910
+ // Gated like every other input the turn's spans record: a caller that
2911
+ // disabled input capture must not leak the payload through the one
2912
+ // span this API synthesizes on its behalf.
2913
+ ...args.recordInputs ? [attrString("ai.toolCall.args", boundedStringify(args.input))] : [],
2914
+ ...attrsFrom(args.dispatch)
2915
+ ]
2916
+ });
2917
+ this.opts.traceShipper.endSpan(span, {
2918
+ // A dispatch returns a handle, not an answer — the answer is the child's.
2919
+ attributes: [
2920
+ attrString(
2921
+ "ai.toolCall.result",
2922
+ boundedStringify({ jobId: args.childEventId, status: "accepted" })
2923
+ )
2924
+ ]
2925
+ });
2926
+ return span;
2927
+ }
2928
+ /**
2929
+ * Adopt a carrier as the current run's parent reference.
2930
+ *
2931
+ * A missing carrier is a legitimate state — the child was invoked directly
2932
+ * rather than dispatched — so this always returns a usable run and leaves
2933
+ * `parent` null. Call sites stay unconditional.
2934
+ */
2935
+ resume(carrierOrHeaders, options = {}) {
2936
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
2937
+ const carrier = carrierOrHeaders ? isTraceCarrier(carrierOrHeaders) ? carrierOrHeaders : this.readCarrier(carrierOrHeaders) : null;
2938
+ warnUnresolvedCarrier(carrierOrHeaders, carrier);
2939
+ const name = (_a = carrier == null ? void 0 : carrier.name) != null ? _a : options.name;
2940
+ const eventId = (_c = (_b = carrier == null ? void 0 : carrier.childEventId) != null ? _b : options.eventId) != null ? _c : randomUUID();
2941
+ 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;
2942
+ 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;
2943
+ const parent = carrier ? {
2944
+ parentEventId: carrier.eventId,
2945
+ ...carrier.spanId ? { parentSpanId: carrier.spanId } : {},
2946
+ ...name ? { name } : {}
2947
+ } : null;
2495
2948
  return {
2496
- inputTokenSemantics: "total",
2497
- // Google v5 reports candidate output and thoughts separately.
2498
- outputTokenSemantics: "exclusive"
2949
+ eventId,
2950
+ name,
2951
+ userId,
2952
+ convoId,
2953
+ parent,
2954
+ metadata: {
2955
+ eventId,
2956
+ ...userId ? { userId } : {},
2957
+ ...convoId ? { convoId } : {},
2958
+ ...parent ? { subagent: parent } : {}
2959
+ },
2960
+ cancel: (reason) => this.settle(eventId, { userId, convoId, name, cancelled: true, output: reason }),
2961
+ fail: (reason) => this.settle(eventId, {
2962
+ userId,
2963
+ convoId,
2964
+ name,
2965
+ handoff: parent != null ? parent : void 0,
2966
+ cancelled: false,
2967
+ output: describeAbortReason(reason),
2968
+ error: reason
2969
+ })
2499
2970
  };
2500
2971
  }
2501
- return {};
2972
+ /**
2973
+ * A carrier arrives from outside this process, so a hostile or merely broken
2974
+ * header bag must cost the job its link, never its run.
2975
+ */
2976
+ readCarrier(headers) {
2977
+ try {
2978
+ return fromHeaders(headers);
2979
+ } catch (err) {
2980
+ if (this.opts.debug) {
2981
+ console.warn(
2982
+ `[raindrop-ai/ai-sdk] sub-agent carrier ignored: ${err instanceof Error ? err.message : err}`
2983
+ );
2984
+ }
2985
+ return null;
2986
+ }
2987
+ }
2988
+ /**
2989
+ * Mark a failed child's own spans as errored.
2990
+ *
2991
+ * Reporting the reason as output is what gets the child an event at all, but
2992
+ * output alone is not enough: status is derived from span shape, and a child
2993
+ * with final output and no error spans derives `finished`. A failed job
2994
+ * reporting success is worse than one reporting nothing, so the failure has
2995
+ * to land on the telemetry too, not just in the text.
2996
+ *
2997
+ * This is the child describing its own run, not a caller writing a status it
2998
+ * cannot observe — the child's own spans are exactly where the contract puts
2999
+ * failure.
3000
+ */
3001
+ recordFailureOnSpans(eventId, args, reason) {
3002
+ var _a, _b, _c;
3003
+ if (!this.opts.sendTraces) return;
3004
+ const failure = (_a = args.error) != null ? _a : reason;
3005
+ let marked = 0;
3006
+ for (const span2 of (_c = (_b = this.opts.spanSource) == null ? void 0 : _b.openSpansForEvent(eventId)) != null ? _c : []) {
3007
+ if (span2.endTimeUnixNano) continue;
3008
+ this.opts.traceShipper.endSpan(span2, { error: failure });
3009
+ marked++;
3010
+ }
3011
+ if (marked > 0) return;
3012
+ const spanName = SUBAGENT_ABORT_SPAN_NAME;
3013
+ const span = this.opts.traceShipper.startSpan({
3014
+ name: spanName,
3015
+ eventId,
3016
+ userId: args.userId,
3017
+ convoId: args.convoId,
3018
+ // Required, not decorative: ingest drops any span carrying no
3019
+ // `ai.operationId` (or traceloop / `gen_ai.*` key) and still answers 200,
3020
+ // so without this the failure disappears silently. The value is
3021
+ // deliberately none of the generate/stream/tool/embed forms, which is
3022
+ // what classifies the span as INTERNAL rather than mislabelling a failed
3023
+ // job as a model call or a tool call.
3024
+ operationId: SUBAGENT_FAILED_OPERATION_ID,
3025
+ // Carries the reverse reference like every other span the child emits:
3026
+ // this is often the child's ONLY span, and a span read on its own is the
3027
+ // whole reason the reference cannot live on the root alone. The name is
3028
+ // stamped even for an unlinked run, which has no caller to reference —
3029
+ // `span_name` no longer says which sub-agent this was, so the attribute
3030
+ // is the only thing that can.
3031
+ attributes: [
3032
+ attrString("resource.name", spanName),
3033
+ ...handoffSpanAttrs(args.handoff),
3034
+ ...subagentNameAttrs(args.name, args.handoff)
3035
+ ]
3036
+ });
3037
+ this.opts.traceShipper.endSpan(span, { error: failure });
3038
+ }
3039
+ async settle(eventId, args) {
3040
+ var _a, _b;
3041
+ if (this.settledEventIds.has(eventId)) {
3042
+ if (this.opts.debug) {
3043
+ console.warn(
3044
+ `[raindrop-ai/ai-sdk] sub-agent ${eventId} already reported an outcome; ignoring the second one`
3045
+ );
3046
+ }
3047
+ return;
3048
+ }
3049
+ this.remember(eventId);
3050
+ const output = args.output && args.output.trim().length > 0 ? args.output : args.cancelled ? SUBAGENT_CANCELLED_OUTPUT : SUBAGENT_ABORTED_OUTPUT;
3051
+ try {
3052
+ if (args.cancelled) {
3053
+ for (const span of (_b = (_a = this.opts.spanSource) == null ? void 0 : _a.openSpansForEvent(eventId)) != null ? _b : []) {
3054
+ stampOpenSpanExact(span, cancelledTerminalAttributes());
3055
+ }
3056
+ } else {
3057
+ this.recordFailureOnSpans(eventId, args, output);
3058
+ }
3059
+ } catch (err) {
3060
+ if (this.opts.debug) {
3061
+ console.warn(
3062
+ `[raindrop-ai/ai-sdk] sub-agent outcome not recorded on spans: ${err instanceof Error ? err.message : err}`
3063
+ );
3064
+ }
3065
+ }
3066
+ if (!this.opts.sendEvents) return;
3067
+ await this.opts.eventShipper.patch(eventId, {
3068
+ userId: args.userId,
3069
+ convoId: args.convoId,
3070
+ // An event is only created from a run that reported something. A child
3071
+ // that dies silently produces no event at all, which pins the caller on
3072
+ // `queued` forever — indistinguishable from a job that never started.
3073
+ output,
3074
+ ...args.cancelled ? { properties: { [HANDOFF_TERMINAL_PROPERTY_KEY]: HANDOFF_TERMINAL_CANCELLED } } : {},
3075
+ isPending: false
3076
+ }).catch((err) => {
3077
+ if (this.opts.debug) {
3078
+ console.warn(
3079
+ `[raindrop-ai/ai-sdk] sub-agent outcome patch failed: ${err instanceof Error ? err.message : err}`
3080
+ );
3081
+ }
3082
+ });
3083
+ }
3084
+ };
3085
+
3086
+ // src/internal/usage.ts
3087
+ function firstTokenCount(...values) {
3088
+ for (const value of values) {
3089
+ if (typeof value === "number" && Number.isSafeInteger(value) && value >= 0) {
3090
+ return value;
3091
+ }
3092
+ }
3093
+ return void 0;
2502
3094
  }
2503
3095
  var CACHE_WRITE_METADATA_KEYS = [
2504
3096
  ["anthropic", "cacheCreationInputTokens"],
@@ -2516,7 +3108,7 @@ function cacheWriteTokensFromProviderMetadata(providerMetadata) {
2516
3108
  })
2517
3109
  );
2518
3110
  }
2519
- function extractUsageMetricsFromUsage(usage, provider, providerMetadata) {
3111
+ function extractUsageMetricsFromUsage(usage, _provider, providerMetadata) {
2520
3112
  if (!isRecord(usage)) return {};
2521
3113
  const inputTokenValue = usage["inputTokens"];
2522
3114
  const outputTokenValue = usage["outputTokens"];
@@ -2584,7 +3176,7 @@ function extractUsageMetricsFromUsage(usage, provider, providerMetadata) {
2584
3176
  cacheReadInputTokens,
2585
3177
  cachedInputTokens: cacheReadInputTokens,
2586
3178
  cacheWriteInputTokens,
2587
- ...hasStructuredUsage ? {} : flatUsageSemantics(provider)
3179
+ ...hasStructuredUsage ? { usageSource: "ai-sdk-structured" } : {}
2588
3180
  };
2589
3181
  }
2590
3182
 
@@ -2660,6 +3252,7 @@ var RaindropTelemetryIntegration = class {
2660
3252
  eventName: (_f = callMeta.eventName) != null ? _f : (_e = this.defaultContext) == null ? void 0 : _e.eventName
2661
3253
  };
2662
3254
  const inherited = getContextManager().getParentSpanIds();
3255
+ const handoff = readDetachedChildLink(metadata);
2663
3256
  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;
2664
3257
  const explicitEventId = callMeta.eventId && !eventIdGenerated ? callMeta.eventId : void 0;
2665
3258
  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();
@@ -2689,7 +3282,10 @@ var RaindropTelemetryIntegration = class {
2689
3282
  attrString("ai.toolCall.name", subagentName),
2690
3283
  attrString("raindrop.subagent.name", subagentName),
2691
3284
  attrString("raindrop.agent.role", "subagent"),
2692
- ...parentAttrs
3285
+ ...parentAttrs,
3286
+ // Top of this child's tree, so the reverse reference matters as much
3287
+ // here as on the root: these are the spans a reader lands on first.
3288
+ ...handoffSpanAttrs(handoff)
2693
3289
  ]
2694
3290
  });
2695
3291
  const subagentParentRef = this.spanParentRef(subagentToolCallSpan);
@@ -2702,7 +3298,8 @@ var RaindropTelemetryIntegration = class {
2702
3298
  attributes: [
2703
3299
  attrString("operation.name", "agent.subagent"),
2704
3300
  attrString("raindrop.span.kind", "llm_call"),
2705
- attrString("raindrop.subagent.name", subagentName)
3301
+ attrString("raindrop.subagent.name", subagentName),
3302
+ ...handoffSpanAttrs(handoff)
2706
3303
  ]
2707
3304
  });
2708
3305
  this.traceShipper.endSpan(markerSpan);
@@ -2770,7 +3367,9 @@ var RaindropTelemetryIntegration = class {
2770
3367
  inputText: isEmbed ? void 0 : this.extractInputText(event),
2771
3368
  toolCallCount: 0,
2772
3369
  subagentName,
2773
- subagentToolCallSpan
3370
+ subagentToolCallSpan,
3371
+ handoff,
3372
+ nestedInEvent: inheritedParent !== void 0
2774
3373
  });
2775
3374
  };
2776
3375
  // ── onStepStart ─────────────────────────────────────────────────────────
@@ -2815,7 +3414,8 @@ var RaindropTelemetryIntegration = class {
2815
3414
  ...attrsFromModelProvider(event.provider),
2816
3415
  attrString("ai.model.id", event.modelId),
2817
3416
  attrString(MODEL_USAGE_ATTRIBUTES.requestModel, event.modelId),
2818
- ...inputAttrs
3417
+ ...inputAttrs,
3418
+ ...handoffSpanAttrs(state.handoff)
2819
3419
  ]
2820
3420
  });
2821
3421
  state.stepSpan = stepSpan;
@@ -2928,7 +3528,8 @@ var RaindropTelemetryIntegration = class {
2928
3528
  attrInt("ai.usage.totalTokens", usageMetrics.totalTokens),
2929
3529
  attrInt("ai.usage.reasoningTokens", usageMetrics.reasoningTokens),
2930
3530
  attrInt("ai.usage.cachedInputTokens", usageMetrics.cachedInputTokens),
2931
- ...buildModelUsageAttributes(usageMetrics)
3531
+ attrString(MODEL_USAGE_ATTRIBUTES.usageSource, usageMetrics.usageSource),
3532
+ ...buildRawModelUsageAttributes(usageMetrics)
2932
3533
  );
2933
3534
  }
2934
3535
  this.emitProviderExecutedToolSpans(event, state);
@@ -2954,7 +3555,8 @@ var RaindropTelemetryIntegration = class {
2954
3555
  attrString("operation.name", operationName),
2955
3556
  attrString("resource.name", resourceName),
2956
3557
  attrString("ai.telemetry.functionId", state.functionId),
2957
- ...inputAttrs
3558
+ ...inputAttrs,
3559
+ ...handoffSpanAttrs(state.handoff)
2958
3560
  ]
2959
3561
  });
2960
3562
  state.embedSpans.set(event.embedCallId, embedSpan);
@@ -3026,15 +3628,26 @@ var RaindropTelemetryIntegration = class {
3026
3628
  this.traceShipper.endSpan(toolSpan, { error: actualError });
3027
3629
  }
3028
3630
  state.toolSpans.clear();
3631
+ const abortReason = describeAbortReason(actualError);
3029
3632
  if (state.rootSpan) {
3030
- this.traceShipper.endSpan(state.rootSpan, { error: actualError });
3633
+ this.traceShipper.endSpan(state.rootSpan, {
3634
+ error: actualError,
3635
+ attributes: this.abortOutcomeAttrs(state, abortReason, "error")
3636
+ });
3031
3637
  }
3032
3638
  if (state.subagentToolCallSpan) {
3033
3639
  this.traceShipper.endSpan(state.subagentToolCallSpan, { error: actualError });
3034
3640
  }
3035
3641
  const isEmbed = state.operationId === "ai.embed" || state.operationId === "ai.embedMany";
3036
3642
  if (!isEmbed) {
3037
- this.finalizeGenerateEvent(state, state.accumulatedText || void 0, void 0);
3643
+ const errorIsTheRunsOutcome = state.handoff !== void 0 && !state.nestedInEvent;
3644
+ this.finalizeGenerateEvent(
3645
+ state,
3646
+ state.accumulatedText || void 0,
3647
+ void 0,
3648
+ false,
3649
+ errorIsTheRunsOutcome ? { fallbackOutput: abortReason } : void 0
3650
+ );
3038
3651
  }
3039
3652
  this.cleanup(event.callId);
3040
3653
  };
@@ -3071,9 +3684,19 @@ var RaindropTelemetryIntegration = class {
3071
3684
  this.traceShipper.endSpan(toolSpan, { attributes: [abortedAttr] });
3072
3685
  }
3073
3686
  state.toolSpans.clear();
3687
+ const abortIsTheRunsOutcome = state.handoff !== void 0 && !state.nestedInEvent;
3074
3688
  if (state.rootSpan) {
3075
3689
  this.traceShipper.endSpan(state.rootSpan, {
3076
- attributes: [abortedAttr, attrInt("ai.toolCall.count", state.toolCallCount)]
3690
+ attributes: [
3691
+ abortedAttr,
3692
+ attrInt("ai.toolCall.count", state.toolCallCount),
3693
+ // An aborted detached child IS a cancelled sub-agent, and a cancelled
3694
+ // run is span-for-span identical to a finished one — spans close,
3695
+ // nothing errors, there is just no answer. So it is the one outcome
3696
+ // that has to be stated, and the child states it on itself.
3697
+ ...abortIsTheRunsOutcome ? cancelledSpanAttrs() : [],
3698
+ ...abortIsTheRunsOutcome ? this.abortOutcomeAttrs(state, SUBAGENT_CANCELLED_OUTPUT, "stop") : []
3699
+ ]
3077
3700
  });
3078
3701
  }
3079
3702
  if (state.subagentToolCallSpan) {
@@ -3081,7 +3704,17 @@ var RaindropTelemetryIntegration = class {
3081
3704
  attributes: [abortedAttr]
3082
3705
  });
3083
3706
  }
3084
- this.finalizeGenerateEvent(state, state.accumulatedText || void 0, void 0);
3707
+ this.finalizeGenerateEvent(
3708
+ state,
3709
+ state.accumulatedText || void 0,
3710
+ void 0,
3711
+ false,
3712
+ abortIsTheRunsOutcome ? {
3713
+ fallbackOutput: SUBAGENT_CANCELLED_OUTPUT,
3714
+ properties: { [HANDOFF_TERMINAL_PROPERTY_KEY]: HANDOFF_TERMINAL_CANCELLED }
3715
+ } : void 0
3716
+ );
3717
+ if (abortIsTheRunsOutcome) this.subagents.noteSettled(state.eventId);
3085
3718
  this.cleanup(callId);
3086
3719
  };
3087
3720
  // ── executeTool ─────────────────────────────────────────────────────────
@@ -3109,6 +3742,97 @@ var RaindropTelemetryIntegration = class {
3109
3742
  this.subagentWrapping = opts.subagentWrapping !== false;
3110
3743
  this.debug = opts.debug === true;
3111
3744
  this.defaultContext = opts.context;
3745
+ this.subagents = new SubagentApi({
3746
+ traceShipper: this.traceShipper,
3747
+ eventShipper: this.eventShipper,
3748
+ sendTraces: this.sendTraces,
3749
+ sendEvents: this.sendEvents,
3750
+ debug: this.debug,
3751
+ defaultContext: this.defaultContext,
3752
+ settledEventIds: opts.settledEventIds,
3753
+ spanSource: {
3754
+ activeDispatch: () => this.activeDispatch(),
3755
+ openSpansForEvent: (eventId) => this.openSpansForEvent(eventId)
3756
+ }
3757
+ });
3758
+ }
3759
+ /**
3760
+ * Record a detached sub-agent on the turn that is live right now.
3761
+ *
3762
+ * Returns the dispatch — the child's event id and the headers to send with
3763
+ * the job. Dispatching is still yours to do; this only states that you are
3764
+ * about to, so a reader can follow the link before the child exists.
3765
+ */
3766
+ subagent(options = {}) {
3767
+ return this.subagents.subagent(options);
3768
+ }
3769
+ // ── detached sub-agent hand-offs ─────────────────────────────────────────
3770
+ /**
3771
+ * The turn a `subagent()` dispatch is happening inside.
3772
+ *
3773
+ * Resolved from the parent-tool context first, which is the only way to reach
3774
+ * the EXACT span that dispatched: the tool call the model itself issued, still
3775
+ * open while its `execute` runs. Falling back to the event id lets a launch
3776
+ * from elsewhere in the turn (a queue producer called mid-generation) still
3777
+ * find the turn's spans, which is where the tool-events opt-in has to land.
3778
+ */
3779
+ activeDispatch() {
3780
+ var _a;
3781
+ const parentTool = getCurrentParentToolContext();
3782
+ let state = parentTool ? this.getState(parentTool.parentCallId) : void 0;
3783
+ const inheritedEventId = (_a = getContextManager().getParentSpanIds()) == null ? void 0 : _a.eventId;
3784
+ if (!state && inheritedEventId) {
3785
+ for (const candidate of this.callStates.values()) {
3786
+ if (candidate.eventId === inheritedEventId) {
3787
+ state = candidate;
3788
+ break;
3789
+ }
3790
+ }
3791
+ }
3792
+ if (!state) return void 0;
3793
+ return {
3794
+ eventId: state.eventId,
3795
+ userId: state.identity.userId,
3796
+ convoId: state.identity.convoId,
3797
+ dispatchSpan: parentTool ? state.toolSpans.get(parentTool.toolCallId) : void 0,
3798
+ turnSpans: [state.rootSpan, state.stepSpan].filter(
3799
+ (span) => span !== void 0
3800
+ ),
3801
+ recordInputs: state.recordInputs
3802
+ };
3803
+ }
3804
+ /** Spans still open for an event, so a late outcome can still be stated. */
3805
+ openSpansForEvent(eventId) {
3806
+ const spans = [];
3807
+ for (const state of this.callStates.values()) {
3808
+ if (state.eventId !== eventId) continue;
3809
+ if (state.rootSpan) spans.push(state.rootSpan);
3810
+ if (state.stepSpan) spans.push(state.stepSpan);
3811
+ }
3812
+ return spans;
3813
+ }
3814
+ /**
3815
+ * End-attributes that keep a detached child legible when it ends without an
3816
+ * answer — an error, an abort, a cancellation.
3817
+ *
3818
+ * An event is created from an LLM span only when it has a finish reason and
3819
+ * non-empty output, so a child that dies silently produces NO event, and the
3820
+ * caller's hand-off pill stays on `queued` forever — indistinguishable from a
3821
+ * job that never started. Reporting the abort reason as the run's output is
3822
+ * what makes the outcome visible. Only detached children get this: an inline
3823
+ * generation's failure is already legible from its caller's own event.
3824
+ *
3825
+ * And only the run's OUTERMOST generation gets it (see `nestedInEvent`): an
3826
+ * inner sub-call ending badly is not the run ending, and since an event is
3827
+ * created from an LLM span with output, `ai.response.text` here would state
3828
+ * the run's outcome through the span while the turn is still working.
3829
+ */
3830
+ abortOutcomeAttrs(state, reason, finishReason) {
3831
+ if (!state.handoff || state.nestedInEvent) return [];
3832
+ return [
3833
+ attrString("ai.response.text", capText2(state.accumulatedText || reason)),
3834
+ attrString("ai.response.finishReason", finishReason)
3835
+ ];
3112
3836
  }
3113
3837
  // ── helpers ──────────────────────────────────────────────────────────────
3114
3838
  getState(callId) {
@@ -3227,7 +3951,8 @@ var RaindropTelemetryIntegration = class {
3227
3951
  attrString("ai.telemetry.functionId", state.functionId),
3228
3952
  attrString("ai.toolCall.name", toolCall.toolName),
3229
3953
  attrString("ai.toolCall.id", toolCall.toolCallId),
3230
- ...inputAttrs
3954
+ ...inputAttrs,
3955
+ ...handoffSpanAttrs(state.handoff)
3231
3956
  ]
3232
3957
  });
3233
3958
  state.toolSpans.set(toolCall.toolCallId, toolSpan);
@@ -3306,7 +4031,8 @@ var RaindropTelemetryIntegration = class {
3306
4031
  attrString("ai.toolCall.name", call.toolName),
3307
4032
  attrString("ai.toolCall.id", call.toolCallId),
3308
4033
  attrString("ai.toolCall.providerExecuted", "true"),
3309
- ...inputAttrs
4034
+ ...inputAttrs,
4035
+ ...handoffSpanAttrs(state.handoff)
3310
4036
  ]
3311
4037
  });
3312
4038
  state.toolCallCount += 1;
@@ -3387,19 +4113,22 @@ var RaindropTelemetryIntegration = class {
3387
4113
  * is finalized by that resume — otherwise each execution would finalize the
3388
4114
  * same event ID into a separate canonical row.
3389
4115
  */
3390
- finalizeGenerateEvent(state, output, model, keepPending = false) {
4116
+ finalizeGenerateEvent(state, output, model, keepPending = false, detachedOutcome) {
3391
4117
  var _a, _b, _c, _d, _e, _f, _g, _h, _i;
3392
4118
  const suppressSubagentEvent = state.subagentName !== void 0 && state.subagentToolCallSpan !== void 0;
3393
4119
  if (!this.sendEvents || suppressSubagentEvent) return;
4120
+ if (this.subagents.wasSettledExplicitly(state.eventId)) return;
3394
4121
  const callMeta = this.extractRaindropMetadata(state.metadata);
3395
4122
  const userId = (_b = callMeta.userId) != null ? _b : (_a = this.defaultContext) == null ? void 0 : _a.userId;
3396
4123
  if (!userId) return;
3397
4124
  const eventName = (_e = (_d = callMeta.eventName) != null ? _d : (_c = this.defaultContext) == null ? void 0 : _c.eventName) != null ? _e : state.operationId;
3398
4125
  const cappedOutput = capText2(output);
4126
+ const reportedOutput = state.handoff && detachedOutcome && !(cappedOutput == null ? void 0 : cappedOutput.trim()) ? detachedOutcome.fallbackOutput : cappedOutput;
3399
4127
  const input = capText2(state.inputText);
3400
4128
  const properties = {
3401
4129
  ...(_f = this.defaultContext) == null ? void 0 : _f.properties,
3402
- ...callMeta.properties
4130
+ ...callMeta.properties,
4131
+ ...state.handoff ? detachedOutcome == null ? void 0 : detachedOutcome.properties : void 0
3403
4132
  };
3404
4133
  const featureFlags = {
3405
4134
  ...((_g = this.defaultContext) == null ? void 0 : _g.featureFlags) ? normalizeFeatureFlags(this.defaultContext.featureFlags) : {},
@@ -3411,7 +4140,7 @@ var RaindropTelemetryIntegration = class {
3411
4140
  userId,
3412
4141
  convoId,
3413
4142
  input,
3414
- output: cappedOutput,
4143
+ output: reportedOutput,
3415
4144
  model,
3416
4145
  properties: Object.keys(properties).length > 0 ? properties : void 0,
3417
4146
  featureFlags: Object.keys(featureFlags).length > 0 ? featureFlags : void 0,
@@ -3748,9 +4477,7 @@ function extractRaindropMetadata(metadata) {
3748
4477
  } catch (e) {
3749
4478
  }
3750
4479
  } else if (featureFlags && typeof featureFlags === "object") {
3751
- result.featureFlags = normalizeFeatureFlags(
3752
- featureFlags
3753
- );
4480
+ result.featureFlags = normalizeFeatureFlags(featureFlags);
3754
4481
  }
3755
4482
  return result;
3756
4483
  }
@@ -3961,12 +4688,7 @@ function setupOperation(params) {
3961
4688
  ...attrsFromTelemetryMetadata(telemetry == null ? void 0 : telemetry.metadata),
3962
4689
  ...attrsFromHeaders(isRecord(arg) ? arg["headers"] : void 0),
3963
4690
  ...attrsFromSettings(arg),
3964
- ...(telemetry == null ? void 0 : telemetry.recordInputs) === false ? [] : [
3965
- attrString(
3966
- "ai.prompt",
3967
- safeJsonWithUint8(normalizePromptAttr(arg))
3968
- )
3969
- ]
4691
+ ...(telemetry == null ? void 0 : telemetry.recordInputs) === false ? [] : [attrString("ai.prompt", safeJsonWithUint8(normalizePromptAttr(arg)))]
3970
4692
  ]
3971
4693
  }) : void 0;
3972
4694
  const rootParentForChildren = rootSpan ? { traceIdB64: rootSpan.ids.traceIdB64, spanIdB64: rootSpan.ids.spanIdB64 } : inheritedParent;
@@ -4316,13 +5038,17 @@ function wrapAISDK(aiSDK, deps) {
4316
5038
  }
4317
5039
  const useNative = deps.options.nativeTelemetry === true;
4318
5040
  if (useNative) {
4319
- const wrapTimeCtx = resolveContext(deps.options.context, { operation: "wrap", args: void 0 });
5041
+ const wrapTimeCtx = resolveContext(deps.options.context, {
5042
+ operation: "wrap",
5043
+ args: void 0
5044
+ });
4320
5045
  const integration = new RaindropTelemetryIntegration({
4321
5046
  traceShipper: deps.traceShipper,
4322
5047
  eventShipper: deps.eventShipper,
4323
5048
  sendTraces: ((_a = deps.options.send) == null ? void 0 : _a.traces) !== false,
4324
5049
  sendEvents: ((_b = deps.options.send) == null ? void 0 : _b.events) !== false,
4325
5050
  debug,
5051
+ settledEventIds: deps.settledEventIds,
4326
5052
  context: {
4327
5053
  userId: wrapTimeCtx.userId,
4328
5054
  eventId: wrapTimeCtx.eventId,
@@ -4560,7 +5286,13 @@ function wrapAgentGenerate(generate, instance, agentSettings, className, aiSDK,
4560
5286
  ...(telemetry == null ? void 0 : telemetry.recordInputs) === false ? [] : [
4561
5287
  attrString(
4562
5288
  "ai.prompt",
4563
- safeJsonWithUint8(normalizePromptAttr({ system: (_d = mergedArgs["system"]) != null ? _d : mergedArgs["instructions"], prompt: mergedArgs["prompt"], messages: mergedArgs["messages"] }))
5289
+ safeJsonWithUint8(
5290
+ normalizePromptAttr({
5291
+ system: (_d = mergedArgs["system"]) != null ? _d : mergedArgs["instructions"],
5292
+ prompt: mergedArgs["prompt"],
5293
+ messages: mergedArgs["messages"]
5294
+ })
5295
+ )
4564
5296
  )
4565
5297
  ]
4566
5298
  ]
@@ -4774,7 +5506,13 @@ function wrapAgentStream(stream, instance, agentSettings, className, aiSDK, deps
4774
5506
  ...(telemetry == null ? void 0 : telemetry.recordInputs) === false ? [] : [
4775
5507
  attrString(
4776
5508
  "ai.prompt",
4777
- safeJsonWithUint8(normalizePromptAttr({ system: (_d = mergedArgs["system"]) != null ? _d : mergedArgs["instructions"], prompt: mergedArgs["prompt"], messages: mergedArgs["messages"] }))
5509
+ safeJsonWithUint8(
5510
+ normalizePromptAttr({
5511
+ system: (_d = mergedArgs["system"]) != null ? _d : mergedArgs["instructions"],
5512
+ prompt: mergedArgs["prompt"],
5513
+ messages: mergedArgs["messages"]
5514
+ })
5515
+ )
4778
5516
  )
4779
5517
  ]
4780
5518
  ]
@@ -5151,9 +5889,19 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
5151
5889
  for (const part of content) {
5152
5890
  if (isRecord(part)) {
5153
5891
  if ((part["type"] === "reasoning" || part["type"] === "thinking") && typeof ((_a = part["text"]) != null ? _a : part["thinking"]) === "string") {
5154
- sendLocalDebuggerLiveEvent({ traceId, type: "reasoning_delta", content: (_b = part["text"]) != null ? _b : part["thinking"], metadata: liveMeta });
5892
+ sendLocalDebuggerLiveEvent({
5893
+ traceId,
5894
+ type: "reasoning_delta",
5895
+ content: (_b = part["text"]) != null ? _b : part["thinking"],
5896
+ metadata: liveMeta
5897
+ });
5155
5898
  } else if (part["type"] === "text" && typeof part["text"] === "string") {
5156
- sendLocalDebuggerLiveEvent({ traceId, type: "text_delta", content: part["text"], metadata: liveMeta });
5899
+ sendLocalDebuggerLiveEvent({
5900
+ traceId,
5901
+ type: "text_delta",
5902
+ content: part["text"],
5903
+ metadata: liveMeta
5904
+ });
5157
5905
  }
5158
5906
  }
5159
5907
  }
@@ -5234,7 +5982,10 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
5234
5982
  attributes: [
5235
5983
  ...((_a = ctx.telemetry) == null ? void 0 : _a.recordOutputs) === false ? [] : [
5236
5984
  attrString("ai.response.finishReason", finishReason),
5237
- attrString("ai.response.text", activeText.length ? capText2(activeText) : void 0),
5985
+ attrString(
5986
+ "ai.response.text",
5987
+ activeText.length ? capText2(activeText) : void 0
5988
+ ),
5238
5989
  attrString(
5239
5990
  "ai.response.toolCalls",
5240
5991
  safeJsonWithUint8(toolCallsLocal.length ? toolCallsLocal : void 0)
@@ -5252,7 +6003,8 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
5252
6003
  ...finishReason ? [attrStringArray("gen_ai.response.finish_reasons", [finishReason])] : [],
5253
6004
  attrString("gen_ai.response.id", responseId),
5254
6005
  attrString(MODEL_USAGE_ATTRIBUTES.responseModel, finalResponseModelId),
5255
- ...buildModelUsageAttributes(usageMetrics),
6006
+ attrString(MODEL_USAGE_ATTRIBUTES.usageSource, usageMetrics.usageSource),
6007
+ ...buildRawModelUsageAttributes(usageMetrics),
5256
6008
  ...msToFirstChunk !== void 0 ? [attrInt("ai.stream.msToFirstChunk", msToFirstChunk)] : [],
5257
6009
  ...msToFinish !== void 0 ? [attrInt("ai.stream.msToFinish", msToFinish)] : [],
5258
6010
  ...avgOutTokensPerSecond !== void 0 ? [attrDouble("ai.stream.avgOutputTokensPerSecond", avgOutTokensPerSecond)] : [],
@@ -5306,19 +6058,44 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
5306
6058
  if ("providerMetadata" in value) providerMetadata = value["providerMetadata"];
5307
6059
  if (localDebuggerEnabled() && ctx.rootParentForChildren) {
5308
6060
  const traceId = ctx.rootParentForChildren.traceIdB64;
5309
- const liveMeta = getLocalDebuggerMetadata({ ...ctx.context, eventId: ctx.eventId });
6061
+ const liveMeta = getLocalDebuggerMetadata({
6062
+ ...ctx.context,
6063
+ eventId: ctx.eventId
6064
+ });
5310
6065
  if (type === "text-delta") {
5311
6066
  const text = typeof value["delta"] === "string" ? value["delta"] : typeof value["textDelta"] === "string" ? value["textDelta"] : typeof value["text"] === "string" ? value["text"] : void 0;
5312
- if (typeof text === "string" && text) sendLocalDebuggerLiveEvent({ traceId, type: "text_delta", content: text, metadata: liveMeta });
6067
+ if (typeof text === "string" && text)
6068
+ sendLocalDebuggerLiveEvent({
6069
+ traceId,
6070
+ type: "text_delta",
6071
+ content: text,
6072
+ metadata: liveMeta
6073
+ });
5313
6074
  } else if (type === "reasoning" || type === "reasoning-delta") {
5314
6075
  const text = typeof value["delta"] === "string" ? value["delta"] : typeof value["text"] === "string" ? value["text"] : typeof value["thinking"] === "string" ? value["thinking"] : void 0;
5315
- if (typeof text === "string" && text) sendLocalDebuggerLiveEvent({ traceId, type: "reasoning_delta", content: text, metadata: liveMeta });
6076
+ if (typeof text === "string" && text)
6077
+ sendLocalDebuggerLiveEvent({
6078
+ traceId,
6079
+ type: "reasoning_delta",
6080
+ content: text,
6081
+ metadata: liveMeta
6082
+ });
5316
6083
  } else if (type === "tool-call") {
5317
6084
  const toolName = typeof value["toolName"] === "string" ? value["toolName"] : "tool";
5318
- sendLocalDebuggerLiveEvent({ traceId, type: "tool_start", content: toolName, metadata: { ...liveMeta, args: value["args"] } });
6085
+ sendLocalDebuggerLiveEvent({
6086
+ traceId,
6087
+ type: "tool_start",
6088
+ content: toolName,
6089
+ metadata: { ...liveMeta, args: value["args"] }
6090
+ });
5319
6091
  } else if (type === "tool-result") {
5320
6092
  const toolName = typeof value["toolName"] === "string" ? value["toolName"] : "tool";
5321
- sendLocalDebuggerLiveEvent({ traceId, type: "tool_result", content: toolName, metadata: { ...liveMeta, result: value["result"] } });
6093
+ sendLocalDebuggerLiveEvent({
6094
+ traceId,
6095
+ type: "tool_result",
6096
+ content: toolName,
6097
+ metadata: { ...liveMeta, result: value["result"] }
6098
+ });
5322
6099
  }
5323
6100
  }
5324
6101
  }
@@ -5398,11 +6175,7 @@ function endDoGenerateSpan(span, result, modelInfo, ctx) {
5398
6175
  } else {
5399
6176
  responseTimestampIso = (/* @__PURE__ */ new Date()).toISOString();
5400
6177
  }
5401
- const usageMetrics = extractUsageMetricsFromUsage(
5402
- usage,
5403
- modelInfo.provider,
5404
- providerMetadata
5405
- );
6178
+ const usageMetrics = extractUsageMetricsFromUsage(usage, modelInfo.provider, providerMetadata);
5406
6179
  const { inputTokens, outputTokens } = usageMetrics;
5407
6180
  ctx.traceShipper.endSpan(span, {
5408
6181
  attributes: [
@@ -5423,7 +6196,8 @@ function endDoGenerateSpan(span, result, modelInfo, ctx) {
5423
6196
  ...finishReason ? [attrStringArray("gen_ai.response.finish_reasons", [finishReason])] : [],
5424
6197
  attrString("gen_ai.response.id", responseId),
5425
6198
  attrString(MODEL_USAGE_ATTRIBUTES.responseModel, responseModelId),
5426
- ...buildModelUsageAttributes(usageMetrics)
6199
+ attrString(MODEL_USAGE_ATTRIBUTES.usageSource, usageMetrics.usageSource),
6200
+ ...buildRawModelUsageAttributes(usageMetrics)
5427
6201
  ]
5428
6202
  });
5429
6203
  }
@@ -5532,6 +6306,8 @@ function eventMetadata(options) {
5532
6306
  if (options.properties) result["raindrop.properties"] = JSON.stringify(options.properties);
5533
6307
  if (options.featureFlags)
5534
6308
  result["raindrop.featureFlags"] = JSON.stringify(normalizeFeatureFlags(options.featureFlags));
6309
+ if (options.subagent) Object.assign(result, detachedChildMetadata(options.subagent));
6310
+ if (options.toolEvents) result[TOOL_EVENTS_SUFFIX] = options.toolEvents;
5535
6311
  return result;
5536
6312
  }
5537
6313
  function deriveChatTurnMessageId(request) {
@@ -5614,12 +6390,22 @@ function createRaindropAISDK(opts) {
5614
6390
  transformSpan: (_j = opts.traces) == null ? void 0 : _j.transformSpan,
5615
6391
  disableDefaultRedaction: (_k = opts.traces) == null ? void 0 : _k.disableDefaultRedaction
5616
6392
  });
6393
+ const settledEventIds = /* @__PURE__ */ new Set();
6394
+ const subagentApi = new SubagentApi({
6395
+ traceShipper,
6396
+ eventShipper,
6397
+ sendTraces: tracesEnabled,
6398
+ sendEvents: eventsEnabled,
6399
+ debug: envDebug,
6400
+ settledEventIds
6401
+ });
5617
6402
  return {
5618
6403
  wrap(aiSDK, options) {
5619
6404
  return wrapAISDK(aiSDK, {
5620
6405
  options: options != null ? options : {},
5621
6406
  eventShipper,
5622
- traceShipper
6407
+ traceShipper,
6408
+ settledEventIds
5623
6409
  });
5624
6410
  },
5625
6411
  createSelfDiagnosticsTool(options = {}) {
@@ -5656,9 +6442,14 @@ function createRaindropAISDK(opts) {
5656
6442
  sendEvents: eventsEnabled,
5657
6443
  subagentWrapping,
5658
6444
  debug: envDebug,
6445
+ settledEventIds,
5659
6446
  context
5660
6447
  });
5661
6448
  },
6449
+ subagents: subagentApi,
6450
+ subagent(options = {}) {
6451
+ return subagentApi.subagent(options);
6452
+ },
5662
6453
  events: {
5663
6454
  async patch(eventId, patch) {
5664
6455
  await eventShipper.patch(eventId, patch);
@@ -5784,8 +6575,17 @@ globalThis.RAINDROP_ASYNC_LOCAL_STORAGE = async_hooks.AsyncLocalStorage;
5784
6575
  exports.DEFAULT_MAX_TEXT_FIELD_CHARS = DEFAULT_MAX_TEXT_FIELD_CHARS2;
5785
6576
  exports.DEFAULT_REDACT_ATTRIBUTE_KEYS = DEFAULT_REDACT_ATTRIBUTE_KEYS;
5786
6577
  exports.DEFAULT_SECRET_KEY_NAMES = DEFAULT_SECRET_KEY_NAMES;
6578
+ exports.DETACHED_MODE = DETACHED_MODE;
6579
+ exports.HANDOFF_ATTRIBUTE_PREFIXES = HANDOFF_ATTRIBUTE_PREFIXES;
6580
+ exports.HANDOFF_ATTRIBUTE_SUFFIXES = HANDOFF_ATTRIBUTE_SUFFIXES;
6581
+ exports.HANDOFF_TERMINAL_CANCELLED = HANDOFF_TERMINAL_CANCELLED;
6582
+ exports.HANDOFF_TERMINAL_PROPERTY_KEY = HANDOFF_TERMINAL_PROPERTY_KEY;
5787
6583
  exports.REDACTED_PLACEHOLDER = REDACTED_PLACEHOLDER;
5788
6584
  exports.RaindropTelemetryIntegration = RaindropTelemetryIntegration;
6585
+ exports.SUBAGENT_ABORTED_OUTPUT = SUBAGENT_ABORTED_OUTPUT;
6586
+ exports.SUBAGENT_AGENT_ROLE = SUBAGENT_AGENT_ROLE;
6587
+ exports.SUBAGENT_CANCELLED_OUTPUT = SUBAGENT_CANCELLED_OUTPUT;
6588
+ exports.TOOL_EVENTS_ALLOW = TOOL_EVENTS_ALLOW;
5789
6589
  exports.TRUNCATION_MARKER = TRUNCATION_MARKER2;
5790
6590
  exports._resetParentToolContextStorage = _resetParentToolContextStorage;
5791
6591
  exports._resetRaindropCallMetadataStorage = _resetRaindropCallMetadataStorage;
@@ -5799,6 +6599,7 @@ exports.defaultTransformSpan = defaultTransformSpan;
5799
6599
  exports.enterParentToolContext = enterParentToolContext;
5800
6600
  exports.eventMetadata = eventMetadata;
5801
6601
  exports.eventMetadataFromChatRequest = eventMetadataFromChatRequest;
6602
+ exports.fromHeaders = fromHeaders;
5802
6603
  exports.getContextManager = getContextManager;
5803
6604
  exports.getCurrentParentToolContext = getCurrentParentToolContext;
5804
6605
  exports.getCurrentRaindropCallMetadata = getCurrentRaindropCallMetadata;
@@ -5807,6 +6608,9 @@ exports.raindrop = raindrop;
5807
6608
  exports.readRaindropCallMetadataFromArgs = readRaindropCallMetadataFromArgs;
5808
6609
  exports.redactJsonAttributeValue = redactJsonAttributeValue;
5809
6610
  exports.redactSecretsInObject = redactSecretsInObject;
6611
+ exports.resetUnresolvedCarrierWarning = resetUnresolvedCarrierWarning;
5810
6612
  exports.runWithParentToolContext = runWithParentToolContext;
5811
6613
  exports.runWithRaindropCallMetadata = runWithRaindropCallMetadata;
6614
+ exports.toHeaders = toHeaders;
6615
+ exports.toLangSmithHeaders = toLangSmithHeaders;
5812
6616
  exports.withCurrent = withCurrent;