@robhowley/pi-openrouter 0.8.2 → 0.8.3
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.
|
@@ -132,3 +132,30 @@ export function createPiModelConfig(overrides?: Partial<PiModelConfig>): PiModel
|
|
|
132
132
|
...overrides,
|
|
133
133
|
};
|
|
134
134
|
}
|
|
135
|
+
|
|
136
|
+
// =============================================================================
|
|
137
|
+
// LocalUsageEvent Fixtures
|
|
138
|
+
// =============================================================================
|
|
139
|
+
|
|
140
|
+
import type { LocalUsageEvent } from '../types.js';
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Creates LocalUsageEvent objects for testing local usage aggregation.
|
|
144
|
+
* Use daysAgo=0 for today, daysAgo=3 for within 7d window, etc.
|
|
145
|
+
*/
|
|
146
|
+
export function createLocalEvents(
|
|
147
|
+
events: Array<{ daysAgo: number; cost: number; model?: string; provider?: string }>,
|
|
148
|
+
): LocalUsageEvent[] {
|
|
149
|
+
return events.map((e, i) => ({
|
|
150
|
+
id: `local-${i}`,
|
|
151
|
+
sessionId: 'test-session',
|
|
152
|
+
generationId: `gen-${i}`,
|
|
153
|
+
completedAt: `${createTestDate(e.daysAgo)}T12:00:00.000Z`,
|
|
154
|
+
requests: 1,
|
|
155
|
+
model: e.model ?? 'gpt-4',
|
|
156
|
+
provider: e.provider ?? 'openai',
|
|
157
|
+
promptTokens: 100,
|
|
158
|
+
completionTokens: 50,
|
|
159
|
+
cost: e.cost,
|
|
160
|
+
}));
|
|
161
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
2
|
import { aggregateUsage } from '../format.js';
|
|
3
3
|
import { renderSpendSparkline } from '../chart.js';
|
|
4
|
-
import { createTestDate, createActivityItem } from './fixtures.js';
|
|
4
|
+
import { createTestDate, createActivityItem, createLocalEvents } from './fixtures.js';
|
|
5
5
|
import type { ActivityItem } from '@openrouter/sdk/models/index.js';
|
|
6
6
|
|
|
7
7
|
describe('aggregateUsage', () => {
|
|
@@ -224,6 +224,54 @@ describe('aggregateUsage', () => {
|
|
|
224
224
|
expect(result.byProvider[0]?.tokens.output).toBe(80); // 50 + 30
|
|
225
225
|
expect(result.byProvider[0]?.requests).toBe(8); // 5 + 3
|
|
226
226
|
});
|
|
227
|
+
|
|
228
|
+
it.each([
|
|
229
|
+
{
|
|
230
|
+
name: 'local today included in 7d model stats',
|
|
231
|
+
api: { daysAgo: 3, cost: 5, model: 'gpt-4' },
|
|
232
|
+
local: { daysAgo: 0, cost: 2.5, model: 'gpt-4' },
|
|
233
|
+
expectSpend7d: 7.5,
|
|
234
|
+
},
|
|
235
|
+
{
|
|
236
|
+
name: 'local outside 7d window excluded from 7d stats',
|
|
237
|
+
api: { daysAgo: 3, cost: 5, model: 'gpt-4' },
|
|
238
|
+
local: { daysAgo: 10, cost: 100, model: 'gpt-4' },
|
|
239
|
+
expectSpend7d: 5,
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
name: 'different models tracked separately',
|
|
243
|
+
api: { daysAgo: 1, cost: 5, model: 'gpt-4' },
|
|
244
|
+
local: { daysAgo: 0, cost: 3, model: 'claude-3' },
|
|
245
|
+
expectSpend7d: null,
|
|
246
|
+
expectModels: [
|
|
247
|
+
{ name: 'gpt-4', spend7d: 5 },
|
|
248
|
+
{ name: 'claude-3', spend7d: 3 },
|
|
249
|
+
],
|
|
250
|
+
},
|
|
251
|
+
])('$name', ({ api, local, expectSpend7d, expectModels }) => {
|
|
252
|
+
const credits = { totalUsage: 1000, totalCredits: 2000 };
|
|
253
|
+
|
|
254
|
+
const result = aggregateUsage(
|
|
255
|
+
credits,
|
|
256
|
+
[
|
|
257
|
+
createActivityItem({
|
|
258
|
+
date: createTestDate(api.daysAgo),
|
|
259
|
+
usage: api.cost,
|
|
260
|
+
model: api.model,
|
|
261
|
+
}),
|
|
262
|
+
],
|
|
263
|
+
Date.now(),
|
|
264
|
+
createLocalEvents([local]),
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
if (expectModels) {
|
|
268
|
+
for (const { name, spend7d } of expectModels) {
|
|
269
|
+
expect(result.topModels.find((m) => m.name === name)?.spend7d).toBe(spend7d);
|
|
270
|
+
}
|
|
271
|
+
} else {
|
|
272
|
+
expect(result.topModels[0]?.spend7d).toBe(expectSpend7d);
|
|
273
|
+
}
|
|
274
|
+
});
|
|
227
275
|
});
|
|
228
276
|
|
|
229
277
|
describe('renderSpendSparkline', () => {
|
|
@@ -25,13 +25,10 @@ export function aggregateUsage(
|
|
|
25
25
|
return d.date >= utcISODate(startOfWeek);
|
|
26
26
|
});
|
|
27
27
|
|
|
28
|
-
const todayData = analytics.filter((d) => {
|
|
29
|
-
// API dates are YYYY-MM-DD in UTC; compare by UTC date boundary
|
|
30
|
-
return d.date >= utcISODate(startOfDay);
|
|
31
|
-
});
|
|
32
|
-
|
|
33
28
|
const weekFromAnalytics = sumSpend(weekData);
|
|
34
|
-
const todayFromAnalytics =
|
|
29
|
+
const todayFromAnalytics = analytics
|
|
30
|
+
.filter((d) => d.date >= utcISODate(startOfDay))
|
|
31
|
+
.reduce((sum, d) => sum + d.usage, 0);
|
|
35
32
|
const month = credits.totalUsage;
|
|
36
33
|
|
|
37
34
|
// Add local events to compute combined totals
|
|
@@ -65,8 +62,10 @@ export function aggregateUsage(
|
|
|
65
62
|
const allData = [...analytics, ...localItems];
|
|
66
63
|
|
|
67
64
|
// Build model stats for both 7d and 30d windows
|
|
68
|
-
//
|
|
69
|
-
const
|
|
65
|
+
// Combine weekData with local events in the 7d window
|
|
66
|
+
const weekLocalItems = localItems.filter((e) => e.date >= utcISODate(startOfWeek));
|
|
67
|
+
const weekAllData = [...weekData, ...weekLocalItems];
|
|
68
|
+
const modelStatsMap = buildModelStats(weekAllData, allData);
|
|
70
69
|
const topModels = Array.from(modelStatsMap.values())
|
|
71
70
|
.sort((a, b) => b.spend30d - a.spend30d)
|
|
72
71
|
.slice(0, 10);
|
package/package.json
CHANGED