@diogonzafe/tokenwatch 0.1.17 → 0.2.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.
- package/README.md +58 -6
- package/dist/adapters.cjs +56 -22
- package/dist/adapters.cjs.map +1 -1
- package/dist/adapters.d.cts +7 -3
- package/dist/adapters.d.ts +7 -3
- package/dist/adapters.js +56 -22
- package/dist/adapters.js.map +1 -1
- package/dist/cli.js +42 -13
- package/dist/cli.js.map +1 -1
- package/dist/{index-Cy_sl3FI.d.ts → index-B_EmA3K7.d.cts} +15 -1
- package/dist/{index-Cy_sl3FI.d.cts → index-B_EmA3K7.d.ts} +15 -1
- package/dist/index.cjs +117 -37
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +23 -8
- package/dist/index.d.ts +23 -8
- package/dist/index.js +117 -37
- package/dist/index.js.map +1 -1
- package/package.json +1 -2
- package/dist/cli.cjs +0 -1625
- package/dist/cli.cjs.map +0 -1
- package/dist/cli.d.cts +0 -1
package/dist/index.cjs
CHANGED
|
@@ -105,29 +105,40 @@ var SqliteStorage = class {
|
|
|
105
105
|
migrate() {
|
|
106
106
|
this.db.exec(`
|
|
107
107
|
CREATE TABLE IF NOT EXISTS usage (
|
|
108
|
-
id
|
|
109
|
-
model
|
|
110
|
-
input_tokens
|
|
111
|
-
output_tokens
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
108
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
109
|
+
model TEXT NOT NULL,
|
|
110
|
+
input_tokens INTEGER NOT NULL,
|
|
111
|
+
output_tokens INTEGER NOT NULL,
|
|
112
|
+
reasoning_tokens INTEGER NOT NULL DEFAULT 0,
|
|
113
|
+
cost_usd REAL NOT NULL,
|
|
114
|
+
session_id TEXT,
|
|
115
|
+
user_id TEXT,
|
|
116
|
+
feature TEXT,
|
|
117
|
+
timestamp TEXT NOT NULL
|
|
116
118
|
)
|
|
117
119
|
`);
|
|
120
|
+
const cols = this.db.prepare(`PRAGMA table_info(usage)`).all().map((c) => c.name);
|
|
121
|
+
if (!cols.includes("reasoning_tokens")) {
|
|
122
|
+
this.db.exec(`ALTER TABLE usage ADD COLUMN reasoning_tokens INTEGER NOT NULL DEFAULT 0`);
|
|
123
|
+
}
|
|
124
|
+
if (!cols.includes("feature")) {
|
|
125
|
+
this.db.exec(`ALTER TABLE usage ADD COLUMN feature TEXT`);
|
|
126
|
+
}
|
|
118
127
|
}
|
|
119
128
|
record(entry) {
|
|
120
129
|
this.db.prepare(
|
|
121
130
|
`INSERT INTO usage
|
|
122
|
-
(model, input_tokens, output_tokens, cost_usd, session_id, user_id, timestamp)
|
|
123
|
-
VALUES (?, ?, ?, ?, ?, ?, ?)`
|
|
131
|
+
(model, input_tokens, output_tokens, reasoning_tokens, cost_usd, session_id, user_id, feature, timestamp)
|
|
132
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
124
133
|
).run(
|
|
125
134
|
entry.model,
|
|
126
135
|
entry.inputTokens,
|
|
127
136
|
entry.outputTokens,
|
|
137
|
+
entry.reasoningTokens ?? 0,
|
|
128
138
|
entry.costUSD,
|
|
129
139
|
entry.sessionId ?? null,
|
|
130
140
|
entry.userId ?? null,
|
|
141
|
+
entry.feature ?? null,
|
|
131
142
|
entry.timestamp
|
|
132
143
|
);
|
|
133
144
|
}
|
|
@@ -137,9 +148,11 @@ var SqliteStorage = class {
|
|
|
137
148
|
model: r.model,
|
|
138
149
|
inputTokens: r.input_tokens,
|
|
139
150
|
outputTokens: r.output_tokens,
|
|
151
|
+
...r.reasoning_tokens > 0 && { reasoningTokens: r.reasoning_tokens },
|
|
140
152
|
costUSD: r.cost_usd,
|
|
141
153
|
...r.session_id != null && { sessionId: r.session_id },
|
|
142
154
|
...r.user_id != null && { userId: r.user_id },
|
|
155
|
+
...r.feature != null && { feature: r.feature },
|
|
143
156
|
timestamp: r.timestamp
|
|
144
157
|
}));
|
|
145
158
|
}
|
|
@@ -1446,6 +1459,7 @@ ${issues}`);
|
|
|
1446
1459
|
const byModel = {};
|
|
1447
1460
|
const bySession = {};
|
|
1448
1461
|
const byUser = {};
|
|
1462
|
+
const byFeature = {};
|
|
1449
1463
|
let totalInput = 0;
|
|
1450
1464
|
let totalOutput = 0;
|
|
1451
1465
|
let totalCost = 0;
|
|
@@ -1455,11 +1469,12 @@ ${issues}`);
|
|
|
1455
1469
|
totalOutput += e.outputTokens;
|
|
1456
1470
|
totalCost += e.costUSD;
|
|
1457
1471
|
if (e.timestamp > lastTimestamp) lastTimestamp = e.timestamp;
|
|
1458
|
-
const m = byModel[e.model] ??= { costUSD: 0, calls: 0, tokens: { input: 0, output: 0 } };
|
|
1472
|
+
const m = byModel[e.model] ??= { costUSD: 0, calls: 0, tokens: { input: 0, output: 0, reasoning: 0 } };
|
|
1459
1473
|
m.costUSD += e.costUSD;
|
|
1460
1474
|
m.calls += 1;
|
|
1461
1475
|
m.tokens.input += e.inputTokens;
|
|
1462
1476
|
m.tokens.output += e.outputTokens;
|
|
1477
|
+
m.tokens.reasoning += e.reasoningTokens ?? 0;
|
|
1463
1478
|
if (e.sessionId) {
|
|
1464
1479
|
const s = bySession[e.sessionId] ??= { costUSD: 0, calls: 0 };
|
|
1465
1480
|
s.costUSD += e.costUSD;
|
|
@@ -1470,6 +1485,11 @@ ${issues}`);
|
|
|
1470
1485
|
u.costUSD += e.costUSD;
|
|
1471
1486
|
u.calls += 1;
|
|
1472
1487
|
}
|
|
1488
|
+
if (e.feature) {
|
|
1489
|
+
const f = byFeature[e.feature] ??= { costUSD: 0, calls: 0 };
|
|
1490
|
+
f.costUSD += e.costUSD;
|
|
1491
|
+
f.calls += 1;
|
|
1492
|
+
}
|
|
1473
1493
|
}
|
|
1474
1494
|
return {
|
|
1475
1495
|
totalCostUSD: totalCost,
|
|
@@ -1477,6 +1497,7 @@ ${issues}`);
|
|
|
1477
1497
|
byModel,
|
|
1478
1498
|
bySession,
|
|
1479
1499
|
byUser,
|
|
1500
|
+
byFeature,
|
|
1480
1501
|
period: { from: startedAt, to: lastTimestamp }
|
|
1481
1502
|
};
|
|
1482
1503
|
}
|
|
@@ -1492,16 +1513,18 @@ ${issues}`);
|
|
|
1492
1513
|
}
|
|
1493
1514
|
async function exportCSV() {
|
|
1494
1515
|
const entries = await Promise.resolve(storage.getAll());
|
|
1495
|
-
const header = "timestamp,model,inputTokens,outputTokens,costUSD,sessionId,userId";
|
|
1516
|
+
const header = "timestamp,model,inputTokens,outputTokens,reasoningTokens,costUSD,sessionId,userId,feature";
|
|
1496
1517
|
const rows = entries.map(
|
|
1497
1518
|
(e) => [
|
|
1498
1519
|
csvEscape(e.timestamp),
|
|
1499
1520
|
csvEscape(e.model),
|
|
1500
1521
|
e.inputTokens,
|
|
1501
1522
|
e.outputTokens,
|
|
1523
|
+
e.reasoningTokens ?? 0,
|
|
1502
1524
|
e.costUSD.toFixed(8),
|
|
1503
1525
|
csvEscape(e.sessionId ?? ""),
|
|
1504
|
-
csvEscape(e.userId ?? "")
|
|
1526
|
+
csvEscape(e.userId ?? ""),
|
|
1527
|
+
csvEscape(e.feature ?? "")
|
|
1505
1528
|
].join(",")
|
|
1506
1529
|
);
|
|
1507
1530
|
return [header, ...rows].join("\n");
|
|
@@ -1527,42 +1550,46 @@ function csvEscape(value) {
|
|
|
1527
1550
|
|
|
1528
1551
|
// src/providers/openai.ts
|
|
1529
1552
|
function extractMeta(params) {
|
|
1530
|
-
const { __sessionId, __userId, ...cleaned } = params;
|
|
1553
|
+
const { __sessionId, __userId, __feature, ...cleaned } = params;
|
|
1531
1554
|
return {
|
|
1532
1555
|
cleaned,
|
|
1533
1556
|
sessionId: typeof __sessionId === "string" ? __sessionId : void 0,
|
|
1534
|
-
userId: typeof __userId === "string" ? __userId : void 0
|
|
1557
|
+
userId: typeof __userId === "string" ? __userId : void 0,
|
|
1558
|
+
feature: typeof __feature === "string" ? __feature : void 0
|
|
1535
1559
|
};
|
|
1536
1560
|
}
|
|
1537
1561
|
function extractUsage(usage) {
|
|
1538
|
-
if (!usage) return { inputTokens: 0, outputTokens: 0 };
|
|
1562
|
+
if (!usage) return { inputTokens: 0, outputTokens: 0, reasoningTokens: 0 };
|
|
1539
1563
|
return {
|
|
1540
1564
|
inputTokens: usage.prompt_tokens ?? usage.input_tokens ?? 0,
|
|
1541
|
-
outputTokens: usage.completion_tokens ?? usage.output_tokens ?? 0
|
|
1565
|
+
outputTokens: usage.completion_tokens ?? usage.output_tokens ?? 0,
|
|
1566
|
+
reasoningTokens: usage.completion_tokens_details?.reasoning_tokens ?? 0
|
|
1542
1567
|
};
|
|
1543
1568
|
}
|
|
1544
|
-
function trackWithMeta(tracker, model, inputTokens, outputTokens, sessionId, userId) {
|
|
1569
|
+
function trackWithMeta(tracker, model, inputTokens, outputTokens, reasoningTokens, sessionId, userId, feature) {
|
|
1545
1570
|
tracker.track({
|
|
1546
1571
|
model,
|
|
1547
1572
|
inputTokens,
|
|
1548
|
-
outputTokens,
|
|
1573
|
+
outputTokens: outputTokens + reasoningTokens,
|
|
1574
|
+
...reasoningTokens > 0 && { reasoningTokens },
|
|
1549
1575
|
...sessionId !== void 0 && { sessionId },
|
|
1550
|
-
...userId !== void 0 && { userId }
|
|
1576
|
+
...userId !== void 0 && { userId },
|
|
1577
|
+
...feature !== void 0 && { feature }
|
|
1551
1578
|
});
|
|
1552
1579
|
}
|
|
1553
|
-
async function* wrapStream(stream, model, sessionId, userId, tracker) {
|
|
1580
|
+
async function* wrapStream(stream, model, sessionId, userId, feature, tracker) {
|
|
1554
1581
|
let lastChunk;
|
|
1555
1582
|
for await (const chunk of stream) {
|
|
1556
1583
|
lastChunk = chunk;
|
|
1557
1584
|
yield chunk;
|
|
1558
1585
|
}
|
|
1559
|
-
const { inputTokens, outputTokens } = extractUsage(lastChunk?.usage);
|
|
1586
|
+
const { inputTokens, outputTokens, reasoningTokens } = extractUsage(lastChunk?.usage);
|
|
1560
1587
|
if (!lastChunk?.usage) {
|
|
1561
1588
|
console.warn(
|
|
1562
1589
|
`[tokenwatch] No usage data in stream for model "${model}". Cost recorded as $0. Pass stream_options: { include_usage: true } to get accurate costs.`
|
|
1563
1590
|
);
|
|
1564
1591
|
}
|
|
1565
|
-
trackWithMeta(tracker, model, inputTokens, outputTokens, sessionId, userId);
|
|
1592
|
+
trackWithMeta(tracker, model, inputTokens, outputTokens, reasoningTokens, sessionId, userId, feature);
|
|
1566
1593
|
}
|
|
1567
1594
|
function wrapOpenAI(client, tracker) {
|
|
1568
1595
|
const proxiedCompletions = new Proxy(client.chat.completions, {
|
|
@@ -1570,7 +1597,7 @@ function wrapOpenAI(client, tracker) {
|
|
|
1570
1597
|
if (prop !== "create")
|
|
1571
1598
|
return target[prop];
|
|
1572
1599
|
return async function(params) {
|
|
1573
|
-
const { cleaned, sessionId, userId } = extractMeta(params);
|
|
1600
|
+
const { cleaned, sessionId, userId, feature } = extractMeta(params);
|
|
1574
1601
|
const model = typeof cleaned["model"] === "string" ? cleaned["model"] : "unknown";
|
|
1575
1602
|
const result = await target.create(cleaned);
|
|
1576
1603
|
if (result && typeof result === "object" && Symbol.asyncIterator in result) {
|
|
@@ -1579,18 +1606,21 @@ function wrapOpenAI(client, tracker) {
|
|
|
1579
1606
|
model,
|
|
1580
1607
|
sessionId,
|
|
1581
1608
|
userId,
|
|
1609
|
+
feature,
|
|
1582
1610
|
tracker
|
|
1583
1611
|
);
|
|
1584
1612
|
}
|
|
1585
1613
|
const completion = result;
|
|
1586
|
-
const { inputTokens, outputTokens } = extractUsage(completion.usage);
|
|
1614
|
+
const { inputTokens, outputTokens, reasoningTokens } = extractUsage(completion.usage);
|
|
1587
1615
|
trackWithMeta(
|
|
1588
1616
|
tracker,
|
|
1589
1617
|
completion.model ?? model,
|
|
1590
1618
|
inputTokens,
|
|
1591
1619
|
outputTokens,
|
|
1620
|
+
reasoningTokens,
|
|
1592
1621
|
sessionId,
|
|
1593
|
-
userId
|
|
1622
|
+
userId,
|
|
1623
|
+
feature
|
|
1594
1624
|
);
|
|
1595
1625
|
return result;
|
|
1596
1626
|
};
|
|
@@ -1602,9 +1632,25 @@ function wrapOpenAI(client, tracker) {
|
|
|
1602
1632
|
return target[prop];
|
|
1603
1633
|
}
|
|
1604
1634
|
});
|
|
1635
|
+
const proxiedEmbeddings = client.embeddings ? new Proxy(client.embeddings, {
|
|
1636
|
+
get(target, prop) {
|
|
1637
|
+
if (prop !== "create")
|
|
1638
|
+
return target[prop];
|
|
1639
|
+
return async function(params) {
|
|
1640
|
+
const { cleaned, sessionId, userId, feature } = extractMeta(params);
|
|
1641
|
+
const model = typeof cleaned["model"] === "string" ? cleaned["model"] : "unknown";
|
|
1642
|
+
const result = await target.create(cleaned);
|
|
1643
|
+
const embedding = result;
|
|
1644
|
+
const inputTokens = embedding.usage?.total_tokens ?? 0;
|
|
1645
|
+
trackWithMeta(tracker, embedding.model ?? model, inputTokens, 0, 0, sessionId, userId, feature);
|
|
1646
|
+
return result;
|
|
1647
|
+
};
|
|
1648
|
+
}
|
|
1649
|
+
}) : void 0;
|
|
1605
1650
|
return new Proxy(client, {
|
|
1606
1651
|
get(target, prop) {
|
|
1607
1652
|
if (prop === "chat") return proxiedChat;
|
|
1653
|
+
if (prop === "embeddings") return proxiedEmbeddings;
|
|
1608
1654
|
return target[prop];
|
|
1609
1655
|
}
|
|
1610
1656
|
});
|
|
@@ -1612,11 +1658,12 @@ function wrapOpenAI(client, tracker) {
|
|
|
1612
1658
|
|
|
1613
1659
|
// src/providers/anthropic.ts
|
|
1614
1660
|
function extractMeta2(params) {
|
|
1615
|
-
const { __sessionId, __userId, ...cleaned } = params;
|
|
1661
|
+
const { __sessionId, __userId, __feature, ...cleaned } = params;
|
|
1616
1662
|
return {
|
|
1617
1663
|
cleaned,
|
|
1618
1664
|
sessionId: typeof __sessionId === "string" ? __sessionId : void 0,
|
|
1619
|
-
userId: typeof __userId === "string" ? __userId : void 0
|
|
1665
|
+
userId: typeof __userId === "string" ? __userId : void 0,
|
|
1666
|
+
feature: typeof __feature === "string" ? __feature : void 0
|
|
1620
1667
|
};
|
|
1621
1668
|
}
|
|
1622
1669
|
function extractUsage2(usage) {
|
|
@@ -1626,18 +1673,27 @@ function extractUsage2(usage) {
|
|
|
1626
1673
|
outputTokens: usage.output_tokens ?? 0
|
|
1627
1674
|
};
|
|
1628
1675
|
}
|
|
1629
|
-
function
|
|
1676
|
+
function extractThinkingTokenApprox(content) {
|
|
1677
|
+
if (!content) return 0;
|
|
1678
|
+
const chars = content.filter((b) => b.type === "thinking").reduce((sum, b) => sum + (b.thinking?.length ?? 0), 0);
|
|
1679
|
+
return chars > 0 ? Math.round(chars / 4) : 0;
|
|
1680
|
+
}
|
|
1681
|
+
function trackWithMeta2(tracker, model, inputTokens, outputTokens, reasoningTokens, sessionId, userId, feature) {
|
|
1630
1682
|
tracker.track({
|
|
1631
1683
|
model,
|
|
1632
1684
|
inputTokens,
|
|
1633
1685
|
outputTokens,
|
|
1686
|
+
...reasoningTokens > 0 && { reasoningTokens },
|
|
1634
1687
|
...sessionId !== void 0 && { sessionId },
|
|
1635
|
-
...userId !== void 0 && { userId }
|
|
1688
|
+
...userId !== void 0 && { userId },
|
|
1689
|
+
...feature !== void 0 && { feature }
|
|
1636
1690
|
});
|
|
1637
1691
|
}
|
|
1638
|
-
async function* wrapStream2(stream, model, sessionId, userId, tracker) {
|
|
1692
|
+
async function* wrapStream2(stream, model, sessionId, userId, feature, tracker) {
|
|
1639
1693
|
let inputTokens = 0;
|
|
1640
1694
|
let outputTokens = 0;
|
|
1695
|
+
let currentBlockIsThinking = false;
|
|
1696
|
+
let thinkingCharCount = 0;
|
|
1641
1697
|
for await (const event of stream) {
|
|
1642
1698
|
yield event;
|
|
1643
1699
|
if (event.type === "message_start" && event.message?.usage) {
|
|
@@ -1646,8 +1702,18 @@ async function* wrapStream2(stream, model, sessionId, userId, tracker) {
|
|
|
1646
1702
|
if (event.type === "message_delta" && event.usage) {
|
|
1647
1703
|
outputTokens = event.usage.output_tokens ?? 0;
|
|
1648
1704
|
}
|
|
1705
|
+
if (event.type === "content_block_start") {
|
|
1706
|
+
currentBlockIsThinking = event.content_block?.type === "thinking";
|
|
1707
|
+
}
|
|
1708
|
+
if (event.type === "content_block_stop") {
|
|
1709
|
+
currentBlockIsThinking = false;
|
|
1710
|
+
}
|
|
1711
|
+
if (event.type === "content_block_delta" && currentBlockIsThinking && event.delta?.thinking) {
|
|
1712
|
+
thinkingCharCount += event.delta.thinking.length;
|
|
1713
|
+
}
|
|
1649
1714
|
}
|
|
1650
|
-
|
|
1715
|
+
const reasoningTokens = thinkingCharCount > 0 ? Math.round(thinkingCharCount / 4) : 0;
|
|
1716
|
+
trackWithMeta2(tracker, model, inputTokens, outputTokens, reasoningTokens, sessionId, userId, feature);
|
|
1651
1717
|
}
|
|
1652
1718
|
function wrapAnthropic(client, tracker) {
|
|
1653
1719
|
const proxiedMessages = new Proxy(client.messages, {
|
|
@@ -1655,7 +1721,7 @@ function wrapAnthropic(client, tracker) {
|
|
|
1655
1721
|
if (prop !== "create")
|
|
1656
1722
|
return target[prop];
|
|
1657
1723
|
return async function(params) {
|
|
1658
|
-
const { cleaned, sessionId, userId } = extractMeta2(params);
|
|
1724
|
+
const { cleaned, sessionId, userId, feature } = extractMeta2(params);
|
|
1659
1725
|
const model = typeof cleaned["model"] === "string" ? cleaned["model"] : "unknown";
|
|
1660
1726
|
const result = await target.create(cleaned);
|
|
1661
1727
|
if (result && typeof result === "object" && Symbol.asyncIterator in result) {
|
|
@@ -1664,18 +1730,22 @@ function wrapAnthropic(client, tracker) {
|
|
|
1664
1730
|
model,
|
|
1665
1731
|
sessionId,
|
|
1666
1732
|
userId,
|
|
1733
|
+
feature,
|
|
1667
1734
|
tracker
|
|
1668
1735
|
);
|
|
1669
1736
|
}
|
|
1670
1737
|
const message = result;
|
|
1671
1738
|
const { inputTokens, outputTokens } = extractUsage2(message.usage);
|
|
1739
|
+
const reasoningTokens = extractThinkingTokenApprox(message.content);
|
|
1672
1740
|
trackWithMeta2(
|
|
1673
1741
|
tracker,
|
|
1674
1742
|
message.model ?? model,
|
|
1675
1743
|
inputTokens,
|
|
1676
1744
|
outputTokens,
|
|
1745
|
+
reasoningTokens,
|
|
1677
1746
|
sessionId,
|
|
1678
|
-
userId
|
|
1747
|
+
userId,
|
|
1748
|
+
feature
|
|
1679
1749
|
);
|
|
1680
1750
|
return result;
|
|
1681
1751
|
};
|
|
@@ -1696,7 +1766,11 @@ function wrapGemini(client, tracker) {
|
|
|
1696
1766
|
if (prop !== "getGenerativeModel")
|
|
1697
1767
|
return target[prop];
|
|
1698
1768
|
return function(modelParams) {
|
|
1699
|
-
const
|
|
1769
|
+
const { __sessionId, __userId, __feature, ...cleanedParams } = modelParams;
|
|
1770
|
+
const feature = typeof __feature === "string" ? __feature : void 0;
|
|
1771
|
+
const sessionId = typeof __sessionId === "string" ? __sessionId : void 0;
|
|
1772
|
+
const userId = typeof __userId === "string" ? __userId : void 0;
|
|
1773
|
+
const modelInstance = target.getGenerativeModel(cleanedParams);
|
|
1700
1774
|
const modelId = modelParams.model;
|
|
1701
1775
|
return new Proxy(modelInstance, {
|
|
1702
1776
|
get(mTarget, mProp) {
|
|
@@ -1707,7 +1781,10 @@ function wrapGemini(client, tracker) {
|
|
|
1707
1781
|
tracker.track({
|
|
1708
1782
|
model: modelId,
|
|
1709
1783
|
inputTokens: meta?.promptTokenCount ?? 0,
|
|
1710
|
-
outputTokens: meta?.candidatesTokenCount ?? 0
|
|
1784
|
+
outputTokens: meta?.candidatesTokenCount ?? 0,
|
|
1785
|
+
...sessionId !== void 0 && { sessionId },
|
|
1786
|
+
...userId !== void 0 && { userId },
|
|
1787
|
+
...feature !== void 0 && { feature }
|
|
1711
1788
|
});
|
|
1712
1789
|
return result;
|
|
1713
1790
|
};
|
|
@@ -1720,7 +1797,10 @@ function wrapGemini(client, tracker) {
|
|
|
1720
1797
|
tracker.track({
|
|
1721
1798
|
model: modelId,
|
|
1722
1799
|
inputTokens: meta?.promptTokenCount ?? 0,
|
|
1723
|
-
outputTokens: meta?.candidatesTokenCount ?? 0
|
|
1800
|
+
outputTokens: meta?.candidatesTokenCount ?? 0,
|
|
1801
|
+
...sessionId !== void 0 && { sessionId },
|
|
1802
|
+
...userId !== void 0 && { userId },
|
|
1803
|
+
...feature !== void 0 && { feature }
|
|
1724
1804
|
});
|
|
1725
1805
|
}).catch(() => {
|
|
1726
1806
|
});
|