@diogonzafe/tokenwatch 0.9.0 → 0.10.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/dist/index.d.cts CHANGED
@@ -1,5 +1,5 @@
1
- import { T as TrackerConfig, a as Tracker, L as LazyTracker, b as TrackingMeta } from './index-fD5QLTWg.cjs';
2
- export { A as AnomalyDetectionConfig, B as BudgetConfig, C as CostForecast, F as FeatureStats, c as ForecastOptions, I as IExporter, d as IStorage, M as ModelPrice, e as ModelStats, P as PriceMap, f as PricesFile, R as Report, g as ReportOptions, S as SessionStats, U as UsageEntry, h as UserStats } from './index-fD5QLTWg.cjs';
1
+ import { T as TrackerConfig, a as Tracker, L as LazyTracker, b as TrackingMeta } from './index-B5OF0YCl.cjs';
2
+ export { A as AnomalyDetectionConfig, B as BudgetConfig, C as CostForecast, F as FeatureStats, c as ForecastOptions, I as IExporter, d as IStorage, M as ModelPrice, e as ModelStats, P as PriceMap, f as PricesFile, R as Report, g as ReportOptions, S as SessionStats, U as UsageEntry, h as UserStats } from './index-B5OF0YCl.cjs';
3
3
 
4
4
  declare function createTracker(config?: TrackerConfig): Tracker;
5
5
 
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { T as TrackerConfig, a as Tracker, L as LazyTracker, b as TrackingMeta } from './index-fD5QLTWg.js';
2
- export { A as AnomalyDetectionConfig, B as BudgetConfig, C as CostForecast, F as FeatureStats, c as ForecastOptions, I as IExporter, d as IStorage, M as ModelPrice, e as ModelStats, P as PriceMap, f as PricesFile, R as Report, g as ReportOptions, S as SessionStats, U as UsageEntry, h as UserStats } from './index-fD5QLTWg.js';
1
+ import { T as TrackerConfig, a as Tracker, L as LazyTracker, b as TrackingMeta } from './index-B5OF0YCl.js';
2
+ export { A as AnomalyDetectionConfig, B as BudgetConfig, C as CostForecast, F as FeatureStats, c as ForecastOptions, I as IExporter, d as IStorage, M as ModelPrice, e as ModelStats, P as PriceMap, f as PricesFile, R as Report, g as ReportOptions, S as SessionStats, U as UsageEntry, h as UserStats } from './index-B5OF0YCl.js';
3
3
 
4
4
  declare function createTracker(config?: TrackerConfig): Tracker;
5
5
 
package/dist/index.js CHANGED
@@ -60,6 +60,7 @@ var CloudExporter = class {
60
60
  sessionId: entry.sessionId,
61
61
  userId: entry.userId,
62
62
  feature: entry.feature,
63
+ metadata: entry.metadata,
63
64
  timestamp: entry.timestamp
64
65
  })
65
66
  }).catch(() => {
@@ -157,6 +158,7 @@ var SqliteStorage = class {
157
158
  user_id TEXT,
158
159
  feature TEXT,
159
160
  app_id TEXT,
161
+ metadata TEXT,
160
162
  timestamp TEXT NOT NULL
161
163
  )
162
164
  `);
@@ -176,13 +178,16 @@ var SqliteStorage = class {
176
178
  if (!cols.includes("app_id")) {
177
179
  this.db.exec(`ALTER TABLE usage ADD COLUMN app_id TEXT`);
178
180
  }
181
+ if (!cols.includes("metadata")) {
182
+ this.db.exec(`ALTER TABLE usage ADD COLUMN metadata TEXT`);
183
+ }
179
184
  }
180
185
  record(entry) {
181
186
  this.db.prepare(
182
187
  `INSERT INTO usage
183
188
  (model, input_tokens, output_tokens, reasoning_tokens, cached_tokens, cache_creation_tokens,
184
- cost_usd, session_id, user_id, feature, app_id, timestamp)
185
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
189
+ cost_usd, session_id, user_id, feature, app_id, metadata, timestamp)
190
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
186
191
  ).run(
187
192
  entry.model,
188
193
  entry.inputTokens,
@@ -195,6 +200,7 @@ var SqliteStorage = class {
195
200
  entry.userId ?? null,
196
201
  entry.feature ?? null,
197
202
  entry.appId ?? null,
203
+ entry.metadata != null ? JSON.stringify(entry.metadata) : null,
198
204
  entry.timestamp
199
205
  );
200
206
  }
