github-issue-tower-defence-management 1.58.1 → 1.58.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.
- package/CHANGELOG.md +16 -0
- package/README.md +3 -3
- package/bin/adapter/entry-points/cli/index.js +1 -3
- package/bin/adapter/entry-points/cli/index.js.map +1 -1
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js +1 -3
- package/bin/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.js.map +1 -1
- package/bin/adapter/proxy/RateLimitCache.js +94 -3
- package/bin/adapter/proxy/RateLimitCache.js.map +1 -1
- package/bin/adapter/proxy/proxyEntry.js +19 -0
- package/bin/adapter/proxy/proxyEntry.js.map +1 -1
- package/bin/adapter/repositories/ProxyClaudeTokenUsageRepository.js +33 -2
- package/bin/adapter/repositories/ProxyClaudeTokenUsageRepository.js.map +1 -1
- package/bin/domain/usecases/StartPreparationUseCase.js +34 -35
- package/bin/domain/usecases/StartPreparationUseCase.js.map +1 -1
- package/package.json +1 -1
- package/src/adapter/entry-points/cli/index.ts +0 -3
- package/src/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.ts +0 -3
- package/src/adapter/proxy/RateLimitCache.test.ts +190 -0
- package/src/adapter/proxy/RateLimitCache.ts +104 -2
- package/src/adapter/proxy/proxyEntry.ts +24 -1
- package/src/adapter/repositories/GraphqlProjectRepository.test.ts +2 -1
- package/src/adapter/repositories/ProxyClaudeTokenUsageRepository.test.ts +354 -7
- package/src/adapter/repositories/ProxyClaudeTokenUsageRepository.ts +42 -2
- package/src/domain/entities/ClaudeTokenUsage.ts +7 -0
- package/src/domain/usecases/StartPreparationUseCase.test.ts +1212 -887
- package/src/domain/usecases/StartPreparationUseCase.ts +47 -57
- package/types/adapter/entry-points/cli/index.d.ts.map +1 -1
- package/types/adapter/entry-points/handlers/HandleScheduledEventUseCaseHandler.d.ts.map +1 -1
- package/types/adapter/proxy/RateLimitCache.d.ts +11 -0
- package/types/adapter/proxy/RateLimitCache.d.ts.map +1 -1
- package/types/adapter/proxy/proxyEntry.d.ts.map +1 -1
- package/types/adapter/repositories/ProxyClaudeTokenUsageRepository.d.ts.map +1 -1
- package/types/domain/entities/ClaudeTokenUsage.d.ts +6 -0
- package/types/domain/entities/ClaudeTokenUsage.d.ts.map +1 -1
- package/types/domain/usecases/StartPreparationUseCase.d.ts +3 -3
- package/types/domain/usecases/StartPreparationUseCase.d.ts.map +1 -1
|
@@ -65,16 +65,24 @@ describe('ProxyClaudeTokenUsageRepository', () => {
|
|
|
65
65
|
expect(mockLoadTokens.mock.calls).toEqual([['/tokens.json']]);
|
|
66
66
|
});
|
|
67
67
|
|
|
68
|
+
const futureReset = Math.floor(Date.now() / 1000) + 3600;
|
|
69
|
+
const pastReset = Math.floor(Date.now() / 1000) - 3600;
|
|
70
|
+
|
|
68
71
|
it('should map each token to its cached utilization', async () => {
|
|
69
72
|
mockLoadTokens.mockReturnValue(['token-a', 'token-b']);
|
|
70
73
|
mockReadRateLimit.mockImplementation((token: string) => {
|
|
71
74
|
if (token === 'token-a') {
|
|
72
75
|
return {
|
|
73
76
|
fiveHourUtilization: 42,
|
|
74
|
-
fiveHourReset:
|
|
77
|
+
fiveHourReset: futureReset,
|
|
75
78
|
sevenDayUtilization: 0,
|
|
76
|
-
sevenDayReset:
|
|
79
|
+
sevenDayReset: futureReset,
|
|
77
80
|
blocked: false,
|
|
81
|
+
rejected: false,
|
|
82
|
+
unifiedRejected: false,
|
|
83
|
+
fiveHourRejected: false,
|
|
84
|
+
sevenDayRejected: false,
|
|
85
|
+
modelWeeklyLimits: {},
|
|
78
86
|
};
|
|
79
87
|
}
|
|
80
88
|
return null;
|
|
@@ -84,8 +92,20 @@ describe('ProxyClaudeTokenUsageRepository', () => {
|
|
|
84
92
|
const result = await repository.getAvailableTokenUsages();
|
|
85
93
|
|
|
86
94
|
expect(result).toEqual([
|
|
87
|
-
{
|
|
88
|
-
|
|
95
|
+
{
|
|
96
|
+
token: 'token-a',
|
|
97
|
+
fiveHourUtilization: 42,
|
|
98
|
+
blocked: false,
|
|
99
|
+
rejected: false,
|
|
100
|
+
modelWeeklyLimits: {},
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
token: 'token-b',
|
|
104
|
+
fiveHourUtilization: 0,
|
|
105
|
+
blocked: false,
|
|
106
|
+
rejected: false,
|
|
107
|
+
modelWeeklyLimits: {},
|
|
108
|
+
},
|
|
89
109
|
]);
|
|
90
110
|
});
|
|
91
111
|
|
|
@@ -93,17 +113,344 @@ describe('ProxyClaudeTokenUsageRepository', () => {
|
|
|
93
113
|
mockLoadTokens.mockReturnValue(['token-a']);
|
|
94
114
|
mockReadRateLimit.mockReturnValue({
|
|
95
115
|
fiveHourUtilization: 5,
|
|
96
|
-
fiveHourReset:
|
|
116
|
+
fiveHourReset: futureReset,
|
|
97
117
|
sevenDayUtilization: 0,
|
|
98
|
-
sevenDayReset:
|
|
118
|
+
sevenDayReset: futureReset,
|
|
99
119
|
blocked: true,
|
|
120
|
+
rejected: false,
|
|
121
|
+
unifiedRejected: false,
|
|
122
|
+
fiveHourRejected: false,
|
|
123
|
+
sevenDayRejected: false,
|
|
124
|
+
modelWeeklyLimits: {},
|
|
125
|
+
});
|
|
126
|
+
const repository = new ProxyClaudeTokenUsageRepository('/tokens.json');
|
|
127
|
+
|
|
128
|
+
const result = await repository.getAvailableTokenUsages();
|
|
129
|
+
|
|
130
|
+
expect(result).toEqual([
|
|
131
|
+
{
|
|
132
|
+
token: 'token-a',
|
|
133
|
+
fiveHourUtilization: 5,
|
|
134
|
+
blocked: true,
|
|
135
|
+
rejected: false,
|
|
136
|
+
modelWeeklyLimits: {},
|
|
137
|
+
},
|
|
138
|
+
]);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
it('should propagate the rejected status from the cache', async () => {
|
|
142
|
+
mockLoadTokens.mockReturnValue(['token-a']);
|
|
143
|
+
mockReadRateLimit.mockReturnValue({
|
|
144
|
+
fiveHourUtilization: 100,
|
|
145
|
+
fiveHourReset: futureReset,
|
|
146
|
+
sevenDayUtilization: 0,
|
|
147
|
+
sevenDayReset: futureReset,
|
|
148
|
+
blocked: false,
|
|
149
|
+
rejected: true,
|
|
150
|
+
unifiedRejected: false,
|
|
151
|
+
fiveHourRejected: true,
|
|
152
|
+
sevenDayRejected: false,
|
|
153
|
+
modelWeeklyLimits: {},
|
|
154
|
+
});
|
|
155
|
+
const repository = new ProxyClaudeTokenUsageRepository('/tokens.json');
|
|
156
|
+
|
|
157
|
+
const result = await repository.getAvailableTokenUsages();
|
|
158
|
+
|
|
159
|
+
expect(result).toEqual([
|
|
160
|
+
{
|
|
161
|
+
token: 'token-a',
|
|
162
|
+
fiveHourUtilization: 100,
|
|
163
|
+
blocked: false,
|
|
164
|
+
rejected: true,
|
|
165
|
+
modelWeeklyLimits: {},
|
|
166
|
+
},
|
|
167
|
+
]);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it('should normalize fiveHourUtilization to 0 when the 5h reset has passed', async () => {
|
|
171
|
+
mockLoadTokens.mockReturnValue(['token-a']);
|
|
172
|
+
mockReadRateLimit.mockReturnValue({
|
|
173
|
+
fiveHourUtilization: 100,
|
|
174
|
+
fiveHourReset: pastReset,
|
|
175
|
+
sevenDayUtilization: 30,
|
|
176
|
+
sevenDayReset: futureReset,
|
|
177
|
+
blocked: false,
|
|
178
|
+
rejected: false,
|
|
179
|
+
unifiedRejected: false,
|
|
180
|
+
fiveHourRejected: false,
|
|
181
|
+
sevenDayRejected: false,
|
|
182
|
+
modelWeeklyLimits: {},
|
|
183
|
+
});
|
|
184
|
+
const repository = new ProxyClaudeTokenUsageRepository('/tokens.json');
|
|
185
|
+
|
|
186
|
+
const result = await repository.getAvailableTokenUsages();
|
|
187
|
+
|
|
188
|
+
expect(result).toEqual([
|
|
189
|
+
{
|
|
190
|
+
token: 'token-a',
|
|
191
|
+
fiveHourUtilization: 0,
|
|
192
|
+
blocked: false,
|
|
193
|
+
rejected: false,
|
|
194
|
+
modelWeeklyLimits: {},
|
|
195
|
+
},
|
|
196
|
+
]);
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('should keep fiveHourUtilization when the 5h reset is in the future', async () => {
|
|
200
|
+
mockLoadTokens.mockReturnValue(['token-a']);
|
|
201
|
+
mockReadRateLimit.mockReturnValue({
|
|
202
|
+
fiveHourUtilization: 95,
|
|
203
|
+
fiveHourReset: futureReset,
|
|
204
|
+
sevenDayUtilization: 0,
|
|
205
|
+
sevenDayReset: futureReset,
|
|
206
|
+
blocked: false,
|
|
207
|
+
rejected: false,
|
|
208
|
+
unifiedRejected: false,
|
|
209
|
+
fiveHourRejected: false,
|
|
210
|
+
sevenDayRejected: false,
|
|
211
|
+
modelWeeklyLimits: {},
|
|
212
|
+
});
|
|
213
|
+
const repository = new ProxyClaudeTokenUsageRepository('/tokens.json');
|
|
214
|
+
|
|
215
|
+
const result = await repository.getAvailableTokenUsages();
|
|
216
|
+
|
|
217
|
+
expect(result).toEqual([
|
|
218
|
+
{
|
|
219
|
+
token: 'token-a',
|
|
220
|
+
fiveHourUtilization: 95,
|
|
221
|
+
blocked: false,
|
|
222
|
+
rejected: false,
|
|
223
|
+
modelWeeklyLimits: {},
|
|
224
|
+
},
|
|
225
|
+
]);
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('should clear a 5h-origin rejection once the 5h reset has passed', async () => {
|
|
229
|
+
mockLoadTokens.mockReturnValue(['token-a']);
|
|
230
|
+
mockReadRateLimit.mockReturnValue({
|
|
231
|
+
fiveHourUtilization: 100,
|
|
232
|
+
fiveHourReset: pastReset,
|
|
233
|
+
sevenDayUtilization: 0,
|
|
234
|
+
sevenDayReset: futureReset,
|
|
235
|
+
blocked: false,
|
|
236
|
+
rejected: true,
|
|
237
|
+
unifiedRejected: false,
|
|
238
|
+
fiveHourRejected: true,
|
|
239
|
+
sevenDayRejected: false,
|
|
240
|
+
modelWeeklyLimits: {},
|
|
241
|
+
});
|
|
242
|
+
const repository = new ProxyClaudeTokenUsageRepository('/tokens.json');
|
|
243
|
+
|
|
244
|
+
const result = await repository.getAvailableTokenUsages();
|
|
245
|
+
|
|
246
|
+
expect(result).toEqual([
|
|
247
|
+
{
|
|
248
|
+
token: 'token-a',
|
|
249
|
+
fiveHourUtilization: 0,
|
|
250
|
+
blocked: false,
|
|
251
|
+
rejected: false,
|
|
252
|
+
modelWeeklyLimits: {},
|
|
253
|
+
},
|
|
254
|
+
]);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it('should clear a 7d-origin rejection once the 7d reset has passed', async () => {
|
|
258
|
+
mockLoadTokens.mockReturnValue(['token-a']);
|
|
259
|
+
mockReadRateLimit.mockReturnValue({
|
|
260
|
+
fiveHourUtilization: 10,
|
|
261
|
+
fiveHourReset: futureReset,
|
|
262
|
+
sevenDayUtilization: 100,
|
|
263
|
+
sevenDayReset: pastReset,
|
|
264
|
+
blocked: false,
|
|
265
|
+
rejected: true,
|
|
266
|
+
unifiedRejected: false,
|
|
267
|
+
fiveHourRejected: false,
|
|
268
|
+
sevenDayRejected: true,
|
|
269
|
+
modelWeeklyLimits: {},
|
|
270
|
+
});
|
|
271
|
+
const repository = new ProxyClaudeTokenUsageRepository('/tokens.json');
|
|
272
|
+
|
|
273
|
+
const result = await repository.getAvailableTokenUsages();
|
|
274
|
+
|
|
275
|
+
expect(result).toEqual([
|
|
276
|
+
{
|
|
277
|
+
token: 'token-a',
|
|
278
|
+
fiveHourUtilization: 10,
|
|
279
|
+
blocked: false,
|
|
280
|
+
rejected: false,
|
|
281
|
+
modelWeeklyLimits: {},
|
|
282
|
+
},
|
|
283
|
+
]);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
it('should keep a 5h-origin rejection while the 5h reset is in the future', async () => {
|
|
287
|
+
mockLoadTokens.mockReturnValue(['token-a']);
|
|
288
|
+
mockReadRateLimit.mockReturnValue({
|
|
289
|
+
fiveHourUtilization: 100,
|
|
290
|
+
fiveHourReset: futureReset,
|
|
291
|
+
sevenDayUtilization: 0,
|
|
292
|
+
sevenDayReset: futureReset,
|
|
293
|
+
blocked: false,
|
|
294
|
+
rejected: true,
|
|
295
|
+
unifiedRejected: false,
|
|
296
|
+
fiveHourRejected: true,
|
|
297
|
+
sevenDayRejected: false,
|
|
298
|
+
modelWeeklyLimits: {},
|
|
299
|
+
});
|
|
300
|
+
const repository = new ProxyClaudeTokenUsageRepository('/tokens.json');
|
|
301
|
+
|
|
302
|
+
const result = await repository.getAvailableTokenUsages();
|
|
303
|
+
|
|
304
|
+
expect(result).toEqual([
|
|
305
|
+
{
|
|
306
|
+
token: 'token-a',
|
|
307
|
+
fiveHourUtilization: 100,
|
|
308
|
+
blocked: false,
|
|
309
|
+
rejected: true,
|
|
310
|
+
modelWeeklyLimits: {},
|
|
311
|
+
},
|
|
312
|
+
]);
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
it('should keep a still-active 7d rejection after the 5h reset has passed', async () => {
|
|
316
|
+
mockLoadTokens.mockReturnValue(['token-a']);
|
|
317
|
+
mockReadRateLimit.mockReturnValue({
|
|
318
|
+
fiveHourUtilization: 100,
|
|
319
|
+
fiveHourReset: pastReset,
|
|
320
|
+
sevenDayUtilization: 100,
|
|
321
|
+
sevenDayReset: futureReset,
|
|
322
|
+
blocked: false,
|
|
323
|
+
rejected: true,
|
|
324
|
+
unifiedRejected: false,
|
|
325
|
+
fiveHourRejected: false,
|
|
326
|
+
sevenDayRejected: true,
|
|
327
|
+
modelWeeklyLimits: {},
|
|
328
|
+
});
|
|
329
|
+
const repository = new ProxyClaudeTokenUsageRepository('/tokens.json');
|
|
330
|
+
|
|
331
|
+
const result = await repository.getAvailableTokenUsages();
|
|
332
|
+
|
|
333
|
+
expect(result).toEqual([
|
|
334
|
+
{
|
|
335
|
+
token: 'token-a',
|
|
336
|
+
fiveHourUtilization: 0,
|
|
337
|
+
blocked: false,
|
|
338
|
+
rejected: true,
|
|
339
|
+
modelWeeklyLimits: {},
|
|
340
|
+
},
|
|
341
|
+
]);
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
it('should clear a unified rejection once the 5h reset has passed', async () => {
|
|
345
|
+
mockLoadTokens.mockReturnValue(['token-a']);
|
|
346
|
+
mockReadRateLimit.mockReturnValue({
|
|
347
|
+
fiveHourUtilization: 100,
|
|
348
|
+
fiveHourReset: pastReset,
|
|
349
|
+
sevenDayUtilization: 0,
|
|
350
|
+
sevenDayReset: futureReset,
|
|
351
|
+
blocked: false,
|
|
352
|
+
rejected: true,
|
|
353
|
+
unifiedRejected: true,
|
|
354
|
+
fiveHourRejected: false,
|
|
355
|
+
sevenDayRejected: false,
|
|
356
|
+
modelWeeklyLimits: {},
|
|
357
|
+
});
|
|
358
|
+
const repository = new ProxyClaudeTokenUsageRepository('/tokens.json');
|
|
359
|
+
|
|
360
|
+
const result = await repository.getAvailableTokenUsages();
|
|
361
|
+
|
|
362
|
+
expect(result).toEqual([
|
|
363
|
+
{
|
|
364
|
+
token: 'token-a',
|
|
365
|
+
fiveHourUtilization: 0,
|
|
366
|
+
blocked: false,
|
|
367
|
+
rejected: false,
|
|
368
|
+
modelWeeklyLimits: {},
|
|
369
|
+
},
|
|
370
|
+
]);
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
it('should default rejected to false when no snapshot exists', async () => {
|
|
374
|
+
mockLoadTokens.mockReturnValue(['token-a']);
|
|
375
|
+
mockReadRateLimit.mockReturnValue(null);
|
|
376
|
+
const repository = new ProxyClaudeTokenUsageRepository('/tokens.json');
|
|
377
|
+
|
|
378
|
+
const result = await repository.getAvailableTokenUsages();
|
|
379
|
+
|
|
380
|
+
expect(result).toEqual([
|
|
381
|
+
{
|
|
382
|
+
token: 'token-a',
|
|
383
|
+
fiveHourUtilization: 0,
|
|
384
|
+
blocked: false,
|
|
385
|
+
rejected: false,
|
|
386
|
+
modelWeeklyLimits: {},
|
|
387
|
+
},
|
|
388
|
+
]);
|
|
389
|
+
});
|
|
390
|
+
|
|
391
|
+
it('should keep a model weekly rejection while its reset is in the future', async () => {
|
|
392
|
+
mockLoadTokens.mockReturnValue(['token-a']);
|
|
393
|
+
mockReadRateLimit.mockReturnValue({
|
|
394
|
+
fiveHourUtilization: 5,
|
|
395
|
+
fiveHourReset: futureReset,
|
|
396
|
+
sevenDayUtilization: 10,
|
|
397
|
+
sevenDayReset: futureReset,
|
|
398
|
+
blocked: false,
|
|
399
|
+
rejected: false,
|
|
400
|
+
unifiedRejected: false,
|
|
401
|
+
fiveHourRejected: false,
|
|
402
|
+
sevenDayRejected: false,
|
|
403
|
+
modelWeeklyLimits: {
|
|
404
|
+
seven_day_sonnet: { rejected: true, resetsAt: futureReset },
|
|
405
|
+
},
|
|
406
|
+
});
|
|
407
|
+
const repository = new ProxyClaudeTokenUsageRepository('/tokens.json');
|
|
408
|
+
|
|
409
|
+
const result = await repository.getAvailableTokenUsages();
|
|
410
|
+
|
|
411
|
+
expect(result).toEqual([
|
|
412
|
+
{
|
|
413
|
+
token: 'token-a',
|
|
414
|
+
fiveHourUtilization: 5,
|
|
415
|
+
blocked: false,
|
|
416
|
+
rejected: false,
|
|
417
|
+
modelWeeklyLimits: {
|
|
418
|
+
seven_day_sonnet: { rejected: true, resetsAt: futureReset },
|
|
419
|
+
},
|
|
420
|
+
},
|
|
421
|
+
]);
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
it('should clear a model weekly rejection once its reset has passed', async () => {
|
|
425
|
+
mockLoadTokens.mockReturnValue(['token-a']);
|
|
426
|
+
mockReadRateLimit.mockReturnValue({
|
|
427
|
+
fiveHourUtilization: 5,
|
|
428
|
+
fiveHourReset: futureReset,
|
|
429
|
+
sevenDayUtilization: 10,
|
|
430
|
+
sevenDayReset: futureReset,
|
|
431
|
+
blocked: false,
|
|
432
|
+
rejected: false,
|
|
433
|
+
unifiedRejected: false,
|
|
434
|
+
fiveHourRejected: false,
|
|
435
|
+
sevenDayRejected: false,
|
|
436
|
+
modelWeeklyLimits: {
|
|
437
|
+
seven_day_sonnet: { rejected: true, resetsAt: pastReset },
|
|
438
|
+
},
|
|
100
439
|
});
|
|
101
440
|
const repository = new ProxyClaudeTokenUsageRepository('/tokens.json');
|
|
102
441
|
|
|
103
442
|
const result = await repository.getAvailableTokenUsages();
|
|
104
443
|
|
|
105
444
|
expect(result).toEqual([
|
|
106
|
-
{
|
|
445
|
+
{
|
|
446
|
+
token: 'token-a',
|
|
447
|
+
fiveHourUtilization: 5,
|
|
448
|
+
blocked: false,
|
|
449
|
+
rejected: false,
|
|
450
|
+
modelWeeklyLimits: {
|
|
451
|
+
seven_day_sonnet: { rejected: false, resetsAt: pastReset },
|
|
452
|
+
},
|
|
453
|
+
},
|
|
107
454
|
]);
|
|
108
455
|
});
|
|
109
456
|
});
|
|
@@ -22,12 +22,52 @@ export class ProxyClaudeTokenUsageRepository implements ClaudeTokenUsageReposito
|
|
|
22
22
|
if (tokens === null) {
|
|
23
23
|
return [];
|
|
24
24
|
}
|
|
25
|
+
const nowEpochSeconds = Date.now() / 1000;
|
|
25
26
|
return tokens.map((token) => {
|
|
26
27
|
const snapshot = readRateLimit(token);
|
|
28
|
+
if (snapshot === null) {
|
|
29
|
+
return {
|
|
30
|
+
token,
|
|
31
|
+
fiveHourUtilization: 0,
|
|
32
|
+
blocked: false,
|
|
33
|
+
rejected: false,
|
|
34
|
+
modelWeeklyLimits: {},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const fiveHourExpired = nowEpochSeconds > snapshot.fiveHourReset;
|
|
38
|
+
const sevenDayExpired = nowEpochSeconds > snapshot.sevenDayReset;
|
|
39
|
+
const fiveHourUtilization = fiveHourExpired
|
|
40
|
+
? 0
|
|
41
|
+
: snapshot.fiveHourUtilization;
|
|
42
|
+
const fiveHourRejectionActive =
|
|
43
|
+
snapshot.fiveHourRejected && !fiveHourExpired;
|
|
44
|
+
const sevenDayRejectionActive =
|
|
45
|
+
snapshot.sevenDayRejected && !sevenDayExpired;
|
|
46
|
+
const unifiedRejectionActive =
|
|
47
|
+
snapshot.unifiedRejected && !fiveHourExpired;
|
|
48
|
+
const rejected =
|
|
49
|
+
unifiedRejectionActive ||
|
|
50
|
+
fiveHourRejectionActive ||
|
|
51
|
+
sevenDayRejectionActive;
|
|
52
|
+
const modelWeeklyLimits: Record<
|
|
53
|
+
string,
|
|
54
|
+
{ rejected: boolean; resetsAt: number }
|
|
55
|
+
> = {};
|
|
56
|
+
for (const [limitType, limit] of Object.entries(
|
|
57
|
+
snapshot.modelWeeklyLimits,
|
|
58
|
+
)) {
|
|
59
|
+
const expired = nowEpochSeconds > limit.resetsAt;
|
|
60
|
+
modelWeeklyLimits[limitType] = {
|
|
61
|
+
rejected: limit.rejected && !expired,
|
|
62
|
+
resetsAt: limit.resetsAt,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
27
65
|
return {
|
|
28
66
|
token,
|
|
29
|
-
fiveHourUtilization
|
|
30
|
-
blocked: snapshot
|
|
67
|
+
fiveHourUtilization,
|
|
68
|
+
blocked: snapshot.blocked,
|
|
69
|
+
rejected,
|
|
70
|
+
modelWeeklyLimits,
|
|
31
71
|
};
|
|
32
72
|
});
|
|
33
73
|
};
|
|
@@ -1,5 +1,12 @@
|
|
|
1
|
+
export type ClaudeModelWeeklyLimit = {
|
|
2
|
+
rejected: boolean;
|
|
3
|
+
resetsAt: number;
|
|
4
|
+
};
|
|
5
|
+
|
|
1
6
|
export type ClaudeTokenUsage = {
|
|
2
7
|
token: string;
|
|
3
8
|
fiveHourUtilization: number;
|
|
4
9
|
blocked: boolean;
|
|
10
|
+
rejected: boolean;
|
|
11
|
+
modelWeeklyLimits: Record<string, ClaudeModelWeeklyLimit>;
|
|
5
12
|
};
|