@stage-labs/metro 0.1.0-beta.251 → 0.1.0-beta.253
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/package.json +2 -2
- package/runtime/marketplace/plugin/.claude-plugin/plugin.json +1 -1
- package/runtime/node_modules/@metro-labs/core/package.json +1 -1
- package/runtime/node_modules/@metro-labs/daemon/package.json +1 -1
- package/runtime/node_modules/@metro-labs/daemon/src/boot/boot.ts +2 -0
- package/runtime/node_modules/@metro-labs/daemon/src/claude/api.ts +9 -1
- package/runtime/node_modules/@metro-labs/daemon/src/claude/login.ts +52 -18
- package/runtime/node_modules/@metro-labs/daemon/src/claude/usage-probe.ts +5 -4
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/claude-logins.ts +168 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/fallback.ts +147 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/forward.ts +48 -1
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/gateway.ts +97 -22
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-api.ts +34 -21
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-config.ts +68 -5
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-signin.ts +2 -0
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-store.ts +8 -1
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/provider-models.ts +1 -2
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage-refresh.ts +37 -14
- package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage.ts +28 -3
- package/runtime/node_modules/@metro-labs/discord-bot/package.json +1 -1
- package/runtime/node_modules/@metro-labs/gmail/package.json +1 -1
- package/runtime/node_modules/@metro-labs/http/package.json +1 -1
- package/runtime/node_modules/@metro-labs/outlook/package.json +1 -1
- package/runtime/node_modules/@metro-labs/telegram/package.json +1 -1
- package/runtime/node_modules/@metro-labs/telegram-bot/package.json +1 -1
- package/runtime/node_modules/@metro-labs/threema/package.json +1 -1
- package/runtime/node_modules/@metro-labs/webhook/package.json +1 -1
- package/runtime/node_modules/@metro-labs/whatsapp/package.json +1 -1
- package/runtime/node_modules/@metro-labs/xmtp/package.json +1 -1
- package/runtime/runtime.json +1 -1
|
@@ -3,7 +3,7 @@ import { stringOf } from '@metro-labs/http/api-http';
|
|
|
3
3
|
|
|
4
4
|
type Key = string;
|
|
5
5
|
|
|
6
|
-
interface UsageWindow {
|
|
6
|
+
export interface UsageWindow {
|
|
7
7
|
label: string;
|
|
8
8
|
used: number | null;
|
|
9
9
|
resetAt: string | null;
|
|
@@ -28,14 +28,32 @@ export interface ProviderUsage {
|
|
|
28
28
|
export type Reported = Omit<ProviderUsage, 'tally'>;
|
|
29
29
|
|
|
30
30
|
const latest = new Map<Key, Reported>();
|
|
31
|
+
const stamps = new Map<Key, Map<string, number>>();
|
|
31
32
|
const tallies = new Map<Key, Tally>();
|
|
32
33
|
const probed = new Map<Key, number>();
|
|
33
34
|
const answers = new Map<Key, Reported>();
|
|
34
35
|
|
|
35
36
|
export const noteUsage = (key: Key, usage: Reported): void => {
|
|
36
37
|
latest.set(key, usage);
|
|
38
|
+
stamps.set(key, new Map(usage.windows.map((w) => [w.label, Date.parse(usage.at)])));
|
|
37
39
|
};
|
|
38
40
|
|
|
41
|
+
export function mergeUsage(key: Key, usage: Reported): void {
|
|
42
|
+
const seen = latest.get(key);
|
|
43
|
+
const marks = stamps.get(key);
|
|
44
|
+
if (seen === undefined || marks === undefined) {
|
|
45
|
+
noteUsage(key, usage);
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
const at = Date.parse(usage.at);
|
|
49
|
+
const newer = new Map(usage.windows.filter((w) => (marks.get(w.label) ?? Number.NEGATIVE_INFINITY) <= at).map((w) => [w.label, w]));
|
|
50
|
+
for (const label of newer.keys()) marks.set(label, at);
|
|
51
|
+
const kept = seen.windows.map((w) => newer.get(w.label) ?? w);
|
|
52
|
+
const added = [...newer.values()].filter((w) => !seen.windows.some((old) => old.label === w.label));
|
|
53
|
+
const later = Date.parse(seen.at) <= at;
|
|
54
|
+
latest.set(key, { windows: [...kept, ...added], note: later ? usage.note : seen.note, at: later ? usage.at : seen.at });
|
|
55
|
+
}
|
|
56
|
+
|
|
39
57
|
export function usageSeen(): Record<Key, ProviderUsage> {
|
|
40
58
|
const out: Record<Key, ProviderUsage> = {};
|
|
41
59
|
for (const key of new Set<Key>([...latest.keys(), ...tallies.keys()])) {
|
|
@@ -50,17 +68,20 @@ export const usageOf = (key: Key): Reported | undefined => latest.get(key);
|
|
|
50
68
|
|
|
51
69
|
export const forgetOne = (key: Key): void => {
|
|
52
70
|
latest.delete(key);
|
|
71
|
+
stamps.delete(key);
|
|
53
72
|
tallies.delete(key);
|
|
54
73
|
probed.delete(key);
|
|
55
74
|
};
|
|
56
75
|
|
|
57
76
|
export const forgetReported = (key: Key): void => {
|
|
58
77
|
latest.delete(key);
|
|
78
|
+
stamps.delete(key);
|
|
59
79
|
probed.delete(key);
|
|
60
80
|
};
|
|
61
81
|
|
|
62
82
|
export const forgetUsage = (): void => {
|
|
63
83
|
latest.clear();
|
|
84
|
+
stamps.clear();
|
|
64
85
|
tallies.clear();
|
|
65
86
|
probed.clear();
|
|
66
87
|
answers.clear();
|
|
@@ -178,13 +199,15 @@ function anthropicUnified(headers: Headers, now: Date): { windows: UsageWindow[]
|
|
|
178
199
|
return { windows, note };
|
|
179
200
|
}
|
|
180
201
|
|
|
202
|
+
export const PER_MINUTE = 'Tokens per minute';
|
|
203
|
+
|
|
181
204
|
function anthropicKeyed(headers: Headers, now: Date): UsageWindow[] {
|
|
182
205
|
const limit = Number(headers.get('anthropic-ratelimit-tokens-limit'));
|
|
183
206
|
const remaining = Number(headers.get('anthropic-ratelimit-tokens-remaining'));
|
|
184
207
|
if (!Number.isFinite(limit) || !Number.isFinite(remaining) || limit <= 0) return [];
|
|
185
208
|
return [
|
|
186
209
|
{
|
|
187
|
-
label:
|
|
210
|
+
label: PER_MINUTE,
|
|
188
211
|
used: clamp(1 - remaining / limit),
|
|
189
212
|
resetAt: whenFrom(headers.get('anthropic-ratelimit-tokens-reset'), now),
|
|
190
213
|
detail: `${remaining.toLocaleString('en-US')} of ${limit.toLocaleString('en-US')} left`,
|
|
@@ -315,7 +338,9 @@ export function claudeLoginUsage(limits: unknown, now = new Date()): Reported |
|
|
|
315
338
|
|
|
316
339
|
export function noteUsageHeaders(kind: 'anthropic' | 'codex', key: Key, headers: Headers, now = new Date()): void {
|
|
317
340
|
const usage = kind === 'anthropic' ? anthropicUsage(headers, now) : codexUsage(headers, now);
|
|
318
|
-
if (usage
|
|
341
|
+
if (usage === null) return;
|
|
342
|
+
if (kind === 'anthropic') mergeUsage(key, usage);
|
|
343
|
+
else noteUsage(key, usage);
|
|
319
344
|
}
|
|
320
345
|
|
|
321
346
|
const dollars = (value: number): string => `$${value.toFixed(2)}`;
|
package/runtime/runtime.json
CHANGED