@diogonzafe/tokenwatch 0.8.0 → 0.10.0
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/dist/adapters.cjs +16 -6
- package/dist/adapters.cjs.map +1 -1
- package/dist/adapters.d.cts +2 -1
- package/dist/adapters.d.ts +2 -1
- package/dist/adapters.js +16 -6
- package/dist/adapters.js.map +1 -1
- package/dist/cli.js +158 -13
- package/dist/cli.js.map +1 -1
- package/dist/exporters.d.cts +1 -1
- package/dist/exporters.d.ts +1 -1
- package/dist/{index-CFBI-1ab.d.cts → index-B5OF0YCl.d.cts} +13 -0
- package/dist/{index-CFBI-1ab.d.ts → index-B5OF0YCl.d.ts} +13 -0
- package/dist/index.cjs +101 -29
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +101 -29
- package/dist/index.js.map +1 -1
- package/dist/langchain.d.cts +1 -1
- package/dist/langchain.d.ts +1 -1
- package/package.json +1 -1
package/dist/exporters.d.cts
CHANGED
package/dist/exporters.d.ts
CHANGED
|
@@ -65,6 +65,10 @@ interface TrackerConfig {
|
|
|
65
65
|
anomalyDetection?: AnomalyDetectionConfig;
|
|
66
66
|
/** Custom exporter called after every tracked call (e.g. OTelExporter) */
|
|
67
67
|
exporter?: IExporter;
|
|
68
|
+
/** TokenWatch Cloud API key — mirrors every tracked call to the cloud dashboard (fire-and-forget) */
|
|
69
|
+
cloudApiKey?: string;
|
|
70
|
+
/** Override the cloud ingest endpoint (default: https://api.tokenwatch.dev/v1/ingest) */
|
|
71
|
+
cloudEndpoint?: string;
|
|
68
72
|
}
|
|
69
73
|
interface UsageEntry {
|
|
70
74
|
model: string;
|
|
@@ -86,6 +90,8 @@ interface UsageEntry {
|
|
|
86
90
|
feature?: string;
|
|
87
91
|
/** Application identifier — set once in TrackerConfig.appId and stamped on every entry */
|
|
88
92
|
appId?: string;
|
|
93
|
+
/** Arbitrary key-value tags for custom dimensions (e.g. tenantId, region, plan) */
|
|
94
|
+
metadata?: Record<string, string>;
|
|
89
95
|
timestamp: string;
|
|
90
96
|
}
|
|
91
97
|
interface ModelStats {
|
|
@@ -133,6 +139,11 @@ interface Report {
|
|
|
133
139
|
byUser: Record<string, UserStats>;
|
|
134
140
|
byFeature: Record<string, FeatureStats>;
|
|
135
141
|
byApp: Record<string, AppStats>;
|
|
142
|
+
/** Grouped by each custom metadata key → value → stats */
|
|
143
|
+
byMetadata: Record<string, Record<string, {
|
|
144
|
+
costUSD: number;
|
|
145
|
+
calls: number;
|
|
146
|
+
}>>;
|
|
136
147
|
period: {
|
|
137
148
|
from: string;
|
|
138
149
|
to: string;
|
|
@@ -188,6 +199,8 @@ interface TrackingMeta {
|
|
|
188
199
|
__feature?: string;
|
|
189
200
|
/** Override the tracker-level appId for this specific call */
|
|
190
201
|
__appId?: string;
|
|
202
|
+
/** Arbitrary key-value tags for custom dimensions — appear in report.byMetadata */
|
|
203
|
+
__metadata?: Record<string, string>;
|
|
191
204
|
}
|
|
192
205
|
|
|
193
206
|
export type { AnomalyDetectionConfig as A, BudgetConfig as B, CostForecast as C, FeatureStats as F, IExporter as I, LazyTracker as L, ModelPrice as M, PriceMap as P, Report as R, SessionStats as S, TrackerConfig as T, UsageEntry as U, Tracker as a, TrackingMeta as b, ForecastOptions as c, IStorage as d, ModelStats as e, PricesFile as f, ReportOptions as g, UserStats as h };
|
|
@@ -65,6 +65,10 @@ interface TrackerConfig {
|
|
|
65
65
|
anomalyDetection?: AnomalyDetectionConfig;
|
|
66
66
|
/** Custom exporter called after every tracked call (e.g. OTelExporter) */
|
|
67
67
|
exporter?: IExporter;
|
|
68
|
+
/** TokenWatch Cloud API key — mirrors every tracked call to the cloud dashboard (fire-and-forget) */
|
|
69
|
+
cloudApiKey?: string;
|
|
70
|
+
/** Override the cloud ingest endpoint (default: https://api.tokenwatch.dev/v1/ingest) */
|
|
71
|
+
cloudEndpoint?: string;
|
|
68
72
|
}
|
|
69
73
|
interface UsageEntry {
|
|
70
74
|
model: string;
|
|
@@ -86,6 +90,8 @@ interface UsageEntry {
|
|
|
86
90
|
feature?: string;
|
|
87
91
|
/** Application identifier — set once in TrackerConfig.appId and stamped on every entry */
|
|
88
92
|
appId?: string;
|
|
93
|
+
/** Arbitrary key-value tags for custom dimensions (e.g. tenantId, region, plan) */
|
|
94
|
+
metadata?: Record<string, string>;
|
|
89
95
|
timestamp: string;
|
|
90
96
|
}
|
|
91
97
|
interface ModelStats {
|
|
@@ -133,6 +139,11 @@ interface Report {
|
|
|
133
139
|
byUser: Record<string, UserStats>;
|
|
134
140
|
byFeature: Record<string, FeatureStats>;
|
|
135
141
|
byApp: Record<string, AppStats>;
|
|
142
|
+
/** Grouped by each custom metadata key → value → stats */
|
|
143
|
+
byMetadata: Record<string, Record<string, {
|
|
144
|
+
costUSD: number;
|
|
145
|
+
calls: number;
|
|
146
|
+
}>>;
|
|
136
147
|
period: {
|
|
137
148
|
from: string;
|
|
138
149
|
to: string;
|
|
@@ -188,6 +199,8 @@ interface TrackingMeta {
|
|
|
188
199
|
__feature?: string;
|
|
189
200
|
/** Override the tracker-level appId for this specific call */
|
|
190
201
|
__appId?: string;
|
|
202
|
+
/** Arbitrary key-value tags for custom dimensions — appear in report.byMetadata */
|
|
203
|
+
__metadata?: Record<string, string>;
|
|
191
204
|
}
|
|
192
205
|
|
|
193
206
|
export type { AnomalyDetectionConfig as A, BudgetConfig as B, CostForecast as C, FeatureStats as F, IExporter as I, LazyTracker as L, ModelPrice as M, PriceMap as P, Report as R, SessionStats as S, TrackerConfig as T, UsageEntry as U, Tracker as a, TrackingMeta as b, ForecastOptions as c, IStorage as d, ModelStats as e, PricesFile as f, ReportOptions as g, UserStats as h };
|
package/dist/index.cjs
CHANGED
|
@@ -64,6 +64,41 @@ function calculateCost(inputTokens, outputTokens, price, cachedTokens = 0, cache
|
|
|
64
64
|
return regularInputCost + cachedReadCost + cacheCreationCost + outputCost;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
// src/exporters/cloud.ts
|
|
68
|
+
var DEFAULT_ENDPOINT = "https://api.tokenwatch.dev/v1/ingest";
|
|
69
|
+
var CloudExporter = class {
|
|
70
|
+
constructor(apiKey, endpoint) {
|
|
71
|
+
this.apiKey = apiKey;
|
|
72
|
+
this.endpoint = endpoint ?? DEFAULT_ENDPOINT;
|
|
73
|
+
}
|
|
74
|
+
apiKey;
|
|
75
|
+
endpoint;
|
|
76
|
+
export(entry) {
|
|
77
|
+
fetch(this.endpoint, {
|
|
78
|
+
method: "POST",
|
|
79
|
+
headers: {
|
|
80
|
+
"Content-Type": "application/json",
|
|
81
|
+
Authorization: `Bearer ${this.apiKey}`
|
|
82
|
+
},
|
|
83
|
+
body: JSON.stringify({
|
|
84
|
+
model: entry.model,
|
|
85
|
+
inputTokens: entry.inputTokens,
|
|
86
|
+
outputTokens: entry.outputTokens,
|
|
87
|
+
reasoningTokens: entry.reasoningTokens ?? 0,
|
|
88
|
+
cachedTokens: entry.cachedTokens ?? 0,
|
|
89
|
+
cacheCreationTokens: entry.cacheCreationTokens ?? 0,
|
|
90
|
+
costUSD: entry.costUSD,
|
|
91
|
+
sessionId: entry.sessionId,
|
|
92
|
+
userId: entry.userId,
|
|
93
|
+
feature: entry.feature,
|
|
94
|
+
metadata: entry.metadata,
|
|
95
|
+
timestamp: entry.timestamp
|
|
96
|
+
})
|
|
97
|
+
}).catch(() => {
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
67
102
|
// src/core/suggestions.ts
|
|
68
103
|
var PROVIDER_PREFIXES = ["gpt-", "claude-", "gemini-", "deepseek-"];
|
|
69
104
|
function getProviderPrefix(model) {
|
|
@@ -155,6 +190,7 @@ var SqliteStorage = class {
|
|
|
155
190
|
user_id TEXT,
|
|
156
191
|
feature TEXT,
|
|
157
192
|
app_id TEXT,
|
|
193
|
+
metadata TEXT,
|
|
158
194
|
timestamp TEXT NOT NULL
|
|
159
195
|
)
|
|
160
196
|
`);
|
|
@@ -174,13 +210,16 @@ var SqliteStorage = class {
|
|
|
174
210
|
if (!cols.includes("app_id")) {
|
|
175
211
|
this.db.exec(`ALTER TABLE usage ADD COLUMN app_id TEXT`);
|
|
176
212
|
}
|
|
213
|
+
if (!cols.includes("metadata")) {
|
|
214
|
+
this.db.exec(`ALTER TABLE usage ADD COLUMN metadata TEXT`);
|
|
215
|
+
}
|
|
177
216
|
}
|
|
178
217
|
record(entry) {
|
|
179
218
|
this.db.prepare(
|
|
180
219
|
`INSERT INTO usage
|
|
181
220
|
(model, input_tokens, output_tokens, reasoning_tokens, cached_tokens, cache_creation_tokens,
|
|
182
|
-
cost_usd, session_id, user_id, feature, app_id, timestamp)
|
|
183
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
221
|
+
cost_usd, session_id, user_id, feature, app_id, metadata, timestamp)
|
|
222
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
184
223
|
).run(
|
|
185
224
|
entry.model,
|
|
186
225
|
entry.inputTokens,
|
|
@@ -193,6 +232,7 @@ var SqliteStorage = class {
|
|
|
193
232
|
entry.userId ?? null,
|
|
194
233
|
entry.feature ?? null,
|
|
195
234
|
entry.appId ?? null,
|
|
235
|
+
entry.metadata != null ? JSON.stringify(entry.metadata) : null,
|
|
196
236
|
entry.timestamp
|
|
197
237
|
);
|
|
198
238
|
}
|
|
@@ -210,6 +250,7 @@ var SqliteStorage = class {
|
|
|
210
250
|
...r.user_id != null && { userId: r.user_id },
|
|
211
251
|
...r.feature != null && { feature: r.feature },
|
|
212
252
|
...r.app_id != null && { appId: r.app_id },
|
|
253
|
+
...r.metadata != null && { metadata: JSON.parse(r.metadata) },
|
|
213
254
|
timestamp: r.timestamp
|
|
214
255
|
}));
|
|
215
256
|
}
|
|
@@ -1725,7 +1766,9 @@ var TrackerConfigSchema = import_zod.z.object({
|
|
|
1725
1766
|
mode: import_zod.z.enum(["once", "always"]).optional().default("once")
|
|
1726
1767
|
}).optional(),
|
|
1727
1768
|
exporter: import_zod.z.custom((v) => v !== null && typeof v === "object" && typeof v.export === "function").optional(),
|
|
1728
|
-
appId: import_zod.z.string().optional()
|
|
1769
|
+
appId: import_zod.z.string().optional(),
|
|
1770
|
+
cloudApiKey: import_zod.z.string().optional(),
|
|
1771
|
+
cloudEndpoint: import_zod.z.string().url().optional()
|
|
1729
1772
|
});
|
|
1730
1773
|
function createTracker(config = {}) {
|
|
1731
1774
|
const parsed = TrackerConfigSchema.safeParse(config);
|
|
@@ -1745,9 +1788,12 @@ ${issues}`);
|
|
|
1745
1788
|
suggestions,
|
|
1746
1789
|
anomalyDetection,
|
|
1747
1790
|
exporter,
|
|
1748
|
-
appId
|
|
1791
|
+
appId,
|
|
1792
|
+
cloudApiKey,
|
|
1793
|
+
cloudEndpoint
|
|
1749
1794
|
} = parsed.data;
|
|
1750
1795
|
const storage = typeof storageOption === "object" ? storageOption : createStorage(storageOption);
|
|
1796
|
+
const cloudExporter = cloudApiKey ? new CloudExporter(cloudApiKey, cloudEndpoint) : null;
|
|
1751
1797
|
let remotePrices;
|
|
1752
1798
|
let pricesUpdatedAt = bundledUpdatedAt;
|
|
1753
1799
|
if (syncPrices) {
|
|
@@ -1808,6 +1854,9 @@ ${issues}`);
|
|
|
1808
1854
|
Promise.resolve(exporter.export(full)).catch(() => {
|
|
1809
1855
|
});
|
|
1810
1856
|
}
|
|
1857
|
+
if (cloudExporter) {
|
|
1858
|
+
cloudExporter.export(full);
|
|
1859
|
+
}
|
|
1811
1860
|
maybeFireAlerts(full);
|
|
1812
1861
|
if (anomalyDetection) maybeDetectAnomaly(full);
|
|
1813
1862
|
if (suggestions) {
|
|
@@ -1889,6 +1938,7 @@ ${issues}`);
|
|
|
1889
1938
|
const byUser = {};
|
|
1890
1939
|
const byFeature = {};
|
|
1891
1940
|
const byApp = {};
|
|
1941
|
+
const byMetadata = {};
|
|
1892
1942
|
let totalInput = 0;
|
|
1893
1943
|
let totalOutput = 0;
|
|
1894
1944
|
let totalCost = 0;
|
|
@@ -1930,6 +1980,14 @@ ${issues}`);
|
|
|
1930
1980
|
a.costUSD += e.costUSD;
|
|
1931
1981
|
a.calls += 1;
|
|
1932
1982
|
}
|
|
1983
|
+
if (e.metadata) {
|
|
1984
|
+
for (const [key, val] of Object.entries(e.metadata)) {
|
|
1985
|
+
const group = byMetadata[key] ??= {};
|
|
1986
|
+
const slot = group[val] ??= { costUSD: 0, calls: 0 };
|
|
1987
|
+
slot.costUSD += e.costUSD;
|
|
1988
|
+
slot.calls += 1;
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1933
1991
|
}
|
|
1934
1992
|
if (options && entries.length > 0) {
|
|
1935
1993
|
periodFrom = entries[0]?.timestamp ?? periodFrom;
|
|
@@ -1942,6 +2000,7 @@ ${issues}`);
|
|
|
1942
2000
|
byUser,
|
|
1943
2001
|
byFeature,
|
|
1944
2002
|
byApp,
|
|
2003
|
+
byMetadata,
|
|
1945
2004
|
period: { from: periodFrom, to: lastTimestamp },
|
|
1946
2005
|
...pricesUpdatedAt ? { pricesUpdatedAt } : {}
|
|
1947
2006
|
};
|
|
@@ -2046,7 +2105,7 @@ ${issues}`);
|
|
|
2046
2105
|
}
|
|
2047
2106
|
async function exportCSV() {
|
|
2048
2107
|
const entries = await Promise.resolve(storage.getAll());
|
|
2049
|
-
const header = "timestamp,model,inputTokens,outputTokens,reasoningTokens,cachedTokens,cacheCreationTokens,costUSD,sessionId,userId,feature,appId";
|
|
2108
|
+
const header = "timestamp,model,inputTokens,outputTokens,reasoningTokens,cachedTokens,cacheCreationTokens,costUSD,sessionId,userId,feature,appId,metadata";
|
|
2050
2109
|
const rows = entries.map(
|
|
2051
2110
|
(e) => [
|
|
2052
2111
|
csvEscape(e.timestamp),
|
|
@@ -2060,7 +2119,8 @@ ${issues}`);
|
|
|
2060
2119
|
csvEscape(e.sessionId ?? ""),
|
|
2061
2120
|
csvEscape(e.userId ?? ""),
|
|
2062
2121
|
csvEscape(e.feature ?? ""),
|
|
2063
|
-
csvEscape(e.appId ?? "")
|
|
2122
|
+
csvEscape(e.appId ?? ""),
|
|
2123
|
+
csvEscape(e.metadata ? JSON.stringify(e.metadata) : "")
|
|
2064
2124
|
].join(",")
|
|
2065
2125
|
);
|
|
2066
2126
|
return [header, ...rows].join("\n");
|
|
@@ -2132,6 +2192,7 @@ function emptyReport() {
|
|
|
2132
2192
|
byUser: {},
|
|
2133
2193
|
byFeature: {},
|
|
2134
2194
|
byApp: {},
|
|
2195
|
+
byMetadata: {},
|
|
2135
2196
|
period: { from: now, to: now }
|
|
2136
2197
|
};
|
|
2137
2198
|
}
|
|
@@ -2188,12 +2249,13 @@ function createLazyTracker() {
|
|
|
2188
2249
|
|
|
2189
2250
|
// src/providers/openai.ts
|
|
2190
2251
|
function extractMeta(params) {
|
|
2191
|
-
const { __sessionId, __userId, __feature, ...cleaned } = params;
|
|
2252
|
+
const { __sessionId, __userId, __feature, __metadata, ...cleaned } = params;
|
|
2192
2253
|
return {
|
|
2193
2254
|
cleaned,
|
|
2194
2255
|
sessionId: typeof __sessionId === "string" ? __sessionId : void 0,
|
|
2195
2256
|
userId: typeof __userId === "string" ? __userId : void 0,
|
|
2196
|
-
feature: typeof __feature === "string" ? __feature : void 0
|
|
2257
|
+
feature: typeof __feature === "string" ? __feature : void 0,
|
|
2258
|
+
metadata: __metadata != null && typeof __metadata === "object" ? __metadata : void 0
|
|
2197
2259
|
};
|
|
2198
2260
|
}
|
|
2199
2261
|
function extractUsage(usage) {
|
|
@@ -2208,7 +2270,7 @@ function extractUsage(usage) {
|
|
|
2208
2270
|
cachedTokens
|
|
2209
2271
|
};
|
|
2210
2272
|
}
|
|
2211
|
-
function trackWithMeta(tracker, model, inputTokens, outputTokens, reasoningTokens, sessionId, userId, feature, cachedTokens = 0) {
|
|
2273
|
+
function trackWithMeta(tracker, model, inputTokens, outputTokens, reasoningTokens, sessionId, userId, feature, cachedTokens = 0, metadata) {
|
|
2212
2274
|
tracker.track({
|
|
2213
2275
|
model,
|
|
2214
2276
|
inputTokens,
|
|
@@ -2217,10 +2279,11 @@ function trackWithMeta(tracker, model, inputTokens, outputTokens, reasoningToken
|
|
|
2217
2279
|
...cachedTokens > 0 && { cachedTokens },
|
|
2218
2280
|
...sessionId !== void 0 && { sessionId },
|
|
2219
2281
|
...userId !== void 0 && { userId },
|
|
2220
|
-
...feature !== void 0 && { feature }
|
|
2282
|
+
...feature !== void 0 && { feature },
|
|
2283
|
+
...metadata !== void 0 && { metadata }
|
|
2221
2284
|
});
|
|
2222
2285
|
}
|
|
2223
|
-
async function* wrapStream(stream, model, sessionId, userId, feature, tracker) {
|
|
2286
|
+
async function* wrapStream(stream, model, sessionId, userId, feature, tracker, metadata) {
|
|
2224
2287
|
let lastChunk;
|
|
2225
2288
|
for await (const chunk of stream) {
|
|
2226
2289
|
lastChunk = chunk;
|
|
@@ -2232,7 +2295,7 @@ async function* wrapStream(stream, model, sessionId, userId, feature, tracker) {
|
|
|
2232
2295
|
`[tokenwatch] No usage data in stream for model "${model}". Cost recorded as $0. Pass stream_options: { include_usage: true } to get accurate costs.`
|
|
2233
2296
|
);
|
|
2234
2297
|
}
|
|
2235
|
-
trackWithMeta(tracker, model, inputTokens, outputTokens, reasoningTokens, sessionId, userId, feature, cachedTokens);
|
|
2298
|
+
trackWithMeta(tracker, model, inputTokens, outputTokens, reasoningTokens, sessionId, userId, feature, cachedTokens, metadata);
|
|
2236
2299
|
}
|
|
2237
2300
|
function wrapOpenAI(client, tracker) {
|
|
2238
2301
|
const proxiedCompletions = new Proxy(client.chat.completions, {
|
|
@@ -2240,7 +2303,7 @@ function wrapOpenAI(client, tracker) {
|
|
|
2240
2303
|
if (prop !== "create")
|
|
2241
2304
|
return target[prop];
|
|
2242
2305
|
return async function(params) {
|
|
2243
|
-
const { cleaned, sessionId, userId, feature } = extractMeta(params);
|
|
2306
|
+
const { cleaned, sessionId, userId, feature, metadata } = extractMeta(params);
|
|
2244
2307
|
const model = typeof cleaned["model"] === "string" ? cleaned["model"] : "unknown";
|
|
2245
2308
|
const result = await target.create(cleaned);
|
|
2246
2309
|
if (result && typeof result === "object" && Symbol.asyncIterator in result) {
|
|
@@ -2250,7 +2313,8 @@ function wrapOpenAI(client, tracker) {
|
|
|
2250
2313
|
sessionId,
|
|
2251
2314
|
userId,
|
|
2252
2315
|
feature,
|
|
2253
|
-
tracker
|
|
2316
|
+
tracker,
|
|
2317
|
+
metadata
|
|
2254
2318
|
);
|
|
2255
2319
|
}
|
|
2256
2320
|
const completion = result;
|
|
@@ -2264,7 +2328,8 @@ function wrapOpenAI(client, tracker) {
|
|
|
2264
2328
|
sessionId,
|
|
2265
2329
|
userId,
|
|
2266
2330
|
feature,
|
|
2267
|
-
cachedTokens
|
|
2331
|
+
cachedTokens,
|
|
2332
|
+
metadata
|
|
2268
2333
|
);
|
|
2269
2334
|
return result;
|
|
2270
2335
|
};
|
|
@@ -2281,12 +2346,12 @@ function wrapOpenAI(client, tracker) {
|
|
|
2281
2346
|
if (prop !== "create")
|
|
2282
2347
|
return target[prop];
|
|
2283
2348
|
return async function(params) {
|
|
2284
|
-
const { cleaned, sessionId, userId, feature } = extractMeta(params);
|
|
2349
|
+
const { cleaned, sessionId, userId, feature, metadata } = extractMeta(params);
|
|
2285
2350
|
const model = typeof cleaned["model"] === "string" ? cleaned["model"] : "unknown";
|
|
2286
2351
|
const result = await target.create(cleaned);
|
|
2287
2352
|
const embedding = result;
|
|
2288
2353
|
const inputTokens = embedding.usage?.total_tokens ?? 0;
|
|
2289
|
-
trackWithMeta(tracker, embedding.model ?? model, inputTokens, 0, 0, sessionId, userId, feature);
|
|
2354
|
+
trackWithMeta(tracker, embedding.model ?? model, inputTokens, 0, 0, sessionId, userId, feature, 0, metadata);
|
|
2290
2355
|
return result;
|
|
2291
2356
|
};
|
|
2292
2357
|
}
|
|
@@ -2302,12 +2367,13 @@ function wrapOpenAI(client, tracker) {
|
|
|
2302
2367
|
|
|
2303
2368
|
// src/providers/anthropic.ts
|
|
2304
2369
|
function extractMeta2(params) {
|
|
2305
|
-
const { __sessionId, __userId, __feature, ...cleaned } = params;
|
|
2370
|
+
const { __sessionId, __userId, __feature, __metadata, ...cleaned } = params;
|
|
2306
2371
|
return {
|
|
2307
2372
|
cleaned,
|
|
2308
2373
|
sessionId: typeof __sessionId === "string" ? __sessionId : void 0,
|
|
2309
2374
|
userId: typeof __userId === "string" ? __userId : void 0,
|
|
2310
|
-
feature: typeof __feature === "string" ? __feature : void 0
|
|
2375
|
+
feature: typeof __feature === "string" ? __feature : void 0,
|
|
2376
|
+
metadata: __metadata != null && typeof __metadata === "object" ? __metadata : void 0
|
|
2311
2377
|
};
|
|
2312
2378
|
}
|
|
2313
2379
|
function extractUsage2(usage) {
|
|
@@ -2324,7 +2390,7 @@ function extractThinkingTokenApprox(content) {
|
|
|
2324
2390
|
const chars = content.filter((b) => b.type === "thinking").reduce((sum, b) => sum + (b.thinking?.length ?? 0), 0);
|
|
2325
2391
|
return chars > 0 ? Math.round(chars / 4) : 0;
|
|
2326
2392
|
}
|
|
2327
|
-
function trackWithMeta2(tracker, model, inputTokens, outputTokens, reasoningTokens, sessionId, userId, feature, cachedTokens = 0, cacheCreationTokens = 0) {
|
|
2393
|
+
function trackWithMeta2(tracker, model, inputTokens, outputTokens, reasoningTokens, sessionId, userId, feature, cachedTokens = 0, cacheCreationTokens = 0, metadata) {
|
|
2328
2394
|
tracker.track({
|
|
2329
2395
|
model,
|
|
2330
2396
|
inputTokens,
|
|
@@ -2334,10 +2400,11 @@ function trackWithMeta2(tracker, model, inputTokens, outputTokens, reasoningToke
|
|
|
2334
2400
|
...cacheCreationTokens > 0 && { cacheCreationTokens },
|
|
2335
2401
|
...sessionId !== void 0 && { sessionId },
|
|
2336
2402
|
...userId !== void 0 && { userId },
|
|
2337
|
-
...feature !== void 0 && { feature }
|
|
2403
|
+
...feature !== void 0 && { feature },
|
|
2404
|
+
...metadata !== void 0 && { metadata }
|
|
2338
2405
|
});
|
|
2339
2406
|
}
|
|
2340
|
-
async function* wrapStream2(stream, model, sessionId, userId, feature, tracker) {
|
|
2407
|
+
async function* wrapStream2(stream, model, sessionId, userId, feature, tracker, metadata) {
|
|
2341
2408
|
let inputTokens = 0;
|
|
2342
2409
|
let outputTokens = 0;
|
|
2343
2410
|
let cachedTokens = 0;
|
|
@@ -2365,7 +2432,7 @@ async function* wrapStream2(stream, model, sessionId, userId, feature, tracker)
|
|
|
2365
2432
|
}
|
|
2366
2433
|
}
|
|
2367
2434
|
const reasoningTokens = thinkingCharCount > 0 ? Math.round(thinkingCharCount / 4) : 0;
|
|
2368
|
-
trackWithMeta2(tracker, model, inputTokens, outputTokens, reasoningTokens, sessionId, userId, feature, cachedTokens, cacheCreationTokens);
|
|
2435
|
+
trackWithMeta2(tracker, model, inputTokens, outputTokens, reasoningTokens, sessionId, userId, feature, cachedTokens, cacheCreationTokens, metadata);
|
|
2369
2436
|
}
|
|
2370
2437
|
function wrapAnthropic(client, tracker) {
|
|
2371
2438
|
const proxiedMessages = new Proxy(client.messages, {
|
|
@@ -2373,7 +2440,7 @@ function wrapAnthropic(client, tracker) {
|
|
|
2373
2440
|
if (prop !== "create")
|
|
2374
2441
|
return target[prop];
|
|
2375
2442
|
return async function(params) {
|
|
2376
|
-
const { cleaned, sessionId, userId, feature } = extractMeta2(params);
|
|
2443
|
+
const { cleaned, sessionId, userId, feature, metadata } = extractMeta2(params);
|
|
2377
2444
|
const model = typeof cleaned["model"] === "string" ? cleaned["model"] : "unknown";
|
|
2378
2445
|
const result = await target.create(cleaned);
|
|
2379
2446
|
if (result && typeof result === "object" && Symbol.asyncIterator in result) {
|
|
@@ -2383,7 +2450,8 @@ function wrapAnthropic(client, tracker) {
|
|
|
2383
2450
|
sessionId,
|
|
2384
2451
|
userId,
|
|
2385
2452
|
feature,
|
|
2386
|
-
tracker
|
|
2453
|
+
tracker,
|
|
2454
|
+
metadata
|
|
2387
2455
|
);
|
|
2388
2456
|
}
|
|
2389
2457
|
const message = result;
|
|
@@ -2399,7 +2467,8 @@ function wrapAnthropic(client, tracker) {
|
|
|
2399
2467
|
userId,
|
|
2400
2468
|
feature,
|
|
2401
2469
|
cachedTokens,
|
|
2402
|
-
cacheCreationTokens
|
|
2470
|
+
cacheCreationTokens,
|
|
2471
|
+
metadata
|
|
2403
2472
|
);
|
|
2404
2473
|
return result;
|
|
2405
2474
|
};
|
|
@@ -2420,10 +2489,11 @@ function wrapGemini(client, tracker) {
|
|
|
2420
2489
|
if (prop !== "getGenerativeModel")
|
|
2421
2490
|
return target[prop];
|
|
2422
2491
|
return function(modelParams) {
|
|
2423
|
-
const { __sessionId, __userId, __feature, ...cleanedParams } = modelParams;
|
|
2492
|
+
const { __sessionId, __userId, __feature, __metadata, ...cleanedParams } = modelParams;
|
|
2424
2493
|
const feature = typeof __feature === "string" ? __feature : void 0;
|
|
2425
2494
|
const sessionId = typeof __sessionId === "string" ? __sessionId : void 0;
|
|
2426
2495
|
const userId = typeof __userId === "string" ? __userId : void 0;
|
|
2496
|
+
const metadata = __metadata != null && typeof __metadata === "object" ? __metadata : void 0;
|
|
2427
2497
|
const modelInstance = target.getGenerativeModel(cleanedParams);
|
|
2428
2498
|
const modelId = modelParams.model;
|
|
2429
2499
|
return new Proxy(modelInstance, {
|
|
@@ -2438,7 +2508,8 @@ function wrapGemini(client, tracker) {
|
|
|
2438
2508
|
outputTokens: meta?.candidatesTokenCount ?? 0,
|
|
2439
2509
|
...sessionId !== void 0 && { sessionId },
|
|
2440
2510
|
...userId !== void 0 && { userId },
|
|
2441
|
-
...feature !== void 0 && { feature }
|
|
2511
|
+
...feature !== void 0 && { feature },
|
|
2512
|
+
...metadata !== void 0 && { metadata }
|
|
2442
2513
|
});
|
|
2443
2514
|
return result;
|
|
2444
2515
|
};
|
|
@@ -2454,7 +2525,8 @@ function wrapGemini(client, tracker) {
|
|
|
2454
2525
|
outputTokens: meta?.candidatesTokenCount ?? 0,
|
|
2455
2526
|
...sessionId !== void 0 && { sessionId },
|
|
2456
2527
|
...userId !== void 0 && { userId },
|
|
2457
|
-
...feature !== void 0 && { feature }
|
|
2528
|
+
...feature !== void 0 && { feature },
|
|
2529
|
+
...metadata !== void 0 && { metadata }
|
|
2458
2530
|
});
|
|
2459
2531
|
}).catch(() => {
|
|
2460
2532
|
});
|