@@ -212,6 +218,7 @@ var SqliteStorage = class {
212
218
  ...r.user_id != null && { userId: r.user_id },
213
219
  ...r.feature != null && { feature: r.feature },
214
220
  ...r.app_id != null && { appId: r.app_id },
221
+ ...r.metadata != null && { metadata: JSON.parse(r.metadata) },
215
222
  timestamp: r.timestamp
216
223
  }));
217
224
  }
@@ -1899,6 +1906,7 @@ ${issues}`);
1899
1906
  const byUser = {};
1900
1907
  const byFeature = {};
1901
1908
  const byApp = {};
1909
+ const byMetadata = {};
1902
1910
  let totalInput = 0;
1903
1911
  let totalOutput = 0;
1904
1912
  let totalCost = 0;
@@ -1940,6 +1948,14 @@ ${issues}`);
1940
1948
  a.costUSD += e.costUSD;
1941
1949
  a.calls += 1;
1942
1950
  }
1951
+ if (e.metadata) {
1952
+ for (const [key, val] of Object.entries(e.metadata)) {
1953
+ const group = byMetadata[key] ??= {};
1954
+ const slot = group[val] ??= { costUSD: 0, calls: 0 };
1955
+ slot.costUSD += e.costUSD;
1956
+ slot.calls += 1;
1957
+ }
1958
+ }
1943
1959
  }
1944
1960
  if (options && entries.length > 0) {
1945
1961
  periodFrom = entries[0]?.timestamp ?? periodFrom;
@@ -1952,6 +1968,7 @@ ${issues}`);
1952
1968
  byUser,
1953
1969
  byFeature,
1954
1970
  byApp,
1971
+ byMetadata,
1955
1972
  period: { from: periodFrom, to: lastTimestamp },
1956
1973
  ...pricesUpdatedAt ? { pricesUpdatedAt } : {}
1957
1974
  };
@@ -2056,7 +2073,7 @@ ${issues}`);
2056
2073
  }
2057
2074
  async function exportCSV() {
2058
2075
  const entries = await Promise.resolve(storage.getAll());
2059
- const header = "timestamp,model,inputTokens,outputTokens,reasoningTokens,cachedTokens,cacheCreationTokens,costUSD,sessionId,userId,feature,appId";
2076
+ const header = "timestamp,model,inputTokens,outputTokens,reasoningTokens,cachedTokens,cacheCreationTokens,costUSD,sessionId,userId,feature,appId,metadata";
2060
2077
  const rows = entries.map(
2061
2078
  (e) => [
2062
2079
  csvEscape(e.timestamp),
@@ -2070,7 +2087,8 @@ ${issues}`);
2070
2087
  csvEscape(e.sessionId ?? ""),
2071
2088
  csvEscape(e.userId ?? ""),
2072
2089
  csvEscape(e.feature ?? ""),
2073
- csvEscape(e.appId ?? "")
2090
+ csvEscape(e.appId ?? ""),
2091
+ csvEscape(e.metadata ? JSON.stringify(e.metadata) : "")
2074
2092
  ].join(",")
2075
2093
  );
2076
2094
  return [header, ...rows].join("\n");
@@ -2142,6 +2160,7 @@ function emptyReport() {
2142
2160
  byUser: {},
2143
2161
  byFeature: {},
2144
2162
  byApp: {},
2163
+ byMetadata: {},
2145
2164
  period: { from: now, to: now }
2146
2165
  };
2147
2166
  }
@@ -2198,12 +2217,13 @@ function createLazyTracker() {
2198
2217
 
2199
2218
  // src/providers/openai.ts
2200
2219
  function extractMeta(params) {
2201
- const { __sessionId, __userId, __feature, ...cleaned } = params;
2220
+ const { __sessionId, __userId, __feature, __metadata, ...cleaned } = params;
2202
2221
  return {
2203
2222
  cleaned,
2204
2223
  sessionId: typeof __sessionId === "string" ? __sessionId : void 0,
2205
2224
  userId: typeof __userId === "string" ? __userId : void 0,
2206
- feature: typeof __feature === "string" ? __feature : void 0
2225
+ feature: typeof __feature === "string" ? __feature : void 0,
2226
+ metadata: __metadata != null && typeof __metadata === "object" ? __metadata : void 0
2207
2227
  };
2208
2228
  }
2209
2229
  function extractUsage(usage) {
@@ -2218,7 +2238,7 @@ function extractUsage(usage) {
2218
2238
  cachedTokens
2219
2239
  };
2220
2240
  }
2221
- function trackWithMeta(tracker, model, inputTokens, outputTokens, reasoningTokens, sessionId, userId, feature, cachedTokens = 0) {
2241
+ function trackWithMeta(tracker, model, inputTokens, outputTokens, reasoningTokens, sessionId, userId, feature, cachedTokens = 0, metadata) {
2222
2242
  tracker.track({
2223
2243
  model,
2224
2244
  inputTokens,
@@ -2227,10 +2247,11 @@ function trackWithMeta(tracker, model, inputTokens, outputTokens, reasoningToken
2227
2247
  ...cachedTokens > 0 && { cachedTokens },
2228
2248
  ...sessionId !== void 0 && { sessionId },
2229
2249
  ...userId !== void 0 && { userId },
2230
- ...feature !== void 0 && { feature }
2250
+ ...feature !== void 0 && { feature },
2251
+ ...metadata !== void 0 && { metadata }
2231
2252
  });
2232
2253
  }
2233
- async function* wrapStream(stream, model, sessionId, userId, feature, tracker) {
2254
+ async function* wrapStream(stream, model, sessionId, userId, feature, tracker, metadata) {
2234
2255
  let lastChunk;
2235
2256
  for await (const chunk of stream) {
2236
2257
  lastChunk = chunk;
@@ -2242,7 +2263,7 @@ async function* wrapStream(stream, model, sessionId, userId, feature, tracker) {
2242
2263
  `[tokenwatch] No usage data in stream for model "${model}". Cost recorded as $0. Pass stream_options: { include_usage: true } to get accurate costs.`
2243
2264
  );
2244
2265
  }
2245
- trackWithMeta(tracker, model, inputTokens, outputTokens, reasoningTokens, sessionId, userId, feature, cachedTokens);
2266
+ trackWithMeta(tracker, model, inputTokens, outputTokens, reasoningTokens, sessionId, userId, feature, cachedTokens, metadata);
2246
2267
  }
2247
2268
  function wrapOpenAI(client, tracker) {
2248
2269
  const proxiedCompletions = new Proxy(client.chat.completions, {
@@ -2250,7 +2271,7 @@ function wrapOpenAI(client, tracker) {
2250
2271
  if (prop !== "create")
2251
2272
  return target[prop];
2252
2273
  return async function(params) {
2253
- const { cleaned, sessionId, userId, feature } = extractMeta(params);
2274
+ const { cleaned, sessionId, userId, feature, metadata } = extractMeta(params);
2254
2275
  const model = typeof cleaned["model"] === "string" ? cleaned["model"] : "unknown";
2255
2276
  const result = await target.create(cleaned);
2256
2277
  if (result && typeof result === "object" && Symbol.asyncIterator in result) {
@@ -2260,7 +2281,8 @@ function wrapOpenAI(client, tracker) {
2260
2281
  sessionId,
2261
2282
  userId,
2262
2283
  feature,
2263
- tracker
2284
+ tracker,
2285
+ metadata
2264
2286
  );
2265
2287
  }
2266
2288
  const completion = result;
@@ -2274,7 +2296,8 @@ function wrapOpenAI(client, tracker) {
2274
2296
  sessionId,
2275
2297
  userId,
2276
2298
  feature,
2277
- cachedTokens
2299
+ cachedTokens,
2300
+ metadata
2278
2301
  );
2279
2302
  return result;
2280
2303
  };
@@ -2291,12 +2314,12 @@ function wrapOpenAI(client, tracker) {
2291
2314
  if (prop !== "create")
2292
2315
  return target[prop];
2293
2316
  return async function(params) {
2294
- const { cleaned, sessionId, userId, feature } = extractMeta(params);
2317
+ const { cleaned, sessionId, userId, feature, metadata } = extractMeta(params);
2295
2318
  const model = typeof cleaned["model"] === "string" ? cleaned["model"] : "unknown";
2296
2319
  const result = await target.create(cleaned);
2297
2320
  const embedding = result;
2298
2321
  const inputTokens = embedding.usage?.total_tokens ?? 0;
2299
- trackWithMeta(tracker, embedding.model ?? model, inputTokens, 0, 0, sessionId, userId, feature);
2322
+ trackWithMeta(tracker, embedding.model ?? model, inputTokens, 0, 0, sessionId, userId, feature, 0, metadata);
2300
2323
  return result;
2301
2324
  };
2302
2325
  }
@@ -2312,12 +2335,13 @@ function wrapOpenAI(client, tracker) {
2312
2335
 
2313
2336
  // src/providers/anthropic.ts
2314
2337
  function extractMeta2(params) {
2315
- const { __sessionId, __userId, __feature, ...cleaned } = params;
2338
+ const { __sessionId, __userId, __feature, __metadata, ...cleaned } = params;
2316
2339
  return {
2317
2340
  cleaned,
2318
2341
  sessionId: typeof __sessionId === "string" ? __sessionId : void 0,
2319
2342
  userId: typeof __userId === "string" ? __userId : void 0,
2320
- feature: typeof __feature === "string" ? __feature : void 0
2343
+ feature: typeof __feature === "string" ? __feature : void 0,
2344
+ metadata: __metadata != null && typeof __metadata === "object" ? __metadata : void 0
2321
2345
  };
2322
2346
  }
2323
2347
  function extractUsage2(usage) {
@@ -2334,7 +2358,7 @@ function extractThinkingTokenApprox(content) {
2334
2358
  const chars = content.filter((b) => b.type === "thinking").reduce((sum, b) => sum + (b.thinking?.length ?? 0), 0);
2335
2359
  return chars > 0 ? Math.round(chars / 4) : 0;
2336
2360
  }
2337
- function trackWithMeta2(tracker, model, inputTokens, outputTokens, reasoningTokens, sessionId, userId, feature, cachedTokens = 0, cacheCreationTokens = 0) {
2361
+ function trackWithMeta2(tracker, model, inputTokens, outputTokens, reasoningTokens, sessionId, userId, feature, cachedTokens = 0, cacheCreationTokens = 0, metadata) {
2338
2362
  tracker.track({
2339
2363
  model,
2340
2364
  inputTokens,
@@ -2344,10 +2368,11 @@ function trackWithMeta2(tracker, model, inputTokens, outputTokens, reasoningToke
2344
2368
  ...cacheCreationTokens > 0 && { cacheCreationTokens },
2345
2369
  ...sessionId !== void 0 && { sessionId },
2346
2370
  ...userId !== void 0 && { userId },
2347
- ...feature !== void 0 && { feature }
2371
+ ...feature !== void 0 && { feature },
2372
+ ...metadata !== void 0 && { metadata }
2348
2373
  });
2349
2374
  }
2350
- async function* wrapStream2(stream, model, sessionId, userId, feature, tracker) {
2375
+ async function* wrapStream2(stream, model, sessionId, userId, feature, tracker, metadata) {
2351
2376
  let inputTokens = 0;
2352
2377
  let outputTokens = 0;
2353
2378
  let cachedTokens = 0;
@@ -2375,7 +2400,7 @@ async function* wrapStream2(stream, model, sessionId, userId, feature, tracker)
2375
2400
  }
2376
2401
  }
2377
2402
  const reasoningTokens = thinkingCharCount > 0 ? Math.round(thinkingCharCount / 4) : 0;
2378
- trackWithMeta2(tracker, model, inputTokens, outputTokens, reasoningTokens, sessionId, userId, feature, cachedTokens, cacheCreationTokens);
2403
+ trackWithMeta2(tracker, model, inputTokens, outputTokens, reasoningTokens, sessionId, userId, feature, cachedTokens, cacheCreationTokens, metadata);
2379
2404
  }
2380
2405
  function wrapAnthropic(client, tracker) {
2381
2406
  const proxiedMessages = new Proxy(client.messages, {
@@ -2383,7 +2408,7 @@ function wrapAnthropic(client, tracker) {
2383
2408
  if (prop !== "create")
2384
2409
  return target[prop];
2385
2410
  return async function(params) {
2386
- const { cleaned, sessionId, userId, feature } = extractMeta2(params);
2411
+ const { cleaned, sessionId, userId, feature, metadata } = extractMeta2(params);
2387
2412
  const model = typeof cleaned["model"] === "string" ? cleaned["model"] : "unknown";
2388
2413
  const result = await target.create(cleaned);
2389
2414
  if (result && typeof result === "object" && Symbol.asyncIterator in result) {
@@ -2393,7 +2418,8 @@ function wrapAnthropic(client, tracker) {
2393
2418
  sessionId,
2394
2419
  userId,
2395
2420
  feature,
2396
- tracker
2421
+ tracker,
2422
+ metadata
2397
2423
  );
2398
2424
  }
2399
2425
  const message = result;
@@ -2409,7 +2435,8 @@ function wrapAnthropic(client, tracker) {
2409
2435
  userId,
2410
2436
  feature,
2411
2437
  cachedTokens,
2412
- cacheCreationTokens
2438
+ cacheCreationTokens,
2439
+ metadata
2413
2440
  );
2414
2441
  return result;
2415
2442
  };
@@ -2430,10 +2457,11 @@ function wrapGemini(client, tracker) {
2430
2457
  if (prop !== "getGenerativeModel")
2431
2458
  return target[prop];
2432
2459
  return function(modelParams) {
2433
- const { __sessionId, __userId, __feature, ...cleanedParams } = modelParams;
2460
+ const { __sessionId, __userId, __feature, __metadata, ...cleanedParams } = modelParams;
2434
2461
  const feature = typeof __feature === "string" ? __feature : void 0;
2435
2462
  const sessionId = typeof __sessionId === "string" ? __sessionId : void 0;
2436
2463
  const userId = typeof __userId === "string" ? __userId : void 0;
2464
+ const metadata = __metadata != null && typeof __metadata === "object" ? __metadata : void 0;
2437
2465
  const modelInstance = target.getGenerativeModel(cleanedParams);
2438
2466
  const modelId = modelParams.model;
2439
2467
  return new Proxy(modelInstance, {
@@ -2448,7 +2476,8 @@ function wrapGemini(client, tracker) {
2448
2476
  outputTokens: meta?.candidatesTokenCount ?? 0,
2449
2477
  ...sessionId !== void 0 && { sessionId },
2450
2478
  ...userId !== void 0 && { userId },
2451
- ...feature !== void 0 && { feature }
2479
+ ...feature !== void 0 && { feature },
2480
+ ...metadata !== void 0 && { metadata }
2452
2481
  });
2453
2482
  return result;
2454
2483
  };
@@ -2464,7 +2493,8 @@ function wrapGemini(client, tracker) {
2464
2493
  outputTokens: meta?.candidatesTokenCount ?? 0,
2465
2494
  ...sessionId !== void 0 && { sessionId },
2466
2495
  ...userId !== void 0 && { userId },
2467
- ...feature !== void 0 && { feature }
2496
+ ...feature !== void 0 && { feature },
2497
+ ...metadata !== void 0 && { metadata }
2468
2498
  });
2469
2499
  }).catch(() => {
2470
2500
  });