@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.
Files changed (30) hide show
  1. package/package.json +2 -2
  2. package/runtime/marketplace/plugin/.claude-plugin/plugin.json +1 -1
  3. package/runtime/node_modules/@metro-labs/core/package.json +1 -1
  4. package/runtime/node_modules/@metro-labs/daemon/package.json +1 -1
  5. package/runtime/node_modules/@metro-labs/daemon/src/boot/boot.ts +2 -0
  6. package/runtime/node_modules/@metro-labs/daemon/src/claude/api.ts +9 -1
  7. package/runtime/node_modules/@metro-labs/daemon/src/claude/login.ts +52 -18
  8. package/runtime/node_modules/@metro-labs/daemon/src/claude/usage-probe.ts +5 -4
  9. package/runtime/node_modules/@metro-labs/daemon/src/gateway/claude-logins.ts +168 -0
  10. package/runtime/node_modules/@metro-labs/daemon/src/gateway/fallback.ts +147 -0
  11. package/runtime/node_modules/@metro-labs/daemon/src/gateway/forward.ts +48 -1
  12. package/runtime/node_modules/@metro-labs/daemon/src/gateway/gateway.ts +97 -22
  13. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-api.ts +34 -21
  14. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-config.ts +68 -5
  15. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-signin.ts +2 -0
  16. package/runtime/node_modules/@metro-labs/daemon/src/gateway/model-store.ts +8 -1
  17. package/runtime/node_modules/@metro-labs/daemon/src/gateway/provider-models.ts +1 -2
  18. package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage-refresh.ts +37 -14
  19. package/runtime/node_modules/@metro-labs/daemon/src/gateway/usage.ts +28 -3
  20. package/runtime/node_modules/@metro-labs/discord-bot/package.json +1 -1
  21. package/runtime/node_modules/@metro-labs/gmail/package.json +1 -1
  22. package/runtime/node_modules/@metro-labs/http/package.json +1 -1
  23. package/runtime/node_modules/@metro-labs/outlook/package.json +1 -1
  24. package/runtime/node_modules/@metro-labs/telegram/package.json +1 -1
  25. package/runtime/node_modules/@metro-labs/telegram-bot/package.json +1 -1
  26. package/runtime/node_modules/@metro-labs/threema/package.json +1 -1
  27. package/runtime/node_modules/@metro-labs/webhook/package.json +1 -1
  28. package/runtime/node_modules/@metro-labs/whatsapp/package.json +1 -1
  29. package/runtime/node_modules/@metro-labs/xmtp/package.json +1 -1
  30. 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: 'Tokens per minute',
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 !== null) noteUsage(key, 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)}`;
@@ -17,7 +17,7 @@
17
17
  "discord.js": "^14.26.4"
18
18
  },
19
19
  "devDependencies": {
20
- "@stage-labs/config": "0.1.0-beta.2",
20
+ "@stage-labs/config": "0.1.0-beta.3",
21
21
  "eslint": "^10.3.0",
22
22
  "knip": "^6.15.0",
23
23
  "madge": "^8.0.0",
@@ -16,7 +16,7 @@
16
16
  "@metro-labs/core": "workspace:*"
17
17
  },
18
18
  "devDependencies": {
19
- "@stage-labs/config": "0.1.0-beta.2",
19
+ "@stage-labs/config": "0.1.0-beta.3",
20
20
  "eslint": "^10.3.0",
21
21
  "knip": "^6.15.0",
22
22
  "madge": "^8.0.0",
@@ -21,7 +21,7 @@
21
21
  "@metro-labs/core": "workspace:*"
22
22
  },
23
23
  "devDependencies": {
24
- "@stage-labs/config": "0.1.0-beta.2",
24
+ "@stage-labs/config": "0.1.0-beta.3",
25
25
  "eslint": "^10.3.0",
26
26
  "knip": "^6.15.0",
27
27
  "madge": "^8.0.0",
@@ -16,7 +16,7 @@
16
16
  "@metro-labs/core": "workspace:*"
17
17
  },
18
18
  "devDependencies": {
19
- "@stage-labs/config": "0.1.0-beta.2",
19
+ "@stage-labs/config": "0.1.0-beta.3",
20
20
  "eslint": "^10.3.0",
21
21
  "knip": "^6.15.0",
22
22
  "madge": "^8.0.0",
@@ -17,7 +17,7 @@
17
17
  "@mtcute/bun": "0.30.1"
18
18
  },
19
19
  "devDependencies": {
20
- "@stage-labs/config": "0.1.0-beta.2",
20
+ "@stage-labs/config": "0.1.0-beta.3",
21
21
  "eslint": "^10.3.0",
22
22
  "knip": "^6.15.0",
23
23
  "madge": "^8.0.0",
@@ -16,7 +16,7 @@
16
16
  "@metro-labs/core": "workspace:*"
17
17
  },
18
18
  "devDependencies": {
19
- "@stage-labs/config": "0.1.0-beta.2",
19
+ "@stage-labs/config": "0.1.0-beta.3",
20
20
  "eslint": "^10.3.0",
21
21
  "knip": "^6.15.0",
22
22
  "madge": "^8.0.0",
@@ -17,7 +17,7 @@
17
17
  "tweetnacl": "^1.0.3"
18
18
  },
19
19
  "devDependencies": {
20
- "@stage-labs/config": "0.1.0-beta.2",
20
+ "@stage-labs/config": "0.1.0-beta.3",
21
21
  "eslint": "^10.3.0",
22
22
  "knip": "^6.15.0",
23
23
  "madge": "^8.0.0",
@@ -14,7 +14,7 @@
14
14
  "@metro-labs/core": "workspace:*"
15
15
  },
16
16
  "devDependencies": {
17
- "@stage-labs/config": "0.1.0-beta.2",
17
+ "@stage-labs/config": "0.1.0-beta.3",
18
18
  "eslint": "^10.3.0",
19
19
  "knip": "^6.15.0",
20
20
  "madge": "^8.0.0",
@@ -17,7 +17,7 @@
17
17
  "baileys": "7.0.0-rc14"
18
18
  },
19
19
  "devDependencies": {
20
- "@stage-labs/config": "0.1.0-beta.2",
20
+ "@stage-labs/config": "0.1.0-beta.3",
21
21
  "eslint": "^10.3.0",
22
22
  "knip": "^6.15.0",
23
23
  "madge": "^8.0.0",
@@ -25,7 +25,7 @@
25
25
  "viem": "^2.52.2"
26
26
  },
27
27
  "devDependencies": {
28
- "@stage-labs/config": "0.1.0-beta.2",
28
+ "@stage-labs/config": "0.1.0-beta.3",
29
29
  "eslint": "^10.3.0",
30
30
  "knip": "^6.15.0",
31
31
  "madge": "^8.0.0",
@@ -1,3 +1,3 @@
1
1
  {
2
- "version": "0.1.0-beta.251"
2
+ "version": "0.1.0-beta.253"
3
3
  }