@raindrop-ai/ai-sdk 0.0.19 → 0.0.20

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.
@@ -1351,6 +1351,536 @@ function attrsFromGenAiRequest(options) {
1351
1351
  ];
1352
1352
  }
1353
1353
 
1354
+ // src/internal/raindrop-telemetry-integration.ts
1355
+ var RaindropTelemetryIntegration = class {
1356
+ constructor(opts) {
1357
+ this.callStates = /* @__PURE__ */ new Map();
1358
+ // ── onStart ─────────────────────────────────────────────────────────────
1359
+ this.onStart = (event) => {
1360
+ var _a, _b, _c, _d;
1361
+ if (event.isEnabled !== true) return;
1362
+ const isEmbed = event.operationId === "ai.embed" || event.operationId === "ai.embedMany";
1363
+ const recordInputs = event.recordInputs !== false;
1364
+ const recordOutputs = event.recordOutputs !== false;
1365
+ const functionId = event.functionId;
1366
+ const metadata = event.metadata;
1367
+ const callMeta = this.extractRaindropMetadata(metadata);
1368
+ const inherited = getContextManager().getParentSpanIds();
1369
+ const eventIdGenerated = (metadata == null ? void 0 : metadata["raindrop.internal.eventIdGenerated"]) === "true" || (metadata == null ? void 0 : metadata["raindrop.internal.eventIdGenerated"]) === true;
1370
+ const explicitEventId = callMeta.eventId && !eventIdGenerated ? callMeta.eventId : void 0;
1371
+ const eventId = (_d = (_c = (_b = explicitEventId != null ? explicitEventId : (_a = this.defaultContext) == null ? void 0 : _a.eventId) != null ? _b : inherited == null ? void 0 : inherited.eventId) != null ? _c : callMeta.eventId) != null ? _d : randomUUID();
1372
+ const inheritedParent = inherited && inherited.eventId === eventId ? { traceIdB64: inherited.traceIdB64, spanIdB64: inherited.spanIdB64 } : void 0;
1373
+ const { operationName, resourceName } = opName(
1374
+ event.operationId,
1375
+ functionId
1376
+ );
1377
+ let rootSpan;
1378
+ if (this.sendTraces) {
1379
+ const promptAttrs = !isEmbed && recordInputs ? [
1380
+ attrString(
1381
+ "ai.prompt",
1382
+ safeJsonWithUint8({
1383
+ system: event.system,
1384
+ prompt: event.prompt,
1385
+ messages: event.messages
1386
+ })
1387
+ )
1388
+ ] : [];
1389
+ const embedAttrs = isEmbed && recordInputs ? event.operationId === "ai.embedMany" ? [
1390
+ attrString(
1391
+ "ai.values",
1392
+ safeJsonWithUint8(event.value)
1393
+ )
1394
+ ] : [attrString("ai.value", safeJsonWithUint8(event.value))] : [];
1395
+ rootSpan = this.traceShipper.startSpan({
1396
+ name: event.operationId,
1397
+ parent: inheritedParent,
1398
+ eventId,
1399
+ operationId: event.operationId,
1400
+ attributes: [
1401
+ attrString("operation.name", operationName),
1402
+ attrString("resource.name", resourceName),
1403
+ attrString("ai.telemetry.functionId", functionId),
1404
+ attrString("ai.model.provider", event.provider),
1405
+ attrString("ai.model.id", event.modelId),
1406
+ // Filter out raindrop.eventId from metadata attrs since TraceShipper
1407
+ // already sets it via the eventId arg. Without this, eventMetadata()'s
1408
+ // auto-generated ID would duplicate and override the resolved one.
1409
+ ...attrsFromTelemetryMetadata(
1410
+ metadata ? Object.fromEntries(
1411
+ Object.entries(metadata).filter(
1412
+ ([k]) => k !== "raindrop.eventId" && k !== "raindrop.internal.eventIdGenerated"
1413
+ )
1414
+ ) : void 0
1415
+ ),
1416
+ ...promptAttrs,
1417
+ ...embedAttrs
1418
+ ]
1419
+ });
1420
+ }
1421
+ this.callStates.set(event.callId, {
1422
+ operationId: event.operationId,
1423
+ eventId,
1424
+ rootSpan,
1425
+ rootParent: rootSpan ? this.spanParentRef(rootSpan) : inheritedParent,
1426
+ stepSpan: void 0,
1427
+ stepParent: void 0,
1428
+ toolSpans: /* @__PURE__ */ new Map(),
1429
+ embedSpans: /* @__PURE__ */ new Map(),
1430
+ recordInputs,
1431
+ recordOutputs,
1432
+ functionId,
1433
+ metadata,
1434
+ accumulatedText: "",
1435
+ inputText: isEmbed ? void 0 : this.extractInputText(event),
1436
+ toolCallCount: 0
1437
+ });
1438
+ };
1439
+ // ── onStepStart ─────────────────────────────────────────────────────────
1440
+ this.onStepStart = (event) => {
1441
+ const state = this.getState(event.callId);
1442
+ if (!(state == null ? void 0 : state.rootSpan) || !state.rootParent) return;
1443
+ const isStream = state.operationId === "ai.streamText" || state.operationId === "ai.streamObject";
1444
+ const stepOperationId = isStream ? `${state.operationId}.doStream` : `${state.operationId}.doGenerate`;
1445
+ const { operationName, resourceName } = opName(
1446
+ stepOperationId,
1447
+ state.functionId
1448
+ );
1449
+ const inputAttrs = [];
1450
+ if (state.recordInputs) {
1451
+ if (event.promptMessages) {
1452
+ inputAttrs.push(
1453
+ attrString(
1454
+ "ai.prompt.messages",
1455
+ safeJsonWithUint8(event.promptMessages)
1456
+ )
1457
+ );
1458
+ }
1459
+ if (event.stepTools) {
1460
+ inputAttrs.push(
1461
+ attrStringArray(
1462
+ "ai.prompt.tools",
1463
+ event.stepTools.map((t) => JSON.stringify(t))
1464
+ )
1465
+ );
1466
+ }
1467
+ if (event.stepToolChoice != null) {
1468
+ inputAttrs.push(
1469
+ attrString(
1470
+ "ai.prompt.toolChoice",
1471
+ JSON.stringify(event.stepToolChoice)
1472
+ )
1473
+ );
1474
+ }
1475
+ }
1476
+ const stepSpan = this.traceShipper.startSpan({
1477
+ name: stepOperationId,
1478
+ parent: state.rootParent,
1479
+ eventId: state.eventId,
1480
+ operationId: stepOperationId,
1481
+ attributes: [
1482
+ attrString("operation.name", operationName),
1483
+ attrString("resource.name", resourceName),
1484
+ attrString("ai.telemetry.functionId", state.functionId),
1485
+ attrString("ai.model.provider", event.provider),
1486
+ attrString("ai.model.id", event.modelId),
1487
+ attrString("gen_ai.system", event.provider),
1488
+ attrString("gen_ai.request.model", event.modelId),
1489
+ ...inputAttrs
1490
+ ]
1491
+ });
1492
+ state.stepSpan = stepSpan;
1493
+ state.stepParent = this.spanParentRef(stepSpan);
1494
+ };
1495
+ // ── onToolCallStart ─────────────────────────────────────────────────────
1496
+ this.onToolCallStart = (event) => {
1497
+ const state = this.getState(event.callId);
1498
+ if (!(state == null ? void 0 : state.stepParent)) return;
1499
+ const { toolCall } = event;
1500
+ const { operationName, resourceName } = opName(
1501
+ "ai.toolCall",
1502
+ state.functionId
1503
+ );
1504
+ const inputAttrs = state.recordInputs ? [attrString("ai.toolCall.args", safeJsonWithUint8(toolCall.input))] : [];
1505
+ const toolSpan = this.traceShipper.startSpan({
1506
+ name: "ai.toolCall",
1507
+ parent: state.stepParent,
1508
+ eventId: state.eventId,
1509
+ operationId: "ai.toolCall",
1510
+ attributes: [
1511
+ attrString("operation.name", operationName),
1512
+ attrString("resource.name", resourceName),
1513
+ attrString("ai.telemetry.functionId", state.functionId),
1514
+ attrString("ai.toolCall.name", toolCall.toolName),
1515
+ attrString("ai.toolCall.id", toolCall.toolCallId),
1516
+ ...inputAttrs
1517
+ ]
1518
+ });
1519
+ state.toolSpans.set(toolCall.toolCallId, toolSpan);
1520
+ };
1521
+ // ── onToolCallFinish ────────────────────────────────────────────────────
1522
+ this.onToolCallFinish = (event) => {
1523
+ const state = this.getState(event.callId);
1524
+ if (!state) return;
1525
+ const toolSpan = state.toolSpans.get(event.toolCall.toolCallId);
1526
+ if (!toolSpan) return;
1527
+ state.toolCallCount += 1;
1528
+ if (event.success) {
1529
+ const outputAttrs = state.recordOutputs ? [attrString("ai.toolCall.result", safeJsonWithUint8(event.output))] : [];
1530
+ this.traceShipper.endSpan(toolSpan, { attributes: outputAttrs });
1531
+ } else {
1532
+ this.traceShipper.endSpan(toolSpan, { error: event.error });
1533
+ }
1534
+ state.toolSpans.delete(event.toolCall.toolCallId);
1535
+ };
1536
+ // ── onChunk (streaming) ─────────────────────────────────────────────────
1537
+ this.onChunk = (event) => {
1538
+ var _a, _b, _c;
1539
+ const callId = (_b = event.callId) != null ? _b : (_a = event.chunk) == null ? void 0 : _a.callId;
1540
+ if (!callId) return;
1541
+ const state = this.getState(callId);
1542
+ if (!state) return;
1543
+ const chunk = event.chunk;
1544
+ if (!chunk || typeof chunk !== "object") return;
1545
+ if (chunk.type === "text-delta") {
1546
+ const delta = (_c = chunk.textDelta) != null ? _c : chunk.delta;
1547
+ if (typeof delta === "string") {
1548
+ state.accumulatedText += delta;
1549
+ }
1550
+ }
1551
+ };
1552
+ // ── onStepFinish ────────────────────────────────────────────────────────
1553
+ this.onStepFinish = (event) => {
1554
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1555
+ const state = this.getState(event.callId);
1556
+ if (!(state == null ? void 0 : state.stepSpan)) return;
1557
+ const outputAttrs = [];
1558
+ if (state.recordOutputs) {
1559
+ outputAttrs.push(
1560
+ attrString("ai.response.finishReason", event.finishReason),
1561
+ attrString("ai.response.text", (_a = event.text) != null ? _a : void 0),
1562
+ attrString("ai.response.id", (_b = event.response) == null ? void 0 : _b.id),
1563
+ attrString("ai.response.model", (_c = event.response) == null ? void 0 : _c.modelId),
1564
+ attrString(
1565
+ "ai.response.timestamp",
1566
+ ((_d = event.response) == null ? void 0 : _d.timestamp) instanceof Date ? event.response.timestamp.toISOString() : (_e = event.response) == null ? void 0 : _e.timestamp
1567
+ ),
1568
+ attrString(
1569
+ "ai.response.providerMetadata",
1570
+ event.providerMetadata ? safeJsonWithUint8(event.providerMetadata) : void 0
1571
+ )
1572
+ );
1573
+ if (((_f = event.toolCalls) == null ? void 0 : _f.length) > 0) {
1574
+ outputAttrs.push(
1575
+ attrString(
1576
+ "ai.response.toolCalls",
1577
+ JSON.stringify(
1578
+ event.toolCalls.map((tc) => ({
1579
+ toolCallId: tc.toolCallId,
1580
+ toolName: tc.toolName,
1581
+ input: tc.input
1582
+ }))
1583
+ )
1584
+ )
1585
+ );
1586
+ }
1587
+ if (((_g = event.reasoning) == null ? void 0 : _g.length) > 0) {
1588
+ const reasoningText = event.reasoning.filter((part) => "text" in part).map((part) => part.text).join("\n");
1589
+ if (reasoningText) {
1590
+ outputAttrs.push(attrString("ai.response.reasoning", reasoningText));
1591
+ }
1592
+ }
1593
+ }
1594
+ outputAttrs.push(
1595
+ attrStringArray("gen_ai.response.finish_reasons", [event.finishReason]),
1596
+ attrString("gen_ai.response.id", (_h = event.response) == null ? void 0 : _h.id),
1597
+ attrString("gen_ai.response.model", (_i = event.response) == null ? void 0 : _i.modelId)
1598
+ );
1599
+ const usage = event.usage;
1600
+ if (usage) {
1601
+ outputAttrs.push(
1602
+ attrInt("ai.usage.inputTokens", usage.inputTokens),
1603
+ attrInt("ai.usage.outputTokens", usage.outputTokens),
1604
+ attrInt("ai.usage.totalTokens", usage.totalTokens),
1605
+ attrInt("ai.usage.reasoningTokens", usage.reasoningTokens),
1606
+ attrInt("ai.usage.cachedInputTokens", usage.cachedInputTokens),
1607
+ attrInt("gen_ai.usage.input_tokens", usage.inputTokens),
1608
+ attrInt("gen_ai.usage.output_tokens", usage.outputTokens)
1609
+ );
1610
+ }
1611
+ this.traceShipper.endSpan(state.stepSpan, { attributes: outputAttrs });
1612
+ state.stepSpan = void 0;
1613
+ state.stepParent = void 0;
1614
+ };
1615
+ // ── onEmbedStart ────────────────────────────────────────────────────────
1616
+ this.onEmbedStart = (event) => {
1617
+ const state = this.getState(event.callId);
1618
+ if (!(state == null ? void 0 : state.rootSpan) || !state.rootParent) return;
1619
+ const { operationName, resourceName } = opName(
1620
+ event.operationId,
1621
+ state.functionId
1622
+ );
1623
+ const inputAttrs = state.recordInputs ? [
1624
+ attrString(
1625
+ "ai.values",
1626
+ safeJsonWithUint8(event.values)
1627
+ )
1628
+ ] : [];
1629
+ const embedSpan = this.traceShipper.startSpan({
1630
+ name: event.operationId,
1631
+ parent: state.rootParent,
1632
+ eventId: state.eventId,
1633
+ operationId: event.operationId,
1634
+ attributes: [
1635
+ attrString("operation.name", operationName),
1636
+ attrString("resource.name", resourceName),
1637
+ attrString("ai.telemetry.functionId", state.functionId),
1638
+ ...inputAttrs
1639
+ ]
1640
+ });
1641
+ state.embedSpans.set(event.embedCallId, embedSpan);
1642
+ };
1643
+ // ── onEmbedFinish ───────────────────────────────────────────────────────
1644
+ this.onEmbedFinish = (event) => {
1645
+ var _a;
1646
+ const state = this.getState(event.callId);
1647
+ if (!state) return;
1648
+ const embedSpan = state.embedSpans.get(event.embedCallId);
1649
+ if (!embedSpan) return;
1650
+ const outputAttrs = [];
1651
+ if (state.recordOutputs) {
1652
+ outputAttrs.push(
1653
+ attrString(
1654
+ "ai.embeddings",
1655
+ safeJsonWithUint8(event.embeddings)
1656
+ )
1657
+ );
1658
+ }
1659
+ if (((_a = event.usage) == null ? void 0 : _a.tokens) != null) {
1660
+ outputAttrs.push(attrInt("ai.usage.tokens", event.usage.tokens));
1661
+ }
1662
+ this.traceShipper.endSpan(embedSpan, { attributes: outputAttrs });
1663
+ state.embedSpans.delete(event.embedCallId);
1664
+ };
1665
+ // ── onFinish ────────────────────────────────────────────────────────────
1666
+ this.onFinish = (event) => {
1667
+ const state = this.getState(event.callId);
1668
+ if (!state) return;
1669
+ const isEmbed = state.operationId === "ai.embed" || state.operationId === "ai.embedMany";
1670
+ if (isEmbed) {
1671
+ this.finishEmbed(event, state);
1672
+ } else {
1673
+ this.finishGenerate(event, state);
1674
+ }
1675
+ this.cleanup(event.callId);
1676
+ };
1677
+ // ── onError ─────────────────────────────────────────────────────────────
1678
+ this.onError = (error) => {
1679
+ var _a;
1680
+ const event = error;
1681
+ if (!(event == null ? void 0 : event.callId)) return;
1682
+ const state = this.getState(event.callId);
1683
+ if (!state) return;
1684
+ const actualError = (_a = event.error) != null ? _a : error;
1685
+ if (state.stepSpan) {
1686
+ this.traceShipper.endSpan(state.stepSpan, { error: actualError });
1687
+ }
1688
+ for (const embedSpan of state.embedSpans.values()) {
1689
+ this.traceShipper.endSpan(embedSpan, { error: actualError });
1690
+ }
1691
+ state.embedSpans.clear();
1692
+ for (const toolSpan of state.toolSpans.values()) {
1693
+ this.traceShipper.endSpan(toolSpan, { error: actualError });
1694
+ }
1695
+ state.toolSpans.clear();
1696
+ if (state.rootSpan) {
1697
+ this.traceShipper.endSpan(state.rootSpan, { error: actualError });
1698
+ }
1699
+ this.cleanup(event.callId);
1700
+ };
1701
+ // ── executeTool ─────────────────────────────────────────────────────────
1702
+ this.executeTool = async ({
1703
+ callId,
1704
+ toolCallId,
1705
+ execute
1706
+ }) => {
1707
+ const state = this.getState(callId);
1708
+ const toolSpan = state == null ? void 0 : state.toolSpans.get(toolCallId);
1709
+ if (!toolSpan) return execute();
1710
+ return runWithParentSpanContext(
1711
+ {
1712
+ traceIdB64: toolSpan.ids.traceIdB64,
1713
+ spanIdB64: toolSpan.ids.spanIdB64,
1714
+ eventId: state.eventId
1715
+ },
1716
+ () => execute()
1717
+ );
1718
+ };
1719
+ this.traceShipper = opts.traceShipper;
1720
+ this.eventShipper = opts.eventShipper;
1721
+ this.sendTraces = opts.sendTraces !== false;
1722
+ this.sendEvents = opts.sendEvents !== false;
1723
+ this.debug = opts.debug === true;
1724
+ this.defaultContext = opts.context;
1725
+ }
1726
+ // ── helpers ──────────────────────────────────────────────────────────────
1727
+ getState(callId) {
1728
+ return this.callStates.get(callId);
1729
+ }
1730
+ cleanup(callId) {
1731
+ this.callStates.delete(callId);
1732
+ }
1733
+ spanParentRef(span) {
1734
+ return { traceIdB64: span.ids.traceIdB64, spanIdB64: span.ids.spanIdB64 };
1735
+ }
1736
+ extractRaindropMetadata(metadata) {
1737
+ if (!metadata) return {};
1738
+ const result = {};
1739
+ const userId = metadata["raindrop.userId"];
1740
+ if (typeof userId === "string" && userId) result.userId = userId;
1741
+ const eventId = metadata["raindrop.eventId"];
1742
+ if (typeof eventId === "string" && eventId) result.eventId = eventId;
1743
+ const convoId = metadata["raindrop.convoId"];
1744
+ if (typeof convoId === "string" && convoId) result.convoId = convoId;
1745
+ const eventName = metadata["raindrop.eventName"];
1746
+ if (typeof eventName === "string" && eventName) result.eventName = eventName;
1747
+ const properties = metadata["raindrop.properties"];
1748
+ if (typeof properties === "string") {
1749
+ try {
1750
+ result.properties = JSON.parse(properties);
1751
+ } catch (e) {
1752
+ }
1753
+ } else if (properties && typeof properties === "object") {
1754
+ result.properties = properties;
1755
+ }
1756
+ return result;
1757
+ }
1758
+ /**
1759
+ * Extract the user-facing input text from an onStart event.
1760
+ * Mirrors the logic in the v4-v6 Proxy path (lastUserMessageTextFromArgs / extractInputFromArgs).
1761
+ */
1762
+ extractInputText(event) {
1763
+ if (typeof event.prompt === "string") return event.prompt;
1764
+ if (Array.isArray(event.messages)) {
1765
+ for (let i = event.messages.length - 1; i >= 0; i--) {
1766
+ const msg = event.messages[i];
1767
+ if ((msg == null ? void 0 : msg.role) === "user") {
1768
+ if (typeof msg.content === "string") return msg.content;
1769
+ if (Array.isArray(msg.content)) {
1770
+ const textPart = msg.content.find(
1771
+ (p) => (p == null ? void 0 : p.type) === "text" && typeof p.text === "string"
1772
+ );
1773
+ if (textPart) return textPart.text;
1774
+ }
1775
+ }
1776
+ }
1777
+ }
1778
+ return void 0;
1779
+ }
1780
+ finishGenerate(event, state) {
1781
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n;
1782
+ if (state.rootSpan) {
1783
+ const outputAttrs = [];
1784
+ if (state.recordOutputs) {
1785
+ outputAttrs.push(
1786
+ attrString("ai.response.finishReason", event.finishReason),
1787
+ attrString("ai.response.text", (_a = event.text) != null ? _a : void 0),
1788
+ attrString(
1789
+ "ai.response.providerMetadata",
1790
+ event.providerMetadata ? safeJsonWithUint8(event.providerMetadata) : void 0
1791
+ )
1792
+ );
1793
+ if (((_b = event.toolCalls) == null ? void 0 : _b.length) > 0) {
1794
+ outputAttrs.push(
1795
+ attrString(
1796
+ "ai.response.toolCalls",
1797
+ JSON.stringify(
1798
+ event.toolCalls.map((tc) => ({
1799
+ toolCallId: tc.toolCallId,
1800
+ toolName: tc.toolName,
1801
+ input: tc.input
1802
+ }))
1803
+ )
1804
+ )
1805
+ );
1806
+ }
1807
+ if (((_c = event.reasoning) == null ? void 0 : _c.length) > 0) {
1808
+ const reasoningText = event.reasoning.filter((part) => "text" in part).map((part) => part.text).join("\n");
1809
+ if (reasoningText) {
1810
+ outputAttrs.push(attrString("ai.response.reasoning", reasoningText));
1811
+ }
1812
+ }
1813
+ }
1814
+ const usage = (_d = event.totalUsage) != null ? _d : event.usage;
1815
+ if (usage) {
1816
+ outputAttrs.push(
1817
+ attrInt("ai.usage.inputTokens", usage.inputTokens),
1818
+ attrInt("ai.usage.outputTokens", usage.outputTokens),
1819
+ attrInt("ai.usage.totalTokens", usage.totalTokens),
1820
+ attrInt("ai.usage.reasoningTokens", usage.reasoningTokens),
1821
+ attrInt("ai.usage.cachedInputTokens", usage.cachedInputTokens)
1822
+ );
1823
+ }
1824
+ outputAttrs.push(
1825
+ attrInt("ai.toolCall.count", state.toolCallCount)
1826
+ );
1827
+ this.traceShipper.endSpan(state.rootSpan, { attributes: outputAttrs });
1828
+ }
1829
+ if (this.sendEvents) {
1830
+ const callMeta = this.extractRaindropMetadata(state.metadata);
1831
+ const userId = (_f = callMeta.userId) != null ? _f : (_e = this.defaultContext) == null ? void 0 : _e.userId;
1832
+ if (userId) {
1833
+ const eventName = (_i = (_h = callMeta.eventName) != null ? _h : (_g = this.defaultContext) == null ? void 0 : _g.eventName) != null ? _i : state.operationId;
1834
+ const output = (_j = event.text) != null ? _j : state.accumulatedText || void 0;
1835
+ const input = state.inputText;
1836
+ const model = (_k = event.response) == null ? void 0 : _k.modelId;
1837
+ const properties = {
1838
+ ...(_l = this.defaultContext) == null ? void 0 : _l.properties,
1839
+ ...callMeta.properties
1840
+ };
1841
+ const convoId = (_n = callMeta.convoId) != null ? _n : (_m = this.defaultContext) == null ? void 0 : _m.convoId;
1842
+ void this.eventShipper.patch(state.eventId, {
1843
+ eventName,
1844
+ userId,
1845
+ convoId,
1846
+ input,
1847
+ output,
1848
+ model,
1849
+ properties: Object.keys(properties).length > 0 ? properties : void 0,
1850
+ isPending: false
1851
+ }).catch((err) => {
1852
+ if (this.debug) {
1853
+ console.warn(
1854
+ `[raindrop-ai/ai-sdk] event patch failed: ${err instanceof Error ? err.message : err}`
1855
+ );
1856
+ }
1857
+ });
1858
+ }
1859
+ }
1860
+ }
1861
+ finishEmbed(event, state) {
1862
+ var _a;
1863
+ if (!state.rootSpan) return;
1864
+ const outputAttrs = [];
1865
+ const isMany = state.operationId === "ai.embedMany";
1866
+ if (state.recordOutputs) {
1867
+ if (isMany) {
1868
+ outputAttrs.push(
1869
+ attrString("ai.embeddings", safeJsonWithUint8(event.embedding))
1870
+ );
1871
+ } else {
1872
+ outputAttrs.push(
1873
+ attrString("ai.embedding", safeJsonWithUint8(event.embedding))
1874
+ );
1875
+ }
1876
+ }
1877
+ if (((_a = event.usage) == null ? void 0 : _a.tokens) != null) {
1878
+ outputAttrs.push(attrInt("ai.usage.tokens", event.usage.tokens));
1879
+ }
1880
+ this.traceShipper.endSpan(state.rootSpan, { attributes: outputAttrs });
1881
+ }
1882
+ };
1883
+
1354
1884
  // src/internal/wrap/wrapAISDK.ts
1355
1885
  var AGENT_REPORTING_TOOL_NAME_DEFAULT = "__raindrop_report";
1356
1886
  var AGENT_REPORTING_SIGNALS_DEFAULT = {
@@ -1560,6 +2090,9 @@ function detectAISDKVersion(aiSDK) {
1560
2090
  if (isFunction(aiSDK["tool"])) return "5";
1561
2091
  return "4";
1562
2092
  }
2093
+ function hasStructuredTelemetryEvents(aiSDK) {
2094
+ return isRecord(aiSDK) && isFunction(aiSDK["registerTelemetryIntegration"]) && isFunction(aiSDK["experimental_streamModelCall"]);
2095
+ }
1563
2096
  function asVercelSchema(jsonSchemaObj) {
1564
2097
  const validatorSymbol = /* @__PURE__ */ Symbol.for("vercel.ai.validator");
1565
2098
  const schemaSymbol = /* @__PURE__ */ Symbol.for("vercel.ai.schema");
@@ -2142,8 +2675,99 @@ async function executeNonStreamingOperation(params) {
2142
2675
  }
2143
2676
  }
2144
2677
  function wrapAISDK(aiSDK, deps) {
2145
- var _a, _b;
2678
+ var _a, _b, _c, _d;
2146
2679
  const debug = deps.eventShipper.isDebugEnabled() || deps.traceShipper.isDebugEnabled();
2680
+ if (deps.options.nativeTelemetry === true) {
2681
+ if (!hasStructuredTelemetryEvents(aiSDK)) {
2682
+ throw new Error(
2683
+ "[raindrop-ai/ai-sdk] nativeTelemetry requires AI SDK v7+. The AI SDK module passed to wrap() does not support structured telemetry events. Remove nativeTelemetry or upgrade to AI SDK v7."
2684
+ );
2685
+ }
2686
+ }
2687
+ const useNative = deps.options.nativeTelemetry === true;
2688
+ if (useNative) {
2689
+ const wrapTimeCtx = resolveContext(deps.options.context, { operation: "wrap", args: void 0 });
2690
+ const integration = new RaindropTelemetryIntegration({
2691
+ traceShipper: deps.traceShipper,
2692
+ eventShipper: deps.eventShipper,
2693
+ sendTraces: ((_a = deps.options.send) == null ? void 0 : _a.traces) !== false,
2694
+ sendEvents: ((_b = deps.options.send) == null ? void 0 : _b.events) !== false,
2695
+ debug,
2696
+ context: {
2697
+ userId: wrapTimeCtx.userId,
2698
+ eventId: wrapTimeCtx.eventId,
2699
+ eventName: wrapTimeCtx.eventName,
2700
+ convoId: wrapTimeCtx.convoId,
2701
+ properties: wrapTimeCtx.properties
2702
+ }
2703
+ });
2704
+ const registerFn = aiSDK["registerTelemetryIntegration"];
2705
+ if (isFunction(registerFn)) {
2706
+ registerFn(integration);
2707
+ }
2708
+ if (debug) {
2709
+ console.log("[raindrop-ai/ai-sdk] nativeTelemetry: registered RaindropTelemetryIntegration (no Proxy)");
2710
+ }
2711
+ const selfDiagnostics2 = normalizeSelfDiagnosticsConfig(deps.options.selfDiagnostics);
2712
+ if (selfDiagnostics2) {
2713
+ const textOps = /* @__PURE__ */ new Set(["generateText", "streamText"]);
2714
+ const jsonSchemaFactory = resolveJsonSchemaFactory(aiSDK);
2715
+ const proxyTarget2 = isModuleNamespace(aiSDK) ? Object.setPrototypeOf({}, aiSDK) : aiSDK;
2716
+ return new Proxy(proxyTarget2, {
2717
+ get(target, prop, receiver) {
2718
+ const original = Reflect.get(target, prop, receiver);
2719
+ if (typeof prop !== "string" || !textOps.has(prop) || !isFunction(original)) {
2720
+ return original;
2721
+ }
2722
+ return (...callArgs) => {
2723
+ var _a2;
2724
+ const arg = callArgs[0];
2725
+ if (!isRecord(arg)) return original.call(aiSDK, ...callArgs);
2726
+ const telemetry = extractExperimentalTelemetry(arg);
2727
+ const callMeta = (telemetry == null ? void 0 : telemetry.metadata) ? extractRaindropMetadata(telemetry.metadata) : {};
2728
+ const perCallEventIdExplicit = (_a2 = callMeta.eventId) != null ? _a2 : wrapTimeCtx.eventId;
2729
+ const perCallEventId = perCallEventIdExplicit != null ? perCallEventIdExplicit : randomUUID();
2730
+ const perCallEventIdGenerated = !perCallEventIdExplicit;
2731
+ const perCallCtx = {
2732
+ eventId: perCallEventId,
2733
+ telemetry,
2734
+ sendTraces: false,
2735
+ debug,
2736
+ eventShipper: deps.eventShipper,
2737
+ traceShipper: deps.traceShipper,
2738
+ rootParentForChildren: void 0,
2739
+ jsonSchemaFactory,
2740
+ selfDiagnostics: selfDiagnostics2,
2741
+ aiSDKVersion: "7"
2742
+ };
2743
+ const tools = isRecord(arg["tools"]) ? { ...arg["tools"] } : {};
2744
+ const toolName = selfDiagnostics2.toolName;
2745
+ if (!(toolName in tools)) {
2746
+ const reportTool = createSelfDiagnosticsTool(perCallCtx);
2747
+ if (reportTool) tools[toolName] = reportTool;
2748
+ }
2749
+ const existingTelemetry = isRecord(arg["experimental_telemetry"]) ? arg["experimental_telemetry"] : {};
2750
+ const existingMetadata = isRecord(existingTelemetry["metadata"]) ? existingTelemetry["metadata"] : {};
2751
+ const mergedMetadata = existingMetadata["raindrop.eventId"] ? existingMetadata : {
2752
+ ...existingMetadata,
2753
+ "raindrop.eventId": perCallEventId,
2754
+ ...perCallEventIdGenerated ? { "raindrop.internal.eventIdGenerated": "true" } : {}
2755
+ };
2756
+ callArgs[0] = {
2757
+ ...arg,
2758
+ tools,
2759
+ experimental_telemetry: {
2760
+ ...existingTelemetry,
2761
+ metadata: mergedMetadata
2762
+ }
2763
+ };
2764
+ return original.call(aiSDK, ...callArgs);
2765
+ };
2766
+ }
2767
+ });
2768
+ }
2769
+ return aiSDK;
2770
+ }
2147
2771
  const instrumentedOps = /* @__PURE__ */ new Set([
2148
2772
  "generateText",
2149
2773
  "streamText",
@@ -2151,8 +2775,8 @@ function wrapAISDK(aiSDK, deps) {
2151
2775
  "streamObject"
2152
2776
  ]);
2153
2777
  const agentClasses = /* @__PURE__ */ new Set(["Agent", "Experimental_Agent", "ToolLoopAgent"]);
2154
- const sendEvents = ((_a = deps.options.send) == null ? void 0 : _a.events) !== false;
2155
- const sendTraces = ((_b = deps.options.send) == null ? void 0 : _b.traces) !== false;
2778
+ const sendEvents = ((_c = deps.options.send) == null ? void 0 : _c.events) !== false;
2779
+ const sendTraces = ((_d = deps.options.send) == null ? void 0 : _d.traces) !== false;
2156
2780
  const autoAttachmentEnabled = deps.options.autoAttachment !== false;
2157
2781
  const selfDiagnostics = normalizeSelfDiagnosticsConfig(deps.options.selfDiagnostics);
2158
2782
  const proxyTarget = isModuleNamespace(aiSDK) ? Object.setPrototypeOf({}, aiSDK) : aiSDK;
@@ -3165,7 +3789,7 @@ function extractNestedTokens(usage, key) {
3165
3789
  // package.json
3166
3790
  var package_default = {
3167
3791
  name: "@raindrop-ai/ai-sdk",
3168
- version: "0.0.19"};
3792
+ version: "0.0.20"};
3169
3793
 
3170
3794
  // src/internal/version.ts
3171
3795
  var libraryName = package_default.name;
@@ -3281,6 +3905,16 @@ function createRaindropAISDK(opts) {
3281
3905
  traceShipper
3282
3906
  });
3283
3907
  },
3908
+ createTelemetryIntegration(context) {
3909
+ return new RaindropTelemetryIntegration({
3910
+ traceShipper,
3911
+ eventShipper,
3912
+ sendTraces: tracesEnabled,
3913
+ sendEvents: eventsEnabled,
3914
+ debug: envDebug,
3915
+ context
3916
+ });
3917
+ },
3284
3918
  events: {
3285
3919
  async patch(eventId, patch) {
3286
3920
  await eventShipper.patch(eventId, patch);
@@ -3314,4 +3948,4 @@ function createRaindropAISDK(opts) {
3314
3948
  };
3315
3949
  }
3316
3950
 
3317
- export { _resetWarnedMissingUserId, createRaindropAISDK, currentSpan, eventMetadata, eventMetadataFromChatRequest, getContextManager, withCurrent };
3951
+ export { RaindropTelemetryIntegration, _resetWarnedMissingUserId, createRaindropAISDK, currentSpan, eventMetadata, eventMetadataFromChatRequest, getContextManager, withCurrent };