@raindrop-ai/ai-sdk 0.0.16 → 0.0.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -9,7 +9,7 @@ Standalone Vercel AI SDK integration for Raindrop:
9
9
  ## Install
10
10
 
11
11
  ```bash
12
- yarn add @raindrop-ai/ai-sdk
12
+ pnpm add @raindrop-ai/ai-sdk
13
13
  ```
14
14
 
15
15
  ## Usage
@@ -121,15 +121,15 @@ packages/ai-sdk/
121
121
 
122
122
  ```bash
123
123
  # Run all version tests (requires OPENAI_API_KEY and RAINDROP_WRITE_KEY in .env)
124
- yarn test
124
+ pnpm test
125
125
 
126
126
  # Run specific version
127
- yarn test:v4
128
- yarn test:v5
129
- yarn test:v6
127
+ pnpm test:v4
128
+ pnpm test:v5
129
+ pnpm test:v6
130
130
 
131
131
  # Quick smoke test (real LLM calls, single version)
132
- yarn smoke:min
132
+ pnpm smoke:min
133
133
  ```
134
134
 
135
135
  ### Test Coverage
@@ -1,4 +1,4 @@
1
- // ../core/dist/chunk-FTBZHS25.js
1
+ // ../core/dist/chunk-FOHDGBT5.js
2
2
  function getCrypto() {
3
3
  const c = globalThis.crypto;
4
4
  return c;
@@ -269,6 +269,7 @@ var EventShipper = class {
269
269
  console.log(`${this.prefix} queue patch`, {
270
270
  eventId,
271
271
  userId: patch.userId,
272
+ convoId: patch.convoId,
272
273
  eventName: patch.eventName,
273
274
  hasInput: typeof patch.input === "string" && patch.input.length > 0,
274
275
  hasOutput: typeof patch.output === "string" && patch.output.length > 0,
@@ -397,16 +398,18 @@ var EventShipper = class {
397
398
  return;
398
399
  }
399
400
  const { wizardSession, ...restProperties } = (_e = accumulated.properties) != null ? _e : {};
401
+ const convoId = (_f = accumulated.convoId) != null ? _f : sticky.convoId;
402
+ const isPending = (_h = (_g = accumulated.isPending) != null ? _g : sticky.isPending) != null ? _h : true;
400
403
  const payload = {
401
404
  event_id: eventId,
402
405
  user_id: userId,
403
406
  event: eventName,
404
- timestamp: (_f = accumulated.timestamp) != null ? _f : (/* @__PURE__ */ new Date()).toISOString(),
407
+ timestamp: (_i = accumulated.timestamp) != null ? _i : (/* @__PURE__ */ new Date()).toISOString(),
405
408
  ai_data: {
406
409
  input: accumulated.input,
407
410
  output: accumulated.output,
408
411
  model: accumulated.model,
409
- convo_id: (_g = accumulated.convoId) != null ? _g : sticky.convoId
412
+ convo_id: convoId
410
413
  },
411
414
  properties: {
412
415
  ...restProperties,
@@ -414,7 +417,7 @@ var EventShipper = class {
414
417
  $context: this.context
415
418
  },
416
419
  attachments: accumulated.attachments,
417
- is_pending: ((_i = (_h = accumulated.isPending) != null ? _h : sticky.isPending) != null ? _i : true) !== false
420
+ is_pending: isPending
418
421
  };
419
422
  const url = `${this.baseUrl}events/track_partial`;
420
423
  if (this.debug) {
@@ -422,7 +425,8 @@ var EventShipper = class {
422
425
  eventId,
423
426
  eventName,
424
427
  userId,
425
- isPending: payload.is_pending,
428
+ convoId,
429
+ isPending,
426
430
  inputPreview: typeof accumulated.input === "string" ? accumulated.input.slice(0, 120) : void 0,
427
431
  outputPreview: typeof accumulated.output === "string" ? accumulated.output.slice(0, 120) : void 0,
428
432
  attachments: (_k = (_j = accumulated.attachments) == null ? void 0 : _j.length) != null ? _k : 0,
@@ -454,7 +458,6 @@ var EventShipper = class {
454
458
  } finally {
455
459
  this.inFlight.delete(p);
456
460
  }
457
- const isPending = payload.is_pending;
458
461
  if (!isPending) {
459
462
  this.sticky.delete(eventId);
460
463
  }
@@ -782,7 +785,7 @@ async function* asyncGeneratorWithCurrent(span, gen) {
782
785
  // package.json
783
786
  var package_default = {
784
787
  name: "@raindrop-ai/ai-sdk",
785
- version: "0.0.16"};
788
+ version: "0.0.18"};
786
789
 
787
790
  // src/internal/version.ts
788
791
  var libraryName = package_default.name;
@@ -1168,6 +1171,145 @@ function extractResponseMessages(result) {
1168
1171
  }
1169
1172
  return [];
1170
1173
  }
1174
+ function buildToolCallMatchKey(info) {
1175
+ if (typeof info.toolCallId === "string" && info.toolCallId.length > 0) {
1176
+ return `id:${info.toolCallId}`;
1177
+ }
1178
+ if (typeof info.toolName === "string" && info.toolName.length > 0) {
1179
+ const inputJson = safeJsonWithUint8(info.input);
1180
+ return inputJson !== void 0 ? `name:${info.toolName}|input:${inputJson}` : `name:${info.toolName}`;
1181
+ }
1182
+ return void 0;
1183
+ }
1184
+ function isTranscriptToolResultError(part, result) {
1185
+ if (part["isError"] === true || part["type"] === "tool-error") {
1186
+ return true;
1187
+ }
1188
+ if (isRecord(result) && typeof result["type"] === "string") {
1189
+ return result["type"].startsWith("error") || result["type"] === "execution-denied";
1190
+ }
1191
+ return false;
1192
+ }
1193
+ function getTranscriptToolErrorMessage(result) {
1194
+ if (typeof result === "string" && result.length > 0) {
1195
+ return result;
1196
+ }
1197
+ if (isRecord(result)) {
1198
+ if (typeof result["value"] === "string" && result["value"].length > 0) {
1199
+ return result["value"];
1200
+ }
1201
+ if (typeof result["reason"] === "string" && result["reason"].length > 0) {
1202
+ return result["reason"];
1203
+ }
1204
+ if (typeof result["message"] === "string" && result["message"].length > 0) {
1205
+ return result["message"];
1206
+ }
1207
+ }
1208
+ return safeJsonWithUint8(result);
1209
+ }
1210
+ function getTranscriptMessageParts(message) {
1211
+ if (!isRecord(message)) return [];
1212
+ const content = message["content"];
1213
+ if (Array.isArray(content)) {
1214
+ return content.filter(isRecord);
1215
+ }
1216
+ return isRecord(content) ? [content] : [];
1217
+ }
1218
+ function getTranscriptToolCallInput(part) {
1219
+ return "input" in part ? part["input"] : "args" in part ? part["args"] : void 0;
1220
+ }
1221
+ function getTranscriptToolCallId(part) {
1222
+ const toolCallId = part["toolCallId"];
1223
+ return typeof toolCallId === "string" && toolCallId.length > 0 ? toolCallId : void 0;
1224
+ }
1225
+ function getTranscriptToolResultValue(part) {
1226
+ if ("output" in part) return part["output"];
1227
+ if ("result" in part) return part["result"];
1228
+ return part["error"];
1229
+ }
1230
+ function rememberPendingTranscriptToolCallKey(pendingKeysByToolName, toolName, key) {
1231
+ var _a;
1232
+ if (!toolName) return;
1233
+ const pendingKeys = (_a = pendingKeysByToolName.get(toolName)) != null ? _a : [];
1234
+ if (pendingKeys.includes(key)) return;
1235
+ pendingKeys.push(key);
1236
+ pendingKeysByToolName.set(toolName, pendingKeys);
1237
+ }
1238
+ function takePendingTranscriptToolCallKey(pendingKeysByToolName, toolName) {
1239
+ if (!toolName) return void 0;
1240
+ const pendingKeys = pendingKeysByToolName.get(toolName);
1241
+ if (!pendingKeys || pendingKeys.length === 0) return void 0;
1242
+ const key = pendingKeys.shift();
1243
+ if (key === void 0) return void 0;
1244
+ if (pendingKeys.length === 0) {
1245
+ pendingKeysByToolName.delete(toolName);
1246
+ }
1247
+ return key;
1248
+ }
1249
+ function mergeTranscriptToolCallPart(params) {
1250
+ var _a, _b, _c, _d;
1251
+ const { spans, pendingKeysByToolName, part } = params;
1252
+ const toolCallId = getTranscriptToolCallId(part);
1253
+ const toolName = typeof part["toolName"] === "string" ? part["toolName"] : void 0;
1254
+ const input = getTranscriptToolCallInput(part);
1255
+ const key = buildToolCallMatchKey({ toolCallId, toolName, input });
1256
+ if (!key) return;
1257
+ const placeholderKey = toolCallId == null ? buildToolCallMatchKey({ toolCallId: void 0, toolName, input: void 0 }) : void 0;
1258
+ const placeholder = placeholderKey && placeholderKey !== key ? spans.get(placeholderKey) : void 0;
1259
+ const existing = (_a = spans.get(key)) != null ? _a : placeholder;
1260
+ spans.set(key, {
1261
+ key,
1262
+ toolCallId: (_b = existing == null ? void 0 : existing.toolCallId) != null ? _b : toolCallId,
1263
+ toolName: (_c = existing == null ? void 0 : existing.toolName) != null ? _c : toolName,
1264
+ input: (_d = existing == null ? void 0 : existing.input) != null ? _d : input,
1265
+ result: existing == null ? void 0 : existing.result,
1266
+ status: existing == null ? void 0 : existing.status,
1267
+ errorMessage: existing == null ? void 0 : existing.errorMessage
1268
+ });
1269
+ if (placeholderKey && placeholderKey !== key) {
1270
+ spans.delete(placeholderKey);
1271
+ }
1272
+ if (!toolCallId && (existing == null ? void 0 : existing.result) === void 0) {
1273
+ rememberPendingTranscriptToolCallKey(pendingKeysByToolName, toolName, key);
1274
+ }
1275
+ }
1276
+ function mergeTranscriptToolResultPart(params) {
1277
+ var _a, _b, _c;
1278
+ const { spans, pendingKeysByToolName, part } = params;
1279
+ const toolCallId = getTranscriptToolCallId(part);
1280
+ const toolName = typeof part["toolName"] === "string" ? part["toolName"] : void 0;
1281
+ const result = getTranscriptToolResultValue(part);
1282
+ const fallbackKey = buildToolCallMatchKey({ toolCallId, toolName, input: void 0 });
1283
+ const key = toolCallId != null ? fallbackKey : (_a = takePendingTranscriptToolCallKey(pendingKeysByToolName, toolName)) != null ? _a : fallbackKey;
1284
+ if (!key) return;
1285
+ const existing = spans.get(key);
1286
+ const isError = isTranscriptToolResultError(part, result);
1287
+ spans.set(key, {
1288
+ key,
1289
+ toolCallId: (_b = existing == null ? void 0 : existing.toolCallId) != null ? _b : toolCallId,
1290
+ toolName: (_c = existing == null ? void 0 : existing.toolName) != null ? _c : toolName,
1291
+ input: existing == null ? void 0 : existing.input,
1292
+ result,
1293
+ status: isError ? "ERROR" : "OK",
1294
+ errorMessage: isError ? getTranscriptToolErrorMessage(result) : void 0
1295
+ });
1296
+ }
1297
+ function extractToolSpansFromMessages(messages) {
1298
+ const spans = /* @__PURE__ */ new Map();
1299
+ const pendingKeysByToolName = /* @__PURE__ */ new Map();
1300
+ for (const message of messages) {
1301
+ for (const part of getTranscriptMessageParts(message)) {
1302
+ if (part["type"] === "tool-call") {
1303
+ mergeTranscriptToolCallPart({ spans, pendingKeysByToolName, part });
1304
+ continue;
1305
+ }
1306
+ if (part["type"] === "tool-result" || part["type"] === "tool-error") {
1307
+ mergeTranscriptToolResultPart({ spans, pendingKeysByToolName, part });
1308
+ }
1309
+ }
1310
+ }
1311
+ return [...spans.values()];
1312
+ }
1171
1313
  function extractTextFromLmContent(content) {
1172
1314
  if (!Array.isArray(content)) return void 0;
1173
1315
  let result = "";
@@ -1183,7 +1325,7 @@ function extractToolCallsFromLmContent(content) {
1183
1325
  const calls = [];
1184
1326
  for (const part of content) {
1185
1327
  if (!isRecord(part) || part["type"] !== "tool-call") continue;
1186
- const toolCallId = typeof part["toolCallId"] === "string" ? part["toolCallId"] : void 0;
1328
+ const toolCallId = getTranscriptToolCallId(part);
1187
1329
  const toolName = typeof part["toolName"] === "string" ? part["toolName"] : void 0;
1188
1330
  if (toolCallId || toolName) {
1189
1331
  calls.push({ toolCallId, toolName, input: part["input"] });
@@ -1222,7 +1364,7 @@ function toOtlpAttr(key, value) {
1222
1364
  }
1223
1365
  function attrsFromTelemetryMetadata(metadata) {
1224
1366
  if (!metadata) return [];
1225
- return Object.entries(metadata).map(([k, v]) => {
1367
+ return Object.entries(metadata).filter(([k]) => !k.startsWith("raindrop.internal.")).map(([k, v]) => {
1226
1368
  const key = k === "raindrop.userId" ? "raindrop.ai.userId" : k;
1227
1369
  return toOtlpAttr(`ai.telemetry.metadata.${key}`, v);
1228
1370
  });
@@ -1311,6 +1453,50 @@ var AGENT_REPORTING_SIGNALS_DEFAULT = {
1311
1453
  }
1312
1454
  };
1313
1455
  var AGENT_REPORTING_TOOL_PREAMBLE = "You have a diagnostic tool for flagging serious failures for developer review. Only call this when you hit a significant, unrecoverable problem \u2014 not for minor hiccups or routine clarifications. If you can still help the user, do that instead of calling this tool. This tool is invisible to the user \u2014 never mention it or its output.";
1456
+ var pendingStoresByShipper = /* @__PURE__ */ new WeakMap();
1457
+ var PendingToolSpanStore = class _PendingToolSpanStore {
1458
+ constructor() {
1459
+ this.spans = /* @__PURE__ */ new Map();
1460
+ }
1461
+ static for(traceShipper, eventId) {
1462
+ let byEvent = pendingStoresByShipper.get(traceShipper);
1463
+ if (!byEvent) {
1464
+ byEvent = /* @__PURE__ */ new Map();
1465
+ pendingStoresByShipper.set(traceShipper, byEvent);
1466
+ }
1467
+ let store = byEvent.get(eventId);
1468
+ if (!store) {
1469
+ store = new _PendingToolSpanStore();
1470
+ byEvent.set(eventId, store);
1471
+ }
1472
+ return store;
1473
+ }
1474
+ resolve(resolvedToolSpans, ctx) {
1475
+ for (const [key, span] of this.spans) {
1476
+ const toolCall = resolvedToolSpans.get(key);
1477
+ if (!toolCall) continue;
1478
+ finishToolSpan(toolCall, span, ctx, span.startTimeUnixNano);
1479
+ this.spans.delete(key);
1480
+ }
1481
+ }
1482
+ remember(toolCall, rootSpan, ctx, startTimeUnixNano) {
1483
+ if (this.spans.has(toolCall.key)) return;
1484
+ this.spans.set(toolCall.key, startToolSpan(toolCall, rootSpan, ctx, startTimeUnixNano));
1485
+ }
1486
+ closeAll(traceShipper) {
1487
+ for (const [, span] of this.spans) {
1488
+ traceShipper.endSpan(span, { endTimeUnixNano: span.startTimeUnixNano });
1489
+ }
1490
+ this.spans.clear();
1491
+ }
1492
+ cleanup(traceShipper, eventId) {
1493
+ if (this.spans.size > 0) return;
1494
+ const byEvent = pendingStoresByShipper.get(traceShipper);
1495
+ if (!byEvent) return;
1496
+ byEvent.delete(eventId);
1497
+ if (byEvent.size === 0) pendingStoresByShipper.delete(traceShipper);
1498
+ }
1499
+ };
1314
1500
  var warnedMissingUserId = false;
1315
1501
  function warnMissingUserIdOnce() {
1316
1502
  if (warnedMissingUserId) return;
@@ -1337,6 +1523,10 @@ function extractRaindropMetadata(metadata) {
1337
1523
  if (typeof userId === "string" && userId) result.userId = userId;
1338
1524
  const eventId = metadata["raindrop.eventId"];
1339
1525
  if (typeof eventId === "string" && eventId) result.eventId = eventId;
1526
+ const eventIdGenerated = metadata["raindrop.internal.eventIdGenerated"];
1527
+ if (eventIdGenerated === true || eventIdGenerated === "true" || eventIdGenerated === "1") {
1528
+ result.eventIdGenerated = true;
1529
+ }
1340
1530
  const convoId = metadata["raindrop.convoId"];
1341
1531
  if (typeof convoId === "string" && convoId) result.convoId = convoId;
1342
1532
  const eventName = metadata["raindrop.eventName"];
@@ -1619,6 +1809,10 @@ function logFinalizeError(debug, err) {
1619
1809
  );
1620
1810
  }
1621
1811
  }
1812
+ function shouldKeepEventPending(params) {
1813
+ if (params.error != null || !params.canKeepEventPending) return false;
1814
+ return params.finishReason === "tool-calls" || params.finishReason === "tool_calls";
1815
+ }
1622
1816
  async function safeFinalize(finalize, debug, result, error) {
1623
1817
  try {
1624
1818
  await finalize(result, error);
@@ -1672,7 +1866,9 @@ function setupOperation(params) {
1672
1866
  const callTimeCtx = extractRaindropMetadata(telemetry == null ? void 0 : telemetry.metadata);
1673
1867
  const mergedCtx = mergeContexts(wrapTimeCtx, callTimeCtx);
1674
1868
  if (!mergedCtx.userId) warnMissingUserIdOnce();
1675
- const eventId = (_c = (_b = (_a = callTimeCtx.eventId) != null ? _a : mergedCtx.eventId) != null ? _b : inherited == null ? void 0 : inherited.eventId) != null ? _c : randomUUID();
1869
+ const hasCallTimeEventId = callTimeCtx.eventId != null;
1870
+ const hasWrapTimeEventId = wrapTimeCtx.eventId != null;
1871
+ const eventId = (_c = (_b = (_a = callTimeCtx.eventId) != null ? _a : wrapTimeCtx.eventId) != null ? _b : inherited == null ? void 0 : inherited.eventId) != null ? _c : randomUUID();
1676
1872
  const ctx = { ...mergedCtx, eventId };
1677
1873
  const inheritedParent = inherited && inherited.eventId === eventId ? { traceIdB64: inherited.traceIdB64, spanIdB64: inherited.spanIdB64 } : void 0;
1678
1874
  const outerOperationId = `ai.${operation}`;
@@ -1724,6 +1920,7 @@ function setupOperation(params) {
1724
1920
  return {
1725
1921
  eventId,
1726
1922
  ctx,
1923
+ canKeepEventPending: hasCallTimeEventId ? callTimeCtx.eventIdGenerated !== true : hasWrapTimeEventId,
1727
1924
  telemetry,
1728
1925
  rootSpan,
1729
1926
  wrappedArgs,
@@ -1746,6 +1943,12 @@ function createFinalize(params) {
1746
1943
  var _a, _b, _c, _d;
1747
1944
  const usage = extractUsageMetrics(result);
1748
1945
  const model = extractModel(result);
1946
+ const finishReason = extractFinishReason(result);
1947
+ const keepEventPending = shouldKeepEventPending({
1948
+ finishReason,
1949
+ error,
1950
+ canKeepEventPending: setup.canKeepEventPending
1951
+ });
1749
1952
  const inputAttachments = autoAttachmentEnabled ? extractInputAttachmentsFromArgs(arg) : void 0;
1750
1953
  const outputAttachments = autoAttachmentEnabled ? await extractOutputAttachmentsFromResult(result) : void 0;
1751
1954
  const baseMessages = coerceMessagesFromArgs(arg);
@@ -1767,7 +1970,18 @@ function createFinalize(params) {
1767
1970
  const output = patch.output;
1768
1971
  const finalModel = (_c = patch.model) != null ? _c : model;
1769
1972
  if (setup.rootSpan) {
1770
- const finishReason = extractFinishReason(result);
1973
+ const spanEndTimeUnixNano = nowUnixNanoString();
1974
+ const syntheticToolCallCount = emitTranscriptToolCallSpans({
1975
+ baseMessages,
1976
+ responseMessages,
1977
+ rootSpan: setup.rootSpan,
1978
+ eventId: setup.eventId,
1979
+ telemetry: setup.telemetry,
1980
+ toolCalls: setup.toolCalls,
1981
+ traceShipper,
1982
+ endTimeUnixNano: spanEndTimeUnixNano,
1983
+ keepEventPending
1984
+ });
1771
1985
  const providerMetadata = isRecord(result) ? result["providerMetadata"] : void 0;
1772
1986
  const resultToolCalls = isRecord(result) && Array.isArray(result["toolCalls"]) ? safeJsonWithUint8(result["toolCalls"]) : setup.toolCalls.length ? safeJsonWithUint8(setup.toolCalls) : void 0;
1773
1987
  traceShipper.endSpan(setup.rootSpan, {
@@ -1785,10 +1999,11 @@ function createFinalize(params) {
1785
1999
  attrInt("ai.usage.totalTokens", usage == null ? void 0 : usage.totalTokens),
1786
2000
  attrInt("ai.usage.reasoningTokens", usage == null ? void 0 : usage.reasoningTokens),
1787
2001
  attrInt("ai.usage.cachedInputTokens", usage == null ? void 0 : usage.cachedInputTokens),
1788
- attrInt("ai.toolCall.count", setup.toolCalls.length),
2002
+ attrInt("ai.toolCall.count", setup.toolCalls.length + syntheticToolCallCount),
1789
2003
  ...error ? [attrString("error.message", error instanceof Error ? error.message : String(error))] : []
1790
2004
  ],
1791
- error
2005
+ error,
2006
+ endTimeUnixNano: spanEndTimeUnixNano
1792
2007
  });
1793
2008
  }
1794
2009
  if (sendEvents) {
@@ -1801,7 +2016,7 @@ function createFinalize(params) {
1801
2016
  model: finalModel,
1802
2017
  properties: patch.properties,
1803
2018
  attachments: patch.attachments,
1804
- isPending: false
2019
+ isPending: keepEventPending
1805
2020
  }).catch((err) => {
1806
2021
  if (debug) {
1807
2022
  console.warn(
@@ -1812,6 +2027,89 @@ function createFinalize(params) {
1812
2027
  }
1813
2028
  };
1814
2029
  }
2030
+ function hasToolResult(toolCall) {
2031
+ return toolCall.result !== void 0 || toolCall.status === "ERROR";
2032
+ }
2033
+ function getExecutedToolCallKeys(toolCalls) {
2034
+ return new Set(
2035
+ toolCalls.map((tc) => buildToolCallMatchKey({ toolCallId: tc.id, toolName: tc.name, input: tc.args })).filter((key) => typeof key === "string" && key.length > 0)
2036
+ );
2037
+ }
2038
+ function getResolvedToolSpans(messages, executedKeys) {
2039
+ return new Map(
2040
+ extractToolSpansFromMessages(messages).filter((tc) => hasToolResult(tc) && !executedKeys.has(tc.key)).map((tc) => [tc.key, tc])
2041
+ );
2042
+ }
2043
+ function startToolSpan(toolCall, rootSpan, ctx, startTimeUnixNano) {
2044
+ var _a, _b, _c;
2045
+ const { operationName, resourceName } = opName("ai.toolCall", (_a = ctx.telemetry) == null ? void 0 : _a.functionId);
2046
+ return ctx.traceShipper.startSpan({
2047
+ name: "ai.toolCall",
2048
+ parent: { traceIdB64: rootSpan.ids.traceIdB64, spanIdB64: rootSpan.ids.spanIdB64 },
2049
+ eventId: ctx.eventId,
2050
+ operationId: "ai.toolCall",
2051
+ attributes: [
2052
+ attrString("operation.name", operationName),
2053
+ attrString("resource.name", resourceName),
2054
+ attrString("ai.telemetry.functionId", (_b = ctx.telemetry) == null ? void 0 : _b.functionId),
2055
+ attrString("ai.toolCall.name", toolCall.toolName),
2056
+ attrString("ai.toolCall.id", toolCall.toolCallId),
2057
+ ...((_c = ctx.telemetry) == null ? void 0 : _c.recordInputs) === false ? [] : [attrString("ai.toolCall.args", safeJsonWithUint8(toolCall.input))]
2058
+ ],
2059
+ startTimeUnixNano
2060
+ });
2061
+ }
2062
+ function finishToolSpan(toolCall, span, ctx, endTimeUnixNano) {
2063
+ var _a, _b, _c;
2064
+ const endAttributes = toolCall.status === "ERROR" ? [attrString("error.message", (_a = toolCall.errorMessage) != null ? _a : "Tool call failed")] : ((_b = ctx.telemetry) == null ? void 0 : _b.recordOutputs) === false ? [] : [attrString("ai.toolCall.result", safeJsonWithUint8(toolCall.result))];
2065
+ ctx.traceShipper.endSpan(span, {
2066
+ attributes: endAttributes,
2067
+ ...toolCall.status === "ERROR" ? { error: new Error((_c = toolCall.errorMessage) != null ? _c : "Tool call failed") } : {},
2068
+ endTimeUnixNano
2069
+ });
2070
+ }
2071
+ function emitToolSpan(toolCall, rootSpan, ctx, timeUnixNano) {
2072
+ const span = startToolSpan(toolCall, rootSpan, ctx, timeUnixNano);
2073
+ finishToolSpan(toolCall, span, ctx, timeUnixNano);
2074
+ }
2075
+ function emitTranscriptToolCallSpans(params) {
2076
+ const store = PendingToolSpanStore.for(params.traceShipper, params.eventId);
2077
+ const responseToolSpans = extractToolSpansFromMessages(params.responseMessages);
2078
+ if (responseToolSpans.length === 0 && params.baseMessages.length === 0) {
2079
+ if (!params.keepEventPending) {
2080
+ store.closeAll(params.traceShipper);
2081
+ }
2082
+ store.cleanup(params.traceShipper, params.eventId);
2083
+ return 0;
2084
+ }
2085
+ const ctx = {
2086
+ eventId: params.eventId,
2087
+ telemetry: params.telemetry,
2088
+ traceShipper: params.traceShipper
2089
+ };
2090
+ const executedKeys = getExecutedToolCallKeys(params.toolCalls);
2091
+ const resolvedSpans = getResolvedToolSpans(
2092
+ [...params.baseMessages, ...params.responseMessages],
2093
+ executedKeys
2094
+ );
2095
+ store.resolve(resolvedSpans, ctx);
2096
+ let syntheticToolCallCount = 0;
2097
+ for (const toolCall of responseToolSpans) {
2098
+ if (executedKeys.has(toolCall.key)) continue;
2099
+ executedKeys.add(toolCall.key);
2100
+ syntheticToolCallCount += 1;
2101
+ if (hasToolResult(toolCall) || !params.keepEventPending) {
2102
+ emitToolSpan(toolCall, params.rootSpan, ctx, params.endTimeUnixNano);
2103
+ } else {
2104
+ store.remember(toolCall, params.rootSpan, ctx, params.endTimeUnixNano);
2105
+ }
2106
+ }
2107
+ if (!params.keepEventPending) {
2108
+ store.closeAll(params.traceShipper);
2109
+ }
2110
+ store.cleanup(params.traceShipper, params.eventId);
2111
+ return syntheticToolCallCount;
2112
+ }
1815
2113
  function executeStreamingOperation(params) {
1816
2114
  const {
1817
2115
  operation,
@@ -1933,7 +2231,7 @@ function wrapAISDK(aiSDK, deps) {
1933
2231
  "generateObject",
1934
2232
  "streamObject"
1935
2233
  ]);
1936
- const agentClasses = /* @__PURE__ */ new Set(["ToolLoopAgent"]);
2234
+ const agentClasses = /* @__PURE__ */ new Set(["Agent", "Experimental_Agent", "ToolLoopAgent"]);
1937
2235
  const sendEvents = ((_a = deps.options.send) == null ? void 0 : _a.events) !== false;
1938
2236
  const sendTraces = ((_b = deps.options.send) == null ? void 0 : _b.traces) !== false;
1939
2237
  const autoAttachmentEnabled = deps.options.autoAttachment !== false;
@@ -2119,6 +2417,18 @@ function wrapAgentGenerate(generate, instance, agentSettings, className, aiSDK,
2119
2417
  const output = patch.output;
2120
2418
  const finalModel = (_c2 = patch.model) != null ? _c2 : model;
2121
2419
  if (rootSpan) {
2420
+ const spanEndTimeUnixNano = nowUnixNanoString();
2421
+ const syntheticToolCallCount = emitTranscriptToolCallSpans({
2422
+ baseMessages,
2423
+ responseMessages,
2424
+ rootSpan,
2425
+ eventId,
2426
+ telemetry,
2427
+ toolCalls,
2428
+ traceShipper: deps.traceShipper,
2429
+ endTimeUnixNano: spanEndTimeUnixNano,
2430
+ keepEventPending: false
2431
+ });
2122
2432
  const finishReason = extractFinishReason(result);
2123
2433
  const providerMetadata = isRecord(result) ? result["providerMetadata"] : void 0;
2124
2434
  const resultToolCalls = isRecord(result) && Array.isArray(result["toolCalls"]) ? safeJsonWithUint8(result["toolCalls"]) : toolCalls.length ? safeJsonWithUint8(toolCalls) : void 0;
@@ -2137,7 +2447,7 @@ function wrapAgentGenerate(generate, instance, agentSettings, className, aiSDK,
2137
2447
  attrInt("ai.usage.totalTokens", usage == null ? void 0 : usage.totalTokens),
2138
2448
  attrInt("ai.usage.reasoningTokens", usage == null ? void 0 : usage.reasoningTokens),
2139
2449
  attrInt("ai.usage.cachedInputTokens", usage == null ? void 0 : usage.cachedInputTokens),
2140
- attrInt("ai.toolCall.count", toolCalls.length),
2450
+ attrInt("ai.toolCall.count", toolCalls.length + syntheticToolCallCount),
2141
2451
  ...error ? [
2142
2452
  attrString(
2143
2453
  "error.message",
@@ -2145,7 +2455,8 @@ function wrapAgentGenerate(generate, instance, agentSettings, className, aiSDK,
2145
2455
  )
2146
2456
  ] : []
2147
2457
  ],
2148
- error
2458
+ error,
2459
+ endTimeUnixNano: spanEndTimeUnixNano
2149
2460
  });
2150
2461
  }
2151
2462
  if (sendEvents) {
@@ -2313,6 +2624,18 @@ function wrapAgentStream(stream, instance, agentSettings, className, aiSDK, deps
2313
2624
  const output = patch.output;
2314
2625
  const finalModel = (_c2 = patch.model) != null ? _c2 : model;
2315
2626
  if (rootSpan) {
2627
+ const spanEndTimeUnixNano = nowUnixNanoString();
2628
+ const syntheticToolCallCount = emitTranscriptToolCallSpans({
2629
+ baseMessages,
2630
+ responseMessages,
2631
+ rootSpan,
2632
+ eventId,
2633
+ telemetry,
2634
+ toolCalls,
2635
+ traceShipper: deps.traceShipper,
2636
+ endTimeUnixNano: spanEndTimeUnixNano,
2637
+ keepEventPending: false
2638
+ });
2316
2639
  const finishReason = extractFinishReason(result);
2317
2640
  const providerMetadata = isRecord(result) ? result["providerMetadata"] : void 0;
2318
2641
  const resultToolCalls = isRecord(result) && Array.isArray(result["toolCalls"]) ? safeJsonWithUint8(result["toolCalls"]) : toolCalls.length ? safeJsonWithUint8(toolCalls) : void 0;
@@ -2331,7 +2654,7 @@ function wrapAgentStream(stream, instance, agentSettings, className, aiSDK, deps
2331
2654
  attrInt("ai.usage.totalTokens", usage == null ? void 0 : usage.totalTokens),
2332
2655
  attrInt("ai.usage.reasoningTokens", usage == null ? void 0 : usage.reasoningTokens),
2333
2656
  attrInt("ai.usage.cachedInputTokens", usage == null ? void 0 : usage.cachedInputTokens),
2334
- attrInt("ai.toolCall.count", toolCalls.length),
2657
+ attrInt("ai.toolCall.count", toolCalls.length + syntheticToolCallCount),
2335
2658
  ...error ? [
2336
2659
  attrString(
2337
2660
  "error.message",
@@ -2339,7 +2662,8 @@ function wrapAgentStream(stream, instance, agentSettings, className, aiSDK, deps
2339
2662
  )
2340
2663
  ] : []
2341
2664
  ],
2342
- error
2665
+ error,
2666
+ endTimeUnixNano: spanEndTimeUnixNano
2343
2667
  });
2344
2668
  }
2345
2669
  if (sendEvents) {
@@ -2509,10 +2833,10 @@ function wrapToolExecute(name, tool, ctx, toolCalls) {
2509
2833
  lastValue = value;
2510
2834
  yield value;
2511
2835
  }
2512
- toolCalls.push({ name, args: toolArgs, result: lastValue, status: "OK" });
2836
+ toolCalls.push({ id: toolCallId, name, args: toolArgs, result: lastValue, status: "OK" });
2513
2837
  endToolSpan(toolSpan, lastValue);
2514
2838
  } catch (error) {
2515
- toolCalls.push({ name, args: toolArgs, status: "ERROR" });
2839
+ toolCalls.push({ id: toolCallId, name, args: toolArgs, status: "ERROR" });
2516
2840
  endToolSpan(toolSpan, void 0, error);
2517
2841
  throw error;
2518
2842
  }
@@ -2525,11 +2849,17 @@ function wrapToolExecute(name, tool, ctx, toolCalls) {
2525
2849
  const run = async () => {
2526
2850
  try {
2527
2851
  const awaitedResult = await result;
2528
- toolCalls.push({ name, args: toolArgs, result: awaitedResult, status: "OK" });
2852
+ toolCalls.push({
2853
+ id: toolCallId,
2854
+ name,
2855
+ args: toolArgs,
2856
+ result: awaitedResult,
2857
+ status: "OK"
2858
+ });
2529
2859
  endToolSpan(toolSpan, awaitedResult);
2530
2860
  return awaitedResult;
2531
2861
  } catch (error) {
2532
- toolCalls.push({ name, args: toolArgs, status: "ERROR" });
2862
+ toolCalls.push({ id: toolCallId, name, args: toolArgs, status: "ERROR" });
2533
2863
  endToolSpan(toolSpan, void 0, error);
2534
2864
  throw error;
2535
2865
  }
@@ -2693,10 +3023,16 @@ function wrapModel(args, aiSDK, outerOperationId, ctx) {
2693
3023
  if (firstChunkMs === void 0) firstChunkMs = Date.now();
2694
3024
  if (isRecord(value)) {
2695
3025
  const type = value["type"];
2696
- if (type === "text-delta" && typeof value["textDelta"] === "string")
2697
- activeText += value["textDelta"];
2698
- if (type === "finish" && typeof value["finishReason"] === "string")
2699
- finishReason = value["finishReason"];
3026
+ if (type === "text-delta") {
3027
+ let textDelta;
3028
+ if (typeof value["delta"] === "string") {
3029
+ textDelta = value["delta"];
3030
+ } else if (typeof value["textDelta"] === "string") {
3031
+ textDelta = value["textDelta"];
3032
+ }
3033
+ if (typeof textDelta === "string") activeText += textDelta;
3034
+ }
3035
+ if (type === "finish") finishReason = extractFinishReason(value);
2700
3036
  if (type === "tool-call") toolCallsLocal.push(value);
2701
3037
  if ("response" in value && isRecord(value["response"])) {
2702
3038
  const response = value["response"];
@@ -2909,15 +3245,44 @@ function extractNestedTokens(usage, key) {
2909
3245
 
2910
3246
  // src/index.ts
2911
3247
  function eventMetadata(options) {
2912
- var _a;
2913
3248
  const result = {};
2914
- result["raindrop.eventId"] = (_a = options.eventId) != null ? _a : randomUUID();
3249
+ if (options.eventId) {
3250
+ result["raindrop.eventId"] = options.eventId;
3251
+ } else {
3252
+ result["raindrop.eventId"] = randomUUID();
3253
+ result["raindrop.internal.eventIdGenerated"] = "true";
3254
+ }
2915
3255
  if (options.userId) result["raindrop.userId"] = options.userId;
2916
3256
  if (options.convoId) result["raindrop.convoId"] = options.convoId;
2917
3257
  if (options.eventName) result["raindrop.eventName"] = options.eventName;
2918
3258
  if (options.properties) result["raindrop.properties"] = JSON.stringify(options.properties);
2919
3259
  return result;
2920
3260
  }
3261
+ function deriveChatTurnMessageId(request) {
3262
+ const messages = Array.isArray(request.messages) ? request.messages : [];
3263
+ for (let i = messages.length - 1; i >= 0; i--) {
3264
+ const message = messages[i];
3265
+ if ((message == null ? void 0 : message.role) === "user" && typeof message.id === "string" && message.id.length > 0) {
3266
+ return message.id;
3267
+ }
3268
+ }
3269
+ if (typeof request.messageId === "string" && request.messageId.length > 0) {
3270
+ return request.messageId;
3271
+ }
3272
+ return void 0;
3273
+ }
3274
+ function eventMetadataFromChatRequest(options) {
3275
+ var _a, _b;
3276
+ const { request, ...rest } = options;
3277
+ const convoId = (_a = rest.convoId) != null ? _a : typeof request.id === "string" && request.id.length > 0 ? request.id : void 0;
3278
+ const turnMessageId = deriveChatTurnMessageId(request);
3279
+ const eventId = (_b = rest.eventId) != null ? _b : turnMessageId ? convoId ? `chat:${convoId}:${turnMessageId}` : `chat:${turnMessageId}` : void 0;
3280
+ return eventMetadata({
3281
+ ...rest,
3282
+ ...convoId ? { convoId } : {},
3283
+ ...eventId ? { eventId } : {}
3284
+ });
3285
+ }
2921
3286
  function envDebugEnabled() {
2922
3287
  var _a;
2923
3288
  if (typeof process === "undefined") return false;
@@ -2995,4 +3360,4 @@ function createRaindropAISDK(opts) {
2995
3360
  };
2996
3361
  }
2997
3362
 
2998
- export { _resetWarnedMissingUserId, createRaindropAISDK, currentSpan, eventMetadata, getContextManager, withCurrent };
3363
+ export { _resetWarnedMissingUserId, createRaindropAISDK, currentSpan, eventMetadata, eventMetadataFromChatRequest, getContextManager, withCurrent